Compare commits
10 commits
db23690a88
...
4fb8930c3e
Author | SHA1 | Date | |
---|---|---|---|
4fb8930c3e | |||
fa7f621960 | |||
4339539c68 | |||
6fb4dfdbf4 | |||
ccb23ae867 | |||
9fe170e09b | |||
d59da594ba | |||
e91d1096f6 | |||
07b494aa75 | |||
1543a1c0af |
|
@ -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>
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
34
README.en.md
|
@ -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.com](https://gitea.com/pomodoro) — latest version.
|
||||
- [git.org.ru](https://git.org.ru/pomodoro) — history of changes.
|
||||
- [hub.mos.ru](https://hub.mos.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
|
||||
|
|
|
@ -5,6 +5,10 @@
|
|||
открытая лицензия РФ вместо MIT — изменений много и везде, но суть осталась прежней — ничего не изменилось. Серия
|
||||
статических вёб-сайтов «Помидоры» — чтобы не скучать и чтобы не забыть, как программы писать, когда работы нет.
|
||||
|
||||
- [gitea.com](https://gitea.com/pomodoro) — последняя версия.
|
||||
- [git.org.ru](https://git.org.ru/pomodoro) — история изменений.
|
||||
- [hub.mos.ru](https://hub.mos.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
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
|
||||
| Незавершённые публикации | Язык | Обновление |
|
||||
|:-----------------------------------------------------------|------|------------|
|
||||
|------------------------------------------------------------------|------|------------|
|
||||
| [Распараллеливание скриптов Bash](parallelizing-bash-scripts.md) | Bash | 2024.09.05 |
|
||||
| [Циклический алгоритм распределения задач](round-robin.md) | Java | 2023.06.05 |
|
||||
|
|
98
archive/parallelizing-bash-scripts.md
Normal 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
|
|
@ -284,4 +284,4 @@ class Test2 {
|
|||
|
||||
---
|
||||
|
||||
© Головин Г.Г., Код с комментариями, 2021-2023
|
||||
© Головин Г.Г., Код с комментариями, 2023
|
||||
|
|
|
@ -3,23 +3,26 @@
|
|||
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. |
|
||||
| | [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) | 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. |
|
||||
| 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.com](https://gitea.com/golovin),
|
||||
[git.org.ru](https://git.org.ru/golovin) and
|
||||
[hub.mos.ru](https://hub.mos.ru/golovin).
|
||||
|
||||
|
|
|
@ -3,23 +3,26 @@
|
|||
Создание архива, переключение домена, составление скриптов и создание репозиториев для публикации.
|
||||
|
||||
| № | Скрипты Bash | Выполняемые действия |
|
||||
|---|:-----------------------------------------------|:---------------------------------------------------------------------------------|
|
||||
|---|:-----------------------------------------------|:----------------------------------------------------------------------------------|
|
||||
| 1 | [**archive_backup.sh**](archive_backup.sh) | Создание общего архива для каталогов проектов на текущую дату. |
|
||||
| | [archive_packages.sh](archive_packages.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) | Составление скриптов с параметрами и копирование их в каталоги проектов. |
|
||||
| 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) | Шаблон скрипта без параметров для создания локального репозитория. |
|
||||
| | [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.com](https://gitea.com/golovin),
|
||||
[git.org.ru](https://git.org.ru/golovin) и
|
||||
[hub.mos.ru](https://hub.mos.ru/golovin).
|
||||
|
||||
|
|
|
@ -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
|
@ -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)) мс."
|
|
@ -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")) мс."
|
16
bash_scripts/archive_packaging.sh
Executable 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)) мс."
|
|
@ -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"
|
||||
|
|
|
@ -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)) мс."
|
||||
|
|
|
@ -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)) мс."
|
||||
|
|
|
@ -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"
|
||||
file="DIRECTORY_TREE.md" # тестирование вёб-интерфейса
|
||||
if [ "$domain" == "hub.mos.ru" ]; then
|
||||
folder="blob" && wiki_home="-/wikis/home"
|
||||
else
|
||||
description="Описание и оглавление"
|
||||
folder="src/branch" && wiki_home="wiki"
|
||||
fi
|
||||
elif [[ "$dir" =~ "color-tomato" ]]; then
|
||||
description="Тема оформления / Цветной помидор"
|
||||
elif [[ "$dir" =~ "older-tomato" ]]; then
|
||||
description="Тема оформления / Старый помидор"
|
||||
# одинаковая шапка "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)) мс."
|
||||
|
|
|
@ -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")) мс."
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)) мс."
|
||||
|
|
|
@ -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"
|
||||
|
|
35
bash_scripts/repo_testing.smpl.sh
Executable 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)) мс."
|
|
@ -9,9 +9,3 @@
|
|||
|  |
|
||||
| website |
|
||||
|  |
|
||||
| bash_scripts |
|
||||
|  |
|
||||
| archive |
|
||||
|  |
|
||||
| pictures |
|
||||
|  |
|
||||
|
|
Before Width: | Height: | Size: 4.2 KiB |
Before Width: | Height: | Size: 15 KiB |
Before Width: | Height: | Size: 5.1 KiB After Width: | Height: | Size: 5.7 KiB |
Before Width: | Height: | Size: 4.5 KiB After Width: | Height: | Size: 5.1 KiB |
Before Width: | Height: | Size: 3.9 KiB |