1
0
Fork 0

Compare commits

...

10 commits

Author SHA1 Message Date
4fb8930c3e 2024-12-29 2024-12-29 10:39:47 +03:00
fa7f621960 2024-11-30 2024-11-30 20:51:14 +03:00
4339539c68 2024-10-31 2024-10-31 21:39:03 +03:00
6fb4dfdbf4 2024-09-30 2024-10-01 18:02:31 +03:00
ccb23ae867 2024-08-31 2024-09-01 08:46:27 +03:00
9fe170e09b 2024-07-31 2024-07-31 21:14:05 +03:00
d59da594ba 2024-06-30 2024-07-01 01:13:35 +03:00
e91d1096f6 2024-04-30 2024-05-02 20:38:07 +03:00
07b494aa75 2024-03-31 2024-03-31 02:19:25 +03:00
1543a1c0af 2024-02-29 2024-02-29 22:58:26 +03:00
28 changed files with 471 additions and 354 deletions

View file

@ -4,12 +4,14 @@
<a href='.'>.</a>
├─ <a href='archive'>archive</a>
│ ├─ <a href='archive/README.md'>README.md</a>
│ ├─ <a href='archive/parallelizing-bash-scripts.md'>parallelizing-bash-scripts.md</a>
│ └─ <a href='archive/round-robin.md'>round-robin.md</a>
├─ <a href='bash_scripts'>bash_scripts</a>
│ ├─ <a href='bash_scripts/README.en.md'>README.en.md</a>
│ ├─ <a href='bash_scripts/README.md'>README.md</a>
│ ├─ <a href='bash_scripts/archive_backup.sh'>archive_backup.sh</a>
│ ├─ <a href='bash_scripts/archive_packages.sh'>archive_packages.sh</a>
│ ├─ <a href='bash_scripts/archive_cleanup.sh'>archive_cleanup.sh</a>
│ ├─ <a href='bash_scripts/archive_packaging.sh'>archive_packaging.sh</a>
│ ├─ <a href='bash_scripts/info_param.sh'>info_param.sh</a>
│ ├─ <a href='bash_scripts/info_references.sh'>info_references.sh</a>
│ ├─ <a href='bash_scripts/info_tree_license.sh'>info_tree_license.sh</a>
@ -17,14 +19,12 @@
│ ├─ <a href='bash_scripts/repo_gitea.tmpl.sh'>repo_gitea.tmpl.sh</a>
│ ├─ <a href='bash_scripts/repo_gitlab.tmpl.sh'>repo_gitlab.tmpl.sh</a>
│ ├─ <a href='bash_scripts/repo_local.tmpl.sh'>repo_local.tmpl.sh</a>
│ └─ <a href='bash_scripts/repo_orchestrate.sh'>repo_orchestrate.sh</a>
│ ├─ <a href='bash_scripts/repo_orchestrate.sh'>repo_orchestrate.sh</a>
│ └─ <a href='bash_scripts/repo_testing.smpl.sh'>repo_testing.smpl.sh</a>
├─ <a href='pictures'>pictures</a>
│ ├─ <a href='pictures/README.md'>README.md</a>
│ ├─ <a href='pictures/archive.jpg'>archive.jpg</a>
│ ├─ <a href='pictures/bash_scripts.jpg'>bash_scripts.jpg</a>
│ ├─ <a href='pictures/color-tomato-theme.jpg'>color-tomato-theme.jpg</a>
│ ├─ <a href='pictures/older-tomato-theme.jpg'>older-tomato-theme.jpg</a>
│ ├─ <a href='pictures/pictures.jpg'>pictures.jpg</a>
│ ├─ <a href='pictures/pomodoro.jpg'>pomodoro.jpg</a>
│ └─ <a href='pictures/website.jpg'>website.jpg</a>
├─ <a href='.gitattributes'>.gitattributes</a>

View file

@ -1,4 +1,4 @@
© Головин Г.Г., 2021-2023
© Головин Г.Г., 2021-2024
Опубликовано под [Открытой лицензией 1.1](OPEN_LICENSE.txt)
@ -8,7 +8,7 @@
---
© Golovin G.G., translation from Russian, 2021-2023
© Golovin G.G., translation from Russian, 2021-2024
Published under the [Open License 1.1](OPEN_LICENSE.txt)

View file

@ -1,21 +1,25 @@
# [Pomodori](README.md)
Updated and once again rewritten variant of my old blog, new versions of old programs: volumetric
tetris, simple captcha and others — simplified site generating without obfuscation, lightweight
page design without JavaScript and open license RF instead of MIT — there are a lot of changes and
everywhere, but the essence remains the same — nothing has changed. Series of static websites
«Pomodori» — not to be bored and not to forget how to write programs, when there is no work.
Updated and once again rewritten variant of my old blog, new versions of old programs: volumetric tetris,
simple captcha and others — simplified site generating without obfuscation, lightweight page design without
JavaScript and open license RF instead of MIT — there are a lot of changes and everywhere, but the essence
remains the same — nothing has changed. Series of static websites «Pomodori» — not to be bored and not to
forget how to write programs, when there is no work.
- [gitea&period;com](https://gitea&period;com/pomodoro) — latest version.
- [git&period;org&period;ru](https://git&period;org&period;ru/pomodoro) — history of changes.
- [hub&period;mos&period;ru](https://hub&period;mos&period;ru/pomodoro) — history of changes.
### Content
Solutions to programming problems with errors and descriptions of solutions. Correction of errors
— is an additional task for C students and cheaters. All code is checked and works — it looks nice,
but such code cannot be used on the production server. Question for B students: find at least one
error. Question for A students: find *more* errors and write the *own* solution.
Solutions to programming problems with errors and descriptions of solutions. Correction of errors — is an
additional task for C students and cheaters. All code is checked and works — it looks nice, but such code
cannot be used on the production server. Question for B students: find at least one error. Question for A
students: find *more* errors and write the *own* solution.
Constructive criticism and error descriptions can be sent over electronic mail — at least it is
interesting for me and useful for professional growth. Because, firstly, not all mistakes are made
intentionally and, secondly, not all of them — are mistakes.
Constructive criticism and error descriptions can be sent over electronic mail — at least it is interesting
for me and useful for professional growth. Because, firstly, not all mistakes are made intentionally and,
secondly, not all of them — are mistakes.
1. [Three-dimensional graphics in JavaScript](https://pomodoro1.mircloud.ru/en/).
2. [Cartesian product, combinatorics](https://pomodoro2.mircloud.ru/en/).
@ -40,9 +44,9 @@ The creative process began in 2016, but even earlier I wrote some things for mys
creativity occurs, when there is no work. Mature thoughts become separate projects, and immature ones
go as parts of this project. Over time, there are more parts, so automation comes in handy here too.
- [Incomplete publications](archive/README.md) — archive without translation.
- [Process management](bash_scripts/README.en.md) — scripts Bash.
- [Avatars for repositories](pictures/README.md) — pictures.
- [Incomplete publications](archive/README.md) — archive without translation.
### Build
@ -53,7 +57,7 @@ the client. *Obusificator* — is a unique solution, no longer used.
Now the site is generated by Jekyll, the template language is Liquid, syntax highlighting during build
time, and the content of the pages is in Markdown format. Process management is performed by Bash scripts.
The thought does not leave me, that I made a *senseless swap* — in general, nothing has changed.
The thought does not leave me, that I *made a senseless swap* — in general, nothing has changed.
### License
@ -72,4 +76,4 @@ provided free of charge, but without any guarantees, and the author of the progr
---
© Golovin G.G., Code with comments, translation from Russian, 2021-2023
© Golovin G.G., Code with comments, translation from Russian, 2021-2024

View file

@ -5,6 +5,10 @@
открытая лицензия РФ вместо MIT — изменений много и везде, но суть осталась прежней — ничего не изменилось. Серия
статических вёб-сайтов «Помидоры» — чтобы не скучать и чтобы не забыть, как программы писать, когда работы нет.
- [gitea&period;com](https://gitea&period;com/pomodoro) — последняя версия.
- [git&period;org&period;ru](https://git&period;org&period;ru/pomodoro) — история изменений.
- [hub&period;mos&period;ru](https://hub&period;mos&period;ru/pomodoro) — история изменений.
### Содержание
Решения задач по программированию с ошибками и описания решений. Исправление ошибок — дополнительная задача для
@ -39,9 +43,9 @@
наступает, когда работы нет. Созревшие мысли становятся отдельными проектами, а несозревшие идут как части
этого проекта. Со временем частей становится больше, поэтому автоматизация пригождается и здесь тоже.
- [Незавершённые публикации](archive/README.md) — архив.
- [Управление процессами](bash_scripts/README.md) — скрипты Bash.
- [Аватарки для репозиториев](pictures/README.md) — картинки.
- [Незавершённые публикации](archive/README.md) — архив.
### Сборка
@ -69,4 +73,4 @@
---
© Головин Г.Г., Код с комментариями, 2021-2023
© Головин Г.Г., Код с комментариями, 2021-2024

View file

@ -1,4 +1,5 @@
| Незавершённые публикации | Язык | Обновление |
|:-----------------------------------------------------------|------|------------|
| [Циклический алгоритм распределения задач](round-robin.md) | Java | 2023.06.05 |
| Незавершённые публикации | Язык | Обновление |
|------------------------------------------------------------------|------|------------|
| [Распараллеливание скриптов Bash](parallelizing-bash-scripts.md) | Bash | 2024.09.05 |
| [Циклический алгоритм распределения задач](round-robin.md) | Java | 2023.06.05 |

View file

@ -0,0 +1,98 @@
# Распараллеливание скриптов Bash
Рассмотрим последовательность действий, не зависящих друг от друга — это итерации циклов, или вызовы функций с параметрами.
Когда цикл один, или функция одна — это тривиальная задача для распараллеливания. Рассмотрим усложнённую модель с тремя
функциями и тремя параметрами для каждой — будем распараллеливать вызовы этих функций с использованием программы `xargs`.
Для решения вопроса об экранировании спецсимволов — сначала все параметры кодируем в HEX коды и после этого составляем с ними
строки — вызовы функций с параметрами. Далее обходим массив строк и выполняем функции в параллельном режиме. Внутри каждой из
них сначала декодируем параметры обратно и затем работаем с ними. Для наглядности замеряем общее время выполнения функций.
```bash
#!/bin/bash
#---------------------------------------------------------------------------;
# три функции с тремя параметрами
#---------------------------------------------------------------------------;
# первая функция с тремя параметрами
function first_func {
p1="$(decode "$1")"
p2="$(decode "$2")"
p3="$(decode "$3")"
echo "1 ${FUNCNAME[*]} [$p1] [$p2] [$p3]"
sleep 5 # эмуляция работы 5 секунд
}
# вторая функция с тремя параметрами
function second_func {
p1="$(decode "$1")"
p2="$(decode "$2")"
p3="$(decode "$3")"
echo "2 ${FUNCNAME[*]} [$p1] [$p2] [$p3]"
sleep 5 # эмуляция работы 5 секунд
}
# третья функция с тремя параметрами
function third_func {
p1="$(decode "$1")"
p2="$(decode "$2")"
p3="$(decode "$3")"
echo "3 ${FUNCNAME[*]} [$p1] [$p2] [$p3]"
sleep 5 # эмуляция работы 5 секунд
}
#---------------------------------------------------------------------------;
# вспомогательные функции и экспорт для дочерних процессов
#---------------------------------------------------------------------------;
# кодирование символов в HEX коды [U0000-UFFFF]
function encode { echo "$1" | uni2ascii -aE -qps; }
# декодирование символов из HEX кодов [U0000-UFFFF]
function decode { echo "$1" | ascii2uni -aE -q; }
# перечисление используемых функций в дочерних процессах bash
export -f decode first_func second_func third_func
#---------------------------------------------------------------------------;
# подготовка массива строк и вывод строк массива
#---------------------------------------------------------------------------;
# параметры могут содержать любые печатные символы или быть пустыми
param0=" \$param\""
param1=
param2='"$2"!="$1"'
# кодирование параметров
p0="$(encode "$param0")"
p1="$(encode "$param1")"
p2="$(encode "$param2")"
# массив строк — вызовы функций с параметрами
array[0]="first_func '$p0' '$p1' '$p2'"
array[1]="second_func '$p1' '$p2' '$p0'"
array[2]="third_func '$p2' '$p0' '$p1'"
# вывод строк массива для наглядности
printf '%s\n' "${array[@]}"
#---------------------------------------------------------------------------;
# параллельное выполнение функций и замер общего времени выполнения
#---------------------------------------------------------------------------;
# текущее время в миллисекундах
time_ms="$(date '+%s%3N')"
# вывод строк массива и вызов функции для каждой из них в параллельном режиме
printf '%s\0' "${array[@]}" | xargs -L1 -0 -P0 bash -c
# время работы в миллисекундах
echo "Общее время выполнения: $(($(date '+%s%3N') - time_ms)) мс."
```
## Вывод
Строки массива — вызовы функций с параметрами через пробелы в кавычках
```
first_func 'U0020U0024U0070U0061U0072U0061U006DU0022' '' 'U0022U0024U0032U0022U0021U003DU0022U0024U0031U0022'
second_func '' 'U0022U0024U0032U0022U0021U003DU0022U0024U0031U0022' 'U0020U0024U0070U0061U0072U0061U006DU0022'
third_func 'U0022U0024U0032U0022U0021U003DU0022U0024U0031U0022' 'U0020U0024U0070U0061U0072U0061U006DU0022' ''
```
Параллельная работа функций, порядок может изменяться
```
3 third_func ["$2"!="$1"] [ $param"] []
2 second_func [] ["$2"!="$1"] [ $param"]
1 first_func [ $param"] [] ["$2"!="$1"]
```
Время работы функций в миллисекундах
```
Общее время выполнения: 5023 мс.
```
---
© Головин Г.Г., Код с комментариями, 2024

View file

@ -284,4 +284,4 @@ class Test2 {
---
© Головин Г.Г., Код с комментариями, 2021-2023
© Головин Г.Г., Код с комментариями, 2023

View file

@ -2,24 +2,27 @@
Creating an archive, switching the domain, composing scripts and creating repositories for publishing.
| № | Bash scripts | Actions performed |
|---|:-----------------------------------------------|:--------------------------------------------------------------------------------------------|
| 1 | [**archive_backup.sh**](archive_backup.sh) | Creating a common archive for the directories of projects on the current date. |
| | [archive_packages.sh](archive_packages.sh) | Building websites, creating and copying archives for deployment. |
| 2 | [**info_param.sh**](info_param.sh) | Parameter for other scripts. Switching the domain of the remote repository. |
| | [info_references.sh](info_references.sh) | Updating the domain of a remote repository in cross-references in descriptions. |
| | [info_tree_license.sh](info_tree_license.sh) | Building a directory tree for each project and copying license files. |
| 3 | [**repo_compose.sh**](repo_compose.sh) | Composing scripts with parameters and copying them to the directories of projects. |
| | [repo_gitea.tmpl.sh](repo_gitea.tmpl.sh) | Script template without parameters to create a remote repository gitea. |
| | [repo_gitlab.tmpl.sh](repo_gitlab.tmpl.sh) | Script template without parameters to create a remote repository gitlab. |
| | [repo_local.tmpl.sh](repo_local.tmpl.sh) | Script template without parameters to create a local repository. |
| 4 | [**repo_orchestrate.sh**](repo_orchestrate.sh) | Parallel execution of scripts and creation of repositories for the directories of projects. |
| № | Bash scripts | Actions performed |
|---|:-----------------------------------------------|:------------------------------------------------------------------------------------------------|
| 1 | [**archive_backup.sh**](archive_backup.sh) | Creating a common archive for the directories of projects on the current date. |
| | [archive_cleanup.sh](archive_cleanup.sh) | Deleting files and folders from the directories of projects before restoring the archive. |
| | [archive_packaging.sh](archive_packaging.sh) | Building websites, packaging and copying archives for deployment. |
| 2 | [**info_param.sh**](info_param.sh) | Parameter for other scripts. Switching the domain of the remote repository. |
| | [info_references.sh](info_references.sh) | Updating the domain of a remote repository in cross-references in descriptions. |
| | [info_tree_license.sh](info_tree_license.sh) | Building a directory tree for each project and copying license files. |
| 3 | [**repo_compose.sh**](repo_compose.sh) | Creating scripts from templates with parameters and saving them in the directories of projects. |
| | [repo_gitea.tmpl.sh](repo_gitea.tmpl.sh) | Template of a script without parameters to create a remote repository gitea. |
| | [repo_gitlab.tmpl.sh](repo_gitlab.tmpl.sh) | Template of a script without parameters to create a remote repository gitlab. |
| | [repo_local.tmpl.sh](repo_local.tmpl.sh) | Template of a script without parameters to create a local repository git. |
| 4 | [**repo_orchestrate.sh**](repo_orchestrate.sh) | Parallel execution of scripts and creation of repositories for the directories of projects. |
| | [repo_testing.smpl.sh](repo_testing.smpl.sh) | Sample of a script for testing the accessibility of pages in the web-interface on the server. |
## Directories of projects
Local project directories are located on the same level. On the server,
repositories with websites are moved to a separate group, and the rest
of the repositories remain with the user. The directory structure for
[gitea&period;com](https://gitea&period;com/golovin),
[git&period;org&period;ru](https://git&period;org&period;ru/golovin) and
[hub&period;mos&period;ru](https://hub&period;mos&period;ru/golovin).

View file

@ -2,24 +2,27 @@
Создание архива, переключение домена, составление скриптов и создание репозиториев для публикации.
| № | Скрипты Bash | Выполняемые действия |
|---|:-----------------------------------------------|:---------------------------------------------------------------------------------|
| 1 | [**archive_backup.sh**](archive_backup.sh) | Создание общего архива для каталогов проектов на текущую дату. |
| | [archive_packages.sh](archive_packages.sh) | Сборка вёб-сайтов, создание и копирование архивов для развёртывания. |
| 2 | [**info_param.sh**](info_param.sh) | Параметр для других скриптов. Переключение домена удалённого репозитория. |
| | [info_references.sh](info_references.sh) | Обновление домена удалённого репозитория в перекрёстных ссылках в описаниях. |
| | [info_tree_license.sh](info_tree_license.sh) | Построение дерева каталогов для каждого проекта и копирование файлов лицензии. |
| 3 | [**repo_compose.sh**](repo_compose.sh) | Составление скриптов с параметрами и копирование их в каталоги проектов. |
| | [repo_gitea.tmpl.sh](repo_gitea.tmpl.sh) | Шаблон скрипта без параметров для создания удалённого репозитория gitea. |
| | [repo_gitlab.tmpl.sh](repo_gitlab.tmpl.sh) | Шаблон скрипта без параметров для создания удалённого репозитория gitlab. |
| | [repo_local.tmpl.sh](repo_local.tmpl.sh) | Шаблон скрипта без параметров для создания локального репозитория. |
| 4 | [**repo_orchestrate.sh**](repo_orchestrate.sh) | Параллельное выполнение скриптов и создание репозиториев для каталогов проектов. |
| № | Скрипты Bash | Выполняемые действия |
|---|:-----------------------------------------------|:----------------------------------------------------------------------------------|
| 1 | [**archive_backup.sh**](archive_backup.sh) | Создание общего архива для каталогов проектов на текущую дату. |
| | [archive_cleanup.sh](archive_cleanup.sh) | Удаление файлов и папок из каталогов проектов перед восстановлением архива. |
| | [archive_packaging.sh](archive_packaging.sh) | Сборка вёб-сайтов, упаковка и копирование архивов для развёртывания. |
| 2 | [**info_param.sh**](info_param.sh) | Параметр для других скриптов. Переключение домена удалённого репозитория. |
| | [info_references.sh](info_references.sh) | Обновление домена удалённого репозитория в перекрёстных ссылках в описаниях. |
| | [info_tree_license.sh](info_tree_license.sh) | Построение дерева каталогов для каждого проекта и копирование файлов лицензии. |
| 3 | [**repo_compose.sh**](repo_compose.sh) | Создание скриптов из шаблонов с параметрами и сохранение их в каталогах проектов. |
| | [repo_gitea.tmpl.sh](repo_gitea.tmpl.sh) | Шаблон скрипта без параметров для создания удалённого репозитория gitea. |
| | [repo_gitlab.tmpl.sh](repo_gitlab.tmpl.sh) | Шаблон скрипта без параметров для создания удалённого репозитория gitlab. |
| | [repo_local.tmpl.sh](repo_local.tmpl.sh) | Шаблон скрипта без параметров для создания локального репозитория git. |
| 4 | [**repo_orchestrate.sh**](repo_orchestrate.sh) | Параллельное выполнение скриптов и создание репозиториев для каталогов проектов. |
| | [repo_testing.smpl.sh](repo_testing.smpl.sh) | Образец скрипта для тестирования доступности страниц в вёб-интерфейсе на сервере. |
## Каталоги проектов
Локальные каталоги проектов расположены на одном уровне. На сервере
репозитории с вёб-сайтами переходят в отдельную группу, а остальные
репозитории остаются у пользователя. Структура каталогов для
[gitea&period;com](https://gitea&period;com/golovin),
[git&period;org&period;ru](https://git&period;org&period;ru/golovin) и
[hub&period;mos&period;ru](https://hub&period;mos&period;ru/golovin).

View file

@ -1,7 +1,9 @@
#!/bin/bash
echo "Создание общего архива для каталогов проектов на текущую дату."
cd ../..
cd ../.. # выход из папки и из репозитория
filename="pomodoro-$(date '+%Y-%m-%d').zip"
rm -rf "$filename"
7z a -tzip -ssw -mx9 -r0 "$filename" ./* -xr!".idea" -xr!".git" -x!"*.iml" \
-x!"*.gem" -x!"*.lock" -x!"*.zip" -x!"_site*" -x!".token_*" -x!".repo_*"
# сводная строка исключений для всех проектов из файлов ".gitignore"
exclusions="$(find . -maxdepth 2 -type f -name '.gitignore' -exec \
sed -E "s|^(.*)$|-xr!'\1'|" {} \; | sort | uniq | tr '\n' ' ')"
rm -f "$filename"
eval "7z a -tzip '$filename' . -xr!'.git' $exclusions" | grep -E '\S'

12
bash_scripts/archive_cleanup.sh Executable file
View file

@ -0,0 +1,12 @@
#!/bin/bash
echo "Удаление файлов и папок из каталогов проектов перед восстановлением архива."
echo "Предохранитель: ОТМЕНА" && exit 0
cd ../.. # выход из папки и из репозитория
time_ms="$(date '+%s%3N')"
# обход всех репозиториев, расположенных на одном уровне с текущим, кроме папки ".idea"
find . -mindepth 1 -maxdepth 1 -type d -not -name ".idea" | while read -r dir; do
echo "Обработка: $dir"
# внутри репозитория — удаление всех вложенных файлов и папок, кроме папки ".git"
find "$dir" -mindepth 1 -maxdepth 1 -type f,d -not -name ".git" -exec rm -r {} \;
done
echo "Общее время выполнения: $(($(date '+%s%3N') - time_ms)) мс."

View file

@ -1,12 +0,0 @@
#!/bin/bash
echo "Сборка вёб-сайтов, создание и копирование архивов для развёртывания."
cd ..
currentTimeMillis=$(date '+%s%3N')
for ((i = 1; i <= 6; i++)); do
echo "Обработка: pomodoro$i"
cd "../pomodoro$i" || continue
./build.sh
./package.sh
cp -v "pomodoro$i.zip" ..
done
echo "Общее время выполнения: $(("$(date '+%s%3N')" - "$currentTimeMillis")) мс."

View file

@ -0,0 +1,16 @@
#!/bin/bash
echo "Сборка вёб-сайтов, упаковка и копирование архивов для развёртывания."
# обработка репозитория вёб-сайта
function packaging {
echo "Обработка: pomodoro$1"
cd "./pomodoro$1" || return
./build.sh >/dev/null
./package.sh >/dev/null
cp -v "pomodoro$1.zip" ..
}
export -f packaging
cd ../.. # выход из папки и из репозитория
time_ms="$(date '+%s%3N')"
# запуск параллельной обработки репозиториев всех вёб-сайтов
printf 'packaging "%s"\0' {1..6} | xargs -n1 -0 -P0 bash -c
echo "Общее время выполнения: $(($(date '+%s%3N') - time_ms)) мс."

View file

@ -1,5 +1,5 @@
#!/bin/bash
#remote="gitea.com"
remote="git.org.ru"
#remote="hub.mos.ru"
echo "Переключение домена удалённого репозитория: $remote"
#!/bin/false
#domain="gitea.com"
domain="git.org.ru"
#domain="hub.mos.ru"
echo "Домен удалённого репозитория: $domain"

View file

@ -1,27 +1,23 @@
#!/bin/bash
echo "Обновление домена удалённого репозитория в перекрёстных ссылках в описаниях."
remote="git.org.ru" && source info_param.sh
# экранируем точки в названии домена
domain="${remote//"."/"\."}"
domain="git.org.ru" && source info_param.sh
# название домена в верхнем регистре
DOMAIN="${domain^^}"
cd ../.. # выходим из папки и из репозитория
# обходим все репозитории, расположенные на одном уровне с текущим
find . -type f -name 'README*.md' | sort -r | while read -r file; do
echo "$remote => $file"
# сбрасываем значения параметров
sed -i 's/gitea\.com/tmp_stub/g' "$file"
sed -i 's/GITEA\.COM/TMP_STUB/g' "$file"
sed -i 's/git\.org\.ru/tmp_stub/g' "$file"
sed -i 's/GIT\.ORG\.RU/TMP_STUB/g' "$file"
sed -i 's/hub\.mos\.ru/tmp_stub/g' "$file"
sed -i 's/HUB\.MOS\.RU/TMP_STUB/g' "$file"
# устанавливаем значения параметров
sed -i 's/tmp_stub/'$domain'/g' "$file"
sed -i 's/TMP_STUB/'$DOMAIN'/g' "$file"
if [ "$remote" == "hub.mos.ru" ]; then
sed -i 's/src\/branch/blob/g' "$file"
else
sed -i 's/blob/src\/branch/g' "$file"
fi
done
# шаблоны для подстановки
expr+=("s|gitea\.com|$domain|g")
expr+=("s|GITEA\.COM|$DOMAIN|g")
expr+=("s|git\.org\.ru|$domain|g")
expr+=("s|GIT\.ORG\.RU|$DOMAIN|g")
expr+=("s|hub\.mos\.ru|$domain|g")
expr+=("s|HUB\.MOS\.RU|$DOMAIN|g")
if [ "$domain" == "hub.mos.ru" ]; then
expr+=("s|src/branch|blob|g")
else
expr+=("s|blob|src/branch|g")
fi
cd ../.. # выход из папки и из репозитория
time_ms="$(date '+%s%3N')"
# запуск параллельной обработки файлов "README" и подстановка значений по шаблонам
find . -type f -name "README*.md" -printf '%p\0' | xargs -I{} -n1 -0 -P0 bash -c \
"echo '$domain => {}' && sed -i $(printf " -e '%s'" "${expr[@]}") '{}'"
echo "Общее время выполнения: $(($(date '+%s%3N') - time_ms)) мс."

View file

@ -12,25 +12,21 @@ function directory_tree {
local head="$2"
local tail="$3"
# префикс для текущего элемента
if [ "one" == "$4" ]; then
echo -n "/"
else
echo -ne "\n$head"
fi
[ "one" == "$4" ] && printf '%s' "/" || printf '\n%s' "$head"
# текущий элемент дерева
echo -n "<a href='${path#*/}'>${path##*/}</a>"
printf '%s' "<a href='${path#*/}'>${path##*/}</a>"
# рекурсивные вызовы для подкаталогов
if [ -d "$path" ]; then
local list # массив файлов и каталогов
readarray -t list <<<"$(list_directory_contents "$path")"
local len=${#list[@]} # размер массива
readarray -t list < <(list_directory_contents "$path")
local size=${#list[@]} # длина массива
local i # счётчик
for ((i = 0; i < len; i++)); do
for ((i = 0; i < size; i++)); do
if [ -z "${list[$i]}" ]; then
continue # пропустить пустой каталог
elif ((len == 1)); then
elif ((size == 1)); then
directory_tree "$path/${list[$i]}" "$tail" "$tail" "one"
elif ((i < len - 1)); then
elif ((i < size - 1)); then
directory_tree "$path/${list[$i]}" "$tail├─ " "$tail"
else
directory_tree "$path/${list[$i]}" "$tail└─ " "$tail "
@ -38,29 +34,24 @@ function directory_tree {
done
fi
}
cd .. # выходим из папки в корень репозитория
basedir=$(pwd) # текущий репозиторий
currentTimeMillis=$(date '+%s%3N')
# обходим все репозитории, расположенные на одном уровне с текущим
find .. -mindepth 1 -maxdepth 1 -type d | sort -r | while read -r dir; do
echo "Обработка: $dir"
# заходим в каталог, иначе пропускаем итерацию
cd "$dir" || continue
# строка исключений для 'ls' из списка '.gitignore' — неотслеживаемые файлы
exclusions="-I \".git\" $(sed 's/^/ -I "/;s/$/"/' .gitignore | tr -d '\n')"
# помещаем дерево в контейнер, добавляем заголовок и выводим в файл
{
echo "## Дерево каталогов"
echo -ne "\n<pre>"
directory_tree .
echo -e "\n</pre>"
} >DIRECTORY_TREE.md
# копирование файлов лицензии и построение дерева каталогов
function tree_license {
echo "Обработка: $1"
cd "$1" || return
# копирование файлов из этого репозитория во все остальные
if [ "${dir##*/}" != "${basedir##*/}" ]; then
rm CONTRIBUTING.md
rm ./*LICENSE*
cp "$basedir"/CONTRIBUTING.md .
cp "$basedir"/*LICENSE* .
if [ "$1" != "./pomodoro" ]; then
cp -f ../pomodoro/CONTRIBUTING.md .
cp -f ../pomodoro/*LICENSE* .
fi
done
echo "Время выполнения: $(("$(date '+%s%3N')" - "$currentTimeMillis")) мс."
# строка исключений для "ls" из списка неотслеживаемых файлов ".gitignore"
exclusions="-I'.git' $(sed -E "s|^(.*)$|-I'\1'|" .gitignore | tr '\n' ' ')"
# помещаем дерево в контейнер, добавляем заголовок и выводим в файл
printf '%s\n' "## Дерево каталогов" "" "<pre>" \
"$(directory_tree . | grep '\S')" "</pre>" >DIRECTORY_TREE.md
}
export -f tree_license directory_tree list_directory_contents
cd ../.. # выход из папки и из репозитория
time_ms="$(date '+%s%3N')"
# запуск параллельной обработки всех репозиториев, расположенных на одном уровне с текущим, кроме папки ".idea"
find . -mindepth 1 -maxdepth 1 -type d -not -name ".idea" -printf 'tree_license "%p"\0' | xargs -n1 -0 -P0 bash -c
echo "Общее время выполнения: $(($(date '+%s%3N') - time_ms)) мс."

View file

@ -1,83 +1,86 @@
#!/bin/bash
echo "Составление скриптов с параметрами и копирование их в каталоги проектов."
remote="git.org.ru" && source info_param.sh
basedir=$(pwd)
cd ../.. # выходим из папки и из репозитория
# обходим все репозитории, расположенные на одном уровне с текущим
find . -mindepth 1 -maxdepth 1 -type d | sort -r | while read -r dir; do
echo "Обработка: $dir"
# добавляем исключение в список '.gitignore', если ещё не добавлено
if [ ! -f "$dir"/.gitignore ] || [ "$(grep -cx "\.repo_\*" "$dir"/.gitignore)" == 0 ]; then
echo ".repo_*" >>"$dir"/.gitignore
echo "Обновлён файл .gitignore"
echo "Создание скриптов из шаблонов с параметрами и сохранение их в каталогах проектов."
export domain="git.org.ru" && source info_param.sh
export basedir="$PWD" # текущая папка
# создание скриптов из шаблонов с параметрами
function compose {
echo "Обработка: $1"
# добавление исключения в список неотслеживаемых файлов, если оно ещё не добавлено
if [ ! -f "$1/.gitignore" ] || [ "$(grep -cF ".repo_*" "$1/.gitignore")" == 0 ]; then
echo ".repo_*" >>"$1/.gitignore" && echo "Обновлён файл: $1/.gitignore"
fi
# параметры для шаблонов
owner="golovin"
repo=${dir##*/}
description=""
type="usr"
wiki=""
# оглавления по страницам сайтов
if [ -f "$dir"/WIKI.md ]; then
if [ "$remote" == "hub.mos.ru" ]; then
wiki=$(uni2ascii -a U -qpsn "$dir"/WIKI.md)
# значения для параметров
owner="golovin" && repo="$1"
case "$1" in
*[1-6]) owner="pomodoro" && repo="${1//$owner/}" ;;&
*1) description="Трёхмерная графика на JavaScript" ;;&
*2) description="Декартово произведение, комбинаторика" ;;&
*3) description="Умножение матриц и повороты" ;;&
*4) description="Практическая философия, поэзия и юмор" ;;&
*5) description="Рисуем картинки текстом" ;;&
*6) description="Пустой" ;;&
*[1-6]) description+=" — https://$owner$repo.mircloud.ru" ;;
pomodoro) description="Описание и оглавление" ;;
color-tomato*) description="Тема оформления / Цветной помидор" ;;
older-tomato*) description="Тема оформления / Старый помидор" ;;
*) return ;; # шесть помидорных вёб-сайтов и три репозитория пользователя
esac
wiki="" # оглавление по страницам вёб-сайта
if [ -f "$1/WIKI.md" ]; then
if [ "$domain" == "hub.mos.ru" ]; then
wiki="$(uni2ascii -aU -qpsn "$1/WIKI.md")"
else
wiki=$(basenc "$dir"/WIKI.md --base64 -w0)
wiki="$(basenc "$1/WIKI.md" --base64 -w0)"
fi
fi
# краткие описания для репозиториев
if [[ "$dir" =~ "pomodoro" ]]; then
if [[ "$dir" =~ [[:digit:]] ]]; then
owner="pomodoro"
repo=${dir//[^[:digit:]]/}
type="org"
if [[ "$dir" =~ "1" ]]; then
description="Трёхмерная графика на JavaScript"
elif [[ "$dir" =~ "2" ]]; then
description="Декартово произведение, комбинаторика"
elif [[ "$dir" =~ "3" ]]; then
description="Умножение матриц и повороты"
elif [[ "$dir" =~ "4" ]]; then
description="Практическая философия, поэзия и юмор"
elif [[ "$dir" =~ "5" ]]; then
description="Рисуем картинки текстом"
elif [[ "$dir" =~ "6" ]]; then
description="Пустой"
fi
description+=" — https://$owner$repo.mircloud.ru"
else
description="Описание и оглавление"
fi
elif [[ "$dir" =~ "color-tomato" ]]; then
description="Тема оформления / Цветной помидор"
elif [[ "$dir" =~ "older-tomato" ]]; then
description="Тема оформления / Старый помидор"
file="DIRECTORY_TREE.md" # тестирование вёб-интерфейса
if [ "$domain" == "hub.mos.ru" ]; then
folder="blob" && wiki_home="-/wikis/home"
else
folder="src/branch" && wiki_home="wiki"
fi
# одинаковая шапка "shebang" для всех трёх скриптов
echo "#!/bin/bash" | tee "$1/.repo_remote.sh" "$1/.repo_local.sh" >"$1/.repo_testing.sh"
# параметры для удалённого репозитория
param_remote+=("domain='$domain'")
param_remote+=("owner='$owner'")
param_remote+=("user='golovin'")
param_remote+=("repo='$repo'")
param_remote+=("description='$description'")
param_remote+=("wiki='$wiki'")
if [ "$domain" == "hub.mos.ru" ]; then
param_remote+=("token='$(cat "$basedir/.token_gitlab")'")
template_remote="repo_gitlab.tmpl.sh"
else
param_remote+=("token='$(cat "$basedir/.token_gitea")'")
template_remote="repo_gitea.tmpl.sh"
fi
# скрипт для создания удалённого репозитория
{
echo "#!/bin/bash"
echo "remote=\"$remote\""
echo "user=\"golovin\""
echo "owner=\"$owner\""
echo "repo=\"$repo\""
echo "description=\"$description\""
echo "type=\"$type\""
echo "wiki=\"$wiki\""
if [ "$remote" == "hub.mos.ru" ]; then
echo "token=\"$(cat "$basedir/.token_gitlab")\""
cat "$basedir/repo_gitlab.tmpl.sh"
else
echo "token=\"$(cat "$basedir/.token_gitea")\""
cat "$basedir/repo_gitea.tmpl.sh"
fi
} >"$dir"/.repo_remote.sh && chmod +x "$dir"/.repo_remote.sh
printf '%s\n' "${param_remote[@]}" >>"$1/.repo_remote.sh"
tail -n+2 "$basedir/$template_remote" >>"$1/.repo_remote.sh"
chmod +x "$1/.repo_remote.sh"
# параметры для локального репозитория
param_local+=("domain='$domain'")
param_local+=("owner='$owner'")
param_local+=("repo='$repo'")
param_local+=("dir='$1'")
# скрипт для создания локального репозитория
{
echo "#!/bin/bash"
echo "remote=\"$remote\""
echo "owner=\"$owner\""
echo "repo=\"$repo\""
echo "folder=\"${dir##*/}\""
cat "$basedir/repo_local.tmpl.sh"
} >"$dir"/.repo_local.sh && chmod +x "$dir"/.repo_local.sh
done
printf '%s\n' "${param_local[@]}" >>"$1/.repo_local.sh"
tail -n+2 "$basedir/repo_local.tmpl.sh" >>"$1/.repo_local.sh"
chmod +x "$1/.repo_local.sh"
# параметры для тестирования вёб-интерфейса
param_testing+=("'https://$domain/$owner/$repo/$folder/master/$file' '$file'")
if [ "$wiki" ]; then
param_testing+=("'https://$domain/$owner/$repo/$wiki_home' 'Home'")
fi
# скрипт для тестирования вёб-интерфейса
printf 'pages+=("%s")\n' "${param_testing[@]}" >>"$1/.repo_testing.sh"
tail -n+21 "$basedir/repo_testing.smpl.sh" >>"$1/.repo_testing.sh"
chmod +x "$1/.repo_testing.sh"
}
export -f compose
cd ../.. # выход из папки и из репозитория
time_ms="$(date '+%s%3N')"
# запуск параллельной обработки всех репозиториев, расположенных на одном уровне с текущим, кроме папки ".idea"
find . -mindepth 1 -maxdepth 1 -type d -not -name ".idea" -printf 'compose "%f"\0' | xargs -n1 -0 -P0 bash -c
echo "Общее время выполнения: $(($(date '+%s%3N') - time_ms)) мс."

View file

@ -1,79 +1,62 @@
if [ -z "$remote" ] || [ -z "$token" ] || [ -z "$owner" ] || [ -z "$repo" ] || [ -z "$description" ] || [ -z "$user" ] || [ -z "$type" ]; then
echo "Не указаны обязательные параметры." && exit 2
#!/bin/false
if [[ -z "$domain" || -z "$token" || -z "$owner" || -z "$repo" || -z "$description" || -z "$user" ]]; then
echo "Не указаны обязательные параметры." && exit 1
fi
if [ -z "$1" ]; then
echo "Создание удалённого репозитория для текущего каталога."
fi
seconds=5
currentTimeMillis=$(date '+%s%3N')
time_ms="$(date '+%s%3N')"
if [ -z "$1" ] || [ "$1" == "delete" ]; then
echo "Удаление старого репозитория."
curl -X DELETE "https://$remote/api/v1/repos/$owner/$repo" \
curl -i -X DELETE "https://$domain/api/v1/repos/$owner/$repo" \
-H "Authorization: token $token" \
-H "Accept: application/json" -i
echo "Ожидание $seconds с."
sleep $seconds
if [ "$1" ]; then
exit 0
fi
-H "Accept: application/json"
fi
if [ -z "$1" ] || [ "$1" == "create" ]; then
echo "Создание нового репозитория пользователя."
curl -X POST "https://$remote/api/v1/user/repos" \
curl -i -X POST "https://$domain/api/v1/user/repos" \
-H "Authorization: token $token" \
-H "Accept: application/json" \
-H "Content-Type: application/json" -d "{ \"name\": \"$repo\", \"description\": \"$description\" }" -i
echo "Ожидание $seconds с."
sleep $seconds
if [ "$type" == "org" ]; then
-H "Content-Type: application/json" -d "{ \"name\": \"$repo\", \"description\": \"$description\" }"
if [ "$user" != "$owner" ]; then
echo "Перемещение репозитория в группу."
curl -X POST "https://$remote/api/v1/repos/$user/$repo/transfer" \
curl -i -X POST "https://$domain/api/v1/repos/$user/$repo/transfer" \
-H "Authorization: token $token" \
-H "Accept: application/json" \
-H "Content-Type: application/json" -d "{ \"new_owner\": \"$owner\" }" -i
echo "Ожидание $seconds с."
sleep $seconds
fi
if [ "$1" ]; then
exit 0
-H "Content-Type: application/json" -d "{ \"new_owner\": \"$owner\" }"
fi
fi
if [ -z "$1" ] || [ "$1" == "options" ]; then
if [ "$wiki" ]; then
echo "Добавление страницы wiki в репозиторий."
curl -X POST "https://$remote/api/v1/repos/$owner/$repo/wiki/new" \
curl -i -X POST "https://$domain/api/v1/repos/$owner/$repo/wiki/new" \
-H "Authorization: token $token" \
-H "Accept: application/json" \
-H "Content-Type: application/json" -d "{ \"content_base64\": \"$wiki\", \"title\": \"Home\" }" -i
-H "Content-Type: application/json" -d "{ \"content_base64\": \"$wiki\", \"title\": \"Home\" }"
has_wiki=true
else
has_wiki=false
fi
echo "Изменение свойств репозитория / отключение ненужного."
curl -X PATCH "https://$remote/api/v1/repos/$owner/$repo" \
curl -i -X PATCH "https://$domain/api/v1/repos/$owner/$repo" \
-H "Authorization: token $token" \
-H "Accept: application/json" \
-H "Content-Type: application/json" -d "{
\"has_actions\": false,
\"has_issues\": false,
\"has_packages\": false,
\"has_projects\": false,
\"has_pull_requests\": false,
\"has_releases\": false,
\"has_wiki\": $has_wiki }" -i
# Метод API появился в версии 1.21.0
\"has_projects\": false, \"has_issues\": false,
\"has_releases\": false, \"has_actions\": false,
\"has_packages\": false, \"has_pull_requests\": false,
\"has_wiki\": $has_wiki }"
echo "Добавление аватарки для репозитория."
picture=$repo
if [ "$type" == "org" ]; then
picture="$repo"
if [ "$user" != "$owner" ]; then
picture="website"
fi
avatar=$(basenc "../pomodoro/pictures/$picture.jpg" --base64 -w0)
curl -X POST "https://$remote/api/v1/repos/$owner/$repo/avatar" \
curl -i -X POST "https://$domain/api/v1/repos/$owner/$repo/avatar" \
-H "Authorization: token $token" \
-H "Accept: application/json" \
-H "Content-Type: application/json" -d "{ \"image\": \"$avatar\" }" -i
if [ "$1" ]; then
exit 0
fi
-H "Content-Type: application/json" -d "{ \"image\": \"$avatar\" }"
fi
if [ -z "$1" ]; then
echo "Общее время выполнения: $(($(date '+%s%3N') - time_ms)) мс."
fi
echo "Время создания удалённого репозитория: $(("$(date '+%s%3N')" - "$currentTimeMillis")) мс."

View file

@ -1,104 +1,73 @@
if [ -z "$remote" ] || [ -z "$token" ] || [ -z "$owner" ] || [ -z "$repo" ] || [ -z "$description" ] || [ -z "$user" ] || [ -z "$type" ]; then
echo "Не указаны обязательные параметры." && exit 2
#!/bin/false
if [[ -z "$domain" || -z "$token" || -z "$owner" || -z "$repo" || -z "$description" || -z "$user" ]]; then
echo "Не указаны обязательные параметры." && exit 1
fi
if [ -z "$1" ]; then
echo "Создание удалённого репозитория для текущего каталога."
fi
seconds=5
currentTimeMillis=$(date '+%s%3N')
time_ms="$(date '+%s%3N')"
if [ -z "$1" ] || [ "$1" == "delete" ]; then
echo "Удаление старого репозитория."
curl -i -X DELETE "https://$remote/api/v4/projects/$owner%2F$repo" \
curl -i -X DELETE "https://$domain/api/v4/projects/$owner%2F$repo" \
-H "PRIVATE-TOKEN: $token" \
-H "Content-Type: application/json" -d "{\"permanently_remove\": \"true\", \"full_path\": \"$owner/$repo\"}"
-H "Content-Type: application/json" -d "{ \"permanently_remove\": \"true\", \"full_path\": \"$owner/$repo\" }"
echo
echo "Ожидание $seconds с."
sleep $seconds
if [ "$1" ]; then
exit 0
fi
fi
if [ -z "$1" ] || [ "$1" == "create" ]; then
echo "Создание нового репозитория пользователя."
curl -i -X POST "https://$remote/api/v4/projects" \
curl -i -X POST "https://$domain/api/v4/projects" \
-H "PRIVATE-TOKEN: $token" \
-H "Content-Type: application/json" -d "{\"name\": \"$repo\", \"description\": \"$description\"}"
-H "Content-Type: application/json" -d "{ \"name\": \"$repo\", \"description\": \"$description\" }"
echo
echo "Ожидание $seconds с."
sleep $seconds
if [ "$type" == "org" ]; then
if [ "$user" != "$owner" ]; then
echo "Перемещение репозитория в группу."
curl -i -X PUT "https://$remote/api/v4/projects/$user%2F$repo/transfer?namespace=$owner" \
curl -i -X PUT "https://$domain/api/v4/projects/$user%2F$repo/transfer?namespace=$owner" \
-H "PRIVATE-TOKEN: $token"
echo
echo "Ожидание $seconds с."
sleep $seconds
fi
if [ "$1" ]; then
exit 0
fi
fi
if [ -z "$1" ] || [ "$1" == "options" ]; then
if [ "$wiki" ]; then
echo "Добавление страницы wiki в репозиторий."
curl -i -X POST "https://$remote/api/v4/projects/$owner%2F$repo/wikis" \
curl -i -X POST "https://$domain/api/v4/projects/$owner%2F$repo/wikis" \
-H "PRIVATE-TOKEN: $token" \
-H "Content-Type: application/json" -d "{\"content\": \"$wiki\", \"title\": \"Home\"}"
-H "Content-Type: application/json" -d "{ \"content\": \"$wiki\", \"title\": \"Home\" }"
echo
has_wiki="enabled"
else
has_wiki="disabled"
fi
echo "Изменение свойств репозитория / отключение ненужного."
curl -i -X PUT "https://$remote/api/v4/projects/$owner%2F$repo" \
curl -i -X PUT "https://$domain/api/v4/projects/$owner%2F$repo" \
-H "PRIVATE-TOKEN: $token" \
-H "Content-Type: application/json" -d "{
\"emails_disabled\": \"true\",
\"issues_access_level\": \"disabled\",
\"merge_requests_access_level\": \"disabled\",
\"operations_access_level\": \"disabled\",
\"builds_access_level\": \"disabled\",
\"request_access_enabled\": \"false\",
\"keep_latest_artifact\": \"false\",
\"ci_forward_deployment_enabled\": \"false\",
\"ci_separated_caches\": \"false\",
\"ci_allow_fork_pipelines_to_run_in_parent_project\": \"false\",
\"jobs_enabled\": \"false\",
\"public_builds\": \"false\",
\"packages_enabled\": \"false\",
\"merge_requests_enabled\": \"false\",
\"issues_enabled\": \"false\",
\"lfs_enabled\": \"false\",
\"snippets_enabled\": \"false\",
\"container_registry_enabled\": \"false\",
\"wiki_access_level\": \"$has_wiki\",
\"container_registry_access_level\": \"disabled\",
\"security_and_compliance_access_level\": \"disabled\",
\"pages_access_level\": \"disabled\",
\"analytics_access_level\": \"disabled\",
\"forking_access_level\": \"disabled\",
\"releases_access_level\": \"disabled\",
\"requirements_access_level\": \"disabled\",
\"environments_access_level\": \"disabled\",
\"feature_flags_access_level\": \"private\",
\"infrastructure_access_level\": \"private\",
\"monitor_access_level\": \"disabled\",
\"snippets_access_level\": \"disabled\",
\"auto_devops_enabled\": \"false\",
\"shared_runners_enabled\": \"false\",
\"group_runners_enabled\": \"false\"}"
\"emails_disabled\": \"true\", \"issues_access_level\": \"disabled\",
\"merge_requests_access_level\": \"disabled\", \"operations_access_level\": \"disabled\",
\"builds_access_level\": \"disabled\", \"request_access_enabled\": \"false\",
\"keep_latest_artifact\": \"false\", \"ci_forward_deployment_enabled\": \"false\",
\"ci_separated_caches\": \"false\", \"ci_allow_fork_pipelines_to_run_in_parent_project\": \"false\",
\"jobs_enabled\": \"false\", \"public_builds\": \"false\", \"packages_enabled\": \"false\",
\"merge_requests_enabled\": \"false\", \"issues_enabled\": \"false\", \"lfs_enabled\": \"false\",
\"snippets_enabled\": \"false\", \"container_registry_enabled\": \"false\",
\"wiki_access_level\": \"$has_wiki\", \"container_registry_access_level\": \"disabled\",
\"security_and_compliance_access_level\": \"disabled\", \"pages_access_level\": \"disabled\",
\"analytics_access_level\": \"disabled\", \"forking_access_level\": \"disabled\",
\"releases_access_level\": \"disabled\", \"requirements_access_level\": \"disabled\",
\"environments_access_level\": \"disabled\", \"feature_flags_access_level\": \"private\",
\"infrastructure_access_level\": \"private\", \"monitor_access_level\": \"disabled\",
\"snippets_access_level\": \"disabled\", \"auto_devops_enabled\": \"false\",
\"shared_runners_enabled\": \"false\", \"group_runners_enabled\": \"false\" }"
echo
echo "Добавление аватарки для репозитория."
picture=$repo
if [ "$type" == "org" ]; then
picture="$repo"
if [ "$user" != "$owner" ]; then
picture="website"
fi
curl -i -X PUT "https://$remote/api/v4/projects/$owner%2F$repo" \
curl -i -X PUT "https://$domain/api/v4/projects/$owner%2F$repo" \
-H "PRIVATE-TOKEN: $token" \
-F "avatar=@../pomodoro/pictures/$picture.jpg"
echo
if [ "$1" ]; then
exit 0
fi
fi
echo "Время создания удалённого репозитория: $(("$(date '+%s%3N')" - "$currentTimeMillis")) мс."
if [ -z "$1" ]; then
echo "Общее время выполнения: $(($(date '+%s%3N') - time_ms)) мс."
fi

View file

@ -1,19 +1,21 @@
if [ -z "$remote" ] || [ -z "$owner" ] || [ -z "$repo" ] || [ -z "$folder" ]; then
echo "Не указаны обязательные параметры." && exit 2
#!/bin/false
if [[ -z "$domain" || -z "$owner" || -z "$repo" || -z "$dir" ]]; then
echo "Не указаны обязательные параметры." && exit 1
fi
echo "Создание локального репозитория, подключение к удалённому и передача данных."
seconds=3
currentTimeMillis=$(date '+%s%3N')
time_ms="$(date '+%s%3N')"
# строка исключений для "find" из списка неотслеживаемых файлов ".gitignore"
exclusions="-not -path '*/.git/*' $(sed -E "s|^(.*)$|-not -path '*/\1*'|" .gitignore | tr '\n' ' ')"
# перевести размеры файла в человеко-читаемую строку, отбросить нули из дробной части и добавить пробел
function BKM { numfmt --to=iec --format="%.2f" --suffix="B" "$1" | sed -r 's|,{,1}0{,2}([BKM])| \1|'; }
rm -rf .git
git init -b master
git remote add "$remote" "git@$remote:$owner/$repo.git"
git remote add "$domain" "git@$domain:$owner/$repo.git"
git add .git*
git commit -m "Инициализация / $folder"
if [ "$remote" == "hub.mos.ru" ]; then
git commit -m "Инициализация / $dir"
if [ "$domain" == "hub.mos.ru" ]; then
echo "Второй пуш, потому что лингвист с первого раза не срабатывает."
git push -u "$remote" master
echo "Ожидание $seconds с."
sleep $seconds
git push -u "$domain" master
fi
git add CONTRIBUTING.md
git add \*LICENSE*
@ -26,7 +28,6 @@ git add \*.yml
git add \*Gemfile*
git add \*install.sh
git add \*.gemspec
git add \*counters_*
git add \*robots.txt
git commit -m "Настройки"
git add \*.sh
@ -42,10 +43,10 @@ git add \*.jpg
git add \*.png
git add \*.svg
git commit -m "Картинки"
find . -type f -not -path "*/.*" -not -path "./_site*" | sort -r | while read -r file; do
while read -r file size; do
echo "Обработка: $file"
git add "$file"
git commit -m "${file#*/}"
done
git push -u "$remote" master
echo "Время создания локального репозитория: $(("$(date '+%s%3N')" - "$currentTimeMillis")) мс."
git commit -m "${file#*/} / $(BKM "$size")"
done < <(eval "find . -type f $exclusions -printf '%p %s\n'" | LC_COLLATE=C sort -r)
git push -u "$domain" master
echo "Общее время выполнения: $(($(date '+%s%3N') - time_ms)) мс."

View file

@ -1,20 +1,34 @@
#!/bin/bash
echo "Параллельное выполнение скриптов и создание репозиториев для каталогов проектов."
# Для всех репозиториев на одном уровне с текущим формируем скрипт в одну строчку и выполняем эти скрипты в параллельном режиме.
# Скрипт в одну строчку — это выполнение одного из заранее подготовленных других скриптов для локальных и удалённых репозиториев.
# Формируем и выполняем скрипты в несколько шагов с разными параметрами и по дороге сохраняем отчёты о выполнении.
# Параллельное выполнение скриптов на последующем шаге начинается после завершения всех потоков на предыдущем шаге.
cd .. # выходим из папки в корень репозитория
currentTimeMillis=$(date '+%s%3N')
# 1 Удаление репозиториев на сервере
find .. -mindepth 1 -maxdepth 1 -type d -printf \
'cd %h/%f && ./.repo_remote.sh "delete" >.repo_remote.log\0' | xargs -L1 -0 -P0 bash -c
# 2 Создание репозиториев на сервере
find .. -mindepth 1 -maxdepth 1 -type d -printf \
'cd %h/%f && ./.repo_remote.sh "create" >>.repo_remote.log\0' | xargs -L1 -0 -P2 bash -c
# 3 Создание локальных репозиториев и отправка данных на сервер
# 4 Изменение настроек репозиториев на сервере, отключение ненужного
find .. -mindepth 1 -maxdepth 1 -type d -printf \
'cd %h/%f && ./.repo_local.sh >.repo_local.log\0
cd %h/%f && ./.repo_remote.sh "options" >>.repo_remote.log\0' | xargs -L1 -0 -P0 bash -c
echo "Общее время выполнения: $(("$(date '+%s%3N')" - "$currentTimeMillis")) мс."
# выполнение скриптов внутри каталога
function orchestrate {
cd "$1" || return
while true; do
while true; do
# 1 Удаление репозитория на сервере
./.repo_remote.sh "delete" >.repo_remote.log
# 2 Создание репозитория на сервере
./.repo_remote.sh "create" >>.repo_remote.log
# 3 Проверка корректности ответа от сервера при создании репозитория
case "$(tail -n+10 .repo_remote.log | grep -cE '^HTTP/[1,2].{,2}? [4,5]')" in
0) break ;; *) echo "Ошибка 400-500. Невозможно подключение к серверу: $1" ;;
esac
done
# 4 Создание локального репозитория и отправка данных на сервер
./.repo_local.sh >.repo_local.log
# 5 Изменение настроек репозитория на сервере, отключение ненужного
./.repo_remote.sh "options" >>.repo_remote.log
# 6 Проверка доступности вёб-интерфейса на сервере
case "$(./.repo_testing.sh | grep -cF '[91m')" in
0) break ;; *) echo "Ошибка доступности вёб-интерфейса: $1" ;;
esac
done
}
export -f orchestrate
cd ../.. # выход из папки и из репозитория
time_ms="$(date '+%s%3N')"
# запуск параллельной обработки всех каталогов проектов, расположенных на одном уровне с текущим
find . -mindepth 1 -maxdepth 1 -type d -printf 'orchestrate "%p"\0' | xargs -n1 -0 -P0 bash -c
# замер продолжительности выполнения в миллисекундах, пересчёт в минуты, секунды и миллисекунды
tms="$(($(date '+%s%3N') - time_ms))" && min="$((tms / 1000 / 60))" && sec="$((tms / 1000 % 60))"
ms="$((tms % 1000))" && printf 'Общее время выполнения: %02d:%02d.%03d мс.\n' "$min" "$sec" "$ms"

View file

@ -0,0 +1,35 @@
#!/bin/bash
echo "Образец скрипта для тестирования доступности страниц в вёб-интерфейсе на сервере."
domain="git.org.ru" && source "info_param.sh"
# две страницы для тестирования
file="DIRECTORY_TREE.md"
if [ "$domain" == "hub.mos.ru" ]; then
folder="blob" && wiki_home="-/wikis/home"
else
folder="src/branch" && wiki_home="wiki"
fi
# подготовка массива строк — адрес страницы и название файла через пробел
for repo in {1..6}; do
#pages+=("'https://$domain/golovin/$repo/$folder/master/$file' '$file'")
pages+=("'https://$domain/pomodoro/$repo/$folder/master/$file' '$file'")
pages+=("'https://$domain/pomodoro/$repo/$wiki_home' 'Home'")
done
for repo in {pomodoro,older-tomato-theme,color-tomato-theme}; do
pages+=("'https://$domain/golovin/$repo/$folder/master/$file' '$file'")
pages+=("'https://$domain/golovin/$repo/$wiki_home' 'Home'")
done
# тестирование доступности страниц
function testing {
# название файла должно находиться в заголовке страницы, иначе сервер должен вернуть ошибку
case "$(curl "$1" 2>/dev/null | grep -oP '(?<=<title>).*(?=</title>)' | grep -cF "$2")" in
0) color="91" ;; # светло-красный цвет для отсутствующих страниц
*) color="0" ;; # обычный цвет для всех остальных страниц
esac
# текст соответствующего цвета и адрес страницы
printf "\e[${color}m%s\e[0m %s\n" "Страница:" "$1"
}
export -f testing
time_ms="$(date '+%s%3N')"
# запуск параллельного тестирования строк массива и сортировка результатов
printf "testing %s\0" "${pages[@]}" | xargs -n1 -0 -P0 bash -c | sort -r -k2
echo "Общее время выполнения: $(($(date '+%s%3N') - time_ms)) мс."

View file

@ -9,9 +9,3 @@
| ![pomodoro](pomodoro.jpg) |
| website |
| ![website](website.jpg) |
| bash_scripts |
| ![bash_scripts](bash_scripts.jpg) |
| archive |
| ![archive](archive.jpg) |
| pictures |
| ![pictures](pictures.jpg) |

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.1 KiB

After

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.5 KiB

After

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.9 KiB