colloq 0.2.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- colloq/__init__.py +12 -0
- colloq/__main__.py +315 -0
- colloq/_app/.colloq-dist.json +66 -0
- colloq/_app/LICENSE +21 -0
- colloq/_app/THIRD_PARTY_NOTICES.md +106 -0
- colloq/_app/cli/colloq.mjs +2517 -0
- colloq/_app/cli/launch.mjs +1572 -0
- colloq/_app/cli/package.json +5 -0
- colloq/_app/cli/public-url-lease.mjs +198 -0
- colloq/_app/kernel/Dockerfile +93 -0
- colloq/_app/kernel/environments/base-gpu.txt +21 -0
- colloq/_app/kernel/environments/base.txt +12 -0
- colloq/_app/kernel/environments/cv.txt +15 -0
- colloq/_app/kernel/environments/gpu.txt +17 -0
- colloq/_app/kernel/environments/kaggle-base.txt +20 -0
- colloq/_app/kernel/environments/pvz-geo.txt +6 -0
- colloq/_app/kernel/requirements.txt +18 -0
- colloq/_app/package.json +20 -0
- colloq/_app/scripts/backup-local.sh +165 -0
- colloq/_app/scripts/backup.sh +34 -0
- colloq/_app/scripts/cluster.sh +492 -0
- colloq/_app/scripts/dns.sh +251 -0
- colloq/_app/scripts/host.sh +1514 -0
- colloq/_app/scripts/lib.sh +62 -0
- colloq/_app/scripts/restore.sh +338 -0
- colloq/_app/scripts/runtime-backup.py +373 -0
- colloq/_app/scripts/state-lock.py +85 -0
- colloq/_app/server/assets/fonts/HSESans-Black.otf +0 -0
- colloq/_app/server/assets/fonts/HSESans-Bold.otf +0 -0
- colloq/_app/server/assets/fonts/HSESans-Regular.otf +0 -0
- colloq/_app/server/assets/fonts/JetBrainsMono-Medium.ttf +0 -0
- colloq/_app/server/assets/fonts/JetBrainsMono-OFL.txt +93 -0
- colloq/_app/server/dist/local-cleanup.js +15987 -0
- colloq/_app/server/dist/runtime-smoke.js +17026 -0
- colloq/_app/server/dist/server.js +54333 -0
- colloq/_app/server/package.json +6 -0
- colloq/_app/web/dist/assets/AdminScreen-C-cg0GlJ.css +1 -0
- colloq/_app/web/dist/assets/AdminScreen-C-cg0GlJ.css.br +0 -0
- colloq/_app/web/dist/assets/AdminScreen-C-cg0GlJ.css.gz +0 -0
- colloq/_app/web/dist/assets/AdminScreen-fu4cB6Ra.js +105 -0
- colloq/_app/web/dist/assets/AdminScreen-fu4cB6Ra.js.br +0 -0
- colloq/_app/web/dist/assets/AdminScreen-fu4cB6Ra.js.gz +0 -0
- colloq/_app/web/dist/assets/App-CMXNqOjp.css +1 -0
- colloq/_app/web/dist/assets/App-CMXNqOjp.css.br +0 -0
- colloq/_app/web/dist/assets/App-CMXNqOjp.css.gz +0 -0
- colloq/_app/web/dist/assets/App-DvCPzIRO.js +26 -0
- colloq/_app/web/dist/assets/App-DvCPzIRO.js.br +0 -0
- colloq/_app/web/dist/assets/App-DvCPzIRO.js.gz +0 -0
- colloq/_app/web/dist/assets/CellOutputs-Dl-AZL45.js +42 -0
- colloq/_app/web/dist/assets/CellOutputs-Dl-AZL45.js.br +0 -0
- colloq/_app/web/dist/assets/CellOutputs-Dl-AZL45.js.gz +0 -0
- colloq/_app/web/dist/assets/CommandPalette-DhBGho7_.js +3 -0
- colloq/_app/web/dist/assets/CommandPalette-DhBGho7_.js.br +0 -0
- colloq/_app/web/dist/assets/CommandPalette-DhBGho7_.js.gz +0 -0
- colloq/_app/web/dist/assets/CompetitionsScreen-Vu3RpHmf.js +3 -0
- colloq/_app/web/dist/assets/CompetitionsScreen-Vu3RpHmf.js.br +0 -0
- colloq/_app/web/dist/assets/CompetitionsScreen-Vu3RpHmf.js.gz +0 -0
- colloq/_app/web/dist/assets/ConsoleView-B2uyYvFh.js +1 -0
- colloq/_app/web/dist/assets/ConsoleView-B2uyYvFh.js.br +0 -0
- colloq/_app/web/dist/assets/ConsoleView-B2uyYvFh.js.gz +0 -0
- colloq/_app/web/dist/assets/ConsoleView-DLbp0Jul.css +1 -0
- colloq/_app/web/dist/assets/DependencyBundleCard-B392XMVZ.js +4 -0
- colloq/_app/web/dist/assets/DependencyBundleCard-B392XMVZ.js.br +0 -0
- colloq/_app/web/dist/assets/DependencyBundleCard-B392XMVZ.js.gz +0 -0
- colloq/_app/web/dist/assets/KaTeX_AMS-Regular-BQhdFMY1.woff2 +0 -0
- colloq/_app/web/dist/assets/KaTeX_AMS-Regular-DMm9YOAa.woff +0 -0
- colloq/_app/web/dist/assets/KaTeX_AMS-Regular-DRggAlZN.ttf +0 -0
- colloq/_app/web/dist/assets/KaTeX_Caligraphic-Bold-ATXxdsX0.ttf +0 -0
- colloq/_app/web/dist/assets/KaTeX_Caligraphic-Bold-BEiXGLvX.woff +0 -0
- colloq/_app/web/dist/assets/KaTeX_Caligraphic-Bold-Dq_IR9rO.woff2 +0 -0
- colloq/_app/web/dist/assets/KaTeX_Caligraphic-Regular-CTRA-rTL.woff +0 -0
- colloq/_app/web/dist/assets/KaTeX_Caligraphic-Regular-Di6jR-x-.woff2 +0 -0
- colloq/_app/web/dist/assets/KaTeX_Caligraphic-Regular-wX97UBjC.ttf +0 -0
- colloq/_app/web/dist/assets/KaTeX_Fraktur-Bold-BdnERNNW.ttf +0 -0
- colloq/_app/web/dist/assets/KaTeX_Fraktur-Bold-BsDP51OF.woff +0 -0
- colloq/_app/web/dist/assets/KaTeX_Fraktur-Bold-CL6g_b3V.woff2 +0 -0
- colloq/_app/web/dist/assets/KaTeX_Fraktur-Regular-CB_wures.ttf +0 -0
- colloq/_app/web/dist/assets/KaTeX_Fraktur-Regular-CTYiF6lA.woff2 +0 -0
- colloq/_app/web/dist/assets/KaTeX_Fraktur-Regular-Dxdc4cR9.woff +0 -0
- colloq/_app/web/dist/assets/KaTeX_Main-Bold-Cx986IdX.woff2 +0 -0
- colloq/_app/web/dist/assets/KaTeX_Main-Bold-Jm3AIy58.woff +0 -0
- colloq/_app/web/dist/assets/KaTeX_Main-Bold-waoOVXN0.ttf +0 -0
- colloq/_app/web/dist/assets/KaTeX_Main-BoldItalic-DxDJ3AOS.woff2 +0 -0
- colloq/_app/web/dist/assets/KaTeX_Main-BoldItalic-DzxPMmG6.ttf +0 -0
- colloq/_app/web/dist/assets/KaTeX_Main-BoldItalic-SpSLRI95.woff +0 -0
- colloq/_app/web/dist/assets/KaTeX_Main-Italic-3WenGoN9.ttf +0 -0
- colloq/_app/web/dist/assets/KaTeX_Main-Italic-BMLOBm91.woff +0 -0
- colloq/_app/web/dist/assets/KaTeX_Main-Italic-NWA7e6Wa.woff2 +0 -0
- colloq/_app/web/dist/assets/KaTeX_Main-Regular-B22Nviop.woff2 +0 -0
- colloq/_app/web/dist/assets/KaTeX_Main-Regular-Dr94JaBh.woff +0 -0
- colloq/_app/web/dist/assets/KaTeX_Main-Regular-ypZvNtVU.ttf +0 -0
- colloq/_app/web/dist/assets/KaTeX_Math-BoldItalic-B3XSjfu4.ttf +0 -0
- colloq/_app/web/dist/assets/KaTeX_Math-BoldItalic-CZnvNsCZ.woff2 +0 -0
- colloq/_app/web/dist/assets/KaTeX_Math-BoldItalic-iY-2wyZ7.woff +0 -0
- colloq/_app/web/dist/assets/KaTeX_Math-Italic-DA0__PXp.woff +0 -0
- colloq/_app/web/dist/assets/KaTeX_Math-Italic-flOr_0UB.ttf +0 -0
- colloq/_app/web/dist/assets/KaTeX_Math-Italic-t53AETM-.woff2 +0 -0
- colloq/_app/web/dist/assets/KaTeX_SansSerif-Bold-CFMepnvq.ttf +0 -0
- colloq/_app/web/dist/assets/KaTeX_SansSerif-Bold-D1sUS0GD.woff2 +0 -0
- colloq/_app/web/dist/assets/KaTeX_SansSerif-Bold-DbIhKOiC.woff +0 -0
- colloq/_app/web/dist/assets/KaTeX_SansSerif-Italic-C3H0VqGB.woff2 +0 -0
- colloq/_app/web/dist/assets/KaTeX_SansSerif-Italic-DN2j7dab.woff +0 -0
- colloq/_app/web/dist/assets/KaTeX_SansSerif-Italic-YYjJ1zSn.ttf +0 -0
- colloq/_app/web/dist/assets/KaTeX_SansSerif-Regular-BNo7hRIc.ttf +0 -0
- colloq/_app/web/dist/assets/KaTeX_SansSerif-Regular-CS6fqUqJ.woff +0 -0
- colloq/_app/web/dist/assets/KaTeX_SansSerif-Regular-DDBCnlJ7.woff2 +0 -0
- colloq/_app/web/dist/assets/KaTeX_Script-Regular-C5JkGWo-.ttf +0 -0
- colloq/_app/web/dist/assets/KaTeX_Script-Regular-D3wIWfF6.woff2 +0 -0
- colloq/_app/web/dist/assets/KaTeX_Script-Regular-D5yQViql.woff +0 -0
- colloq/_app/web/dist/assets/KaTeX_Size1-Regular-C195tn64.woff +0 -0
- colloq/_app/web/dist/assets/KaTeX_Size1-Regular-Dbsnue_I.ttf +0 -0
- colloq/_app/web/dist/assets/KaTeX_Size1-Regular-mCD8mA8B.woff2 +0 -0
- colloq/_app/web/dist/assets/KaTeX_Size2-Regular-B7gKUWhC.ttf +0 -0
- colloq/_app/web/dist/assets/KaTeX_Size2-Regular-Dy4dx90m.woff2 +0 -0
- colloq/_app/web/dist/assets/KaTeX_Size2-Regular-oD1tc_U0.woff +0 -0
- colloq/_app/web/dist/assets/KaTeX_Size3-Regular-CTq5MqoE.woff +0 -0
- colloq/_app/web/dist/assets/KaTeX_Size3-Regular-DgpXs0kz.ttf +0 -0
- colloq/_app/web/dist/assets/KaTeX_Size4-Regular-BF-4gkZK.woff +0 -0
- colloq/_app/web/dist/assets/KaTeX_Size4-Regular-DWFBv043.ttf +0 -0
- colloq/_app/web/dist/assets/KaTeX_Size4-Regular-Dl5lxZxV.woff2 +0 -0
- colloq/_app/web/dist/assets/KaTeX_Typewriter-Regular-C0xS9mPB.woff +0 -0
- colloq/_app/web/dist/assets/KaTeX_Typewriter-Regular-CO6r4hn1.woff2 +0 -0
- colloq/_app/web/dist/assets/KaTeX_Typewriter-Regular-D3Ib7_Hf.ttf +0 -0
- colloq/_app/web/dist/assets/PultWindow-B3cc8537.css +1 -0
- colloq/_app/web/dist/assets/PultWindow-B3cc8537.css.br +0 -0
- colloq/_app/web/dist/assets/PultWindow-B3cc8537.css.gz +0 -0
- colloq/_app/web/dist/assets/PultWindow-DPOUhSqt.js +8 -0
- colloq/_app/web/dist/assets/PultWindow-DPOUhSqt.js.br +0 -0
- colloq/_app/web/dist/assets/PultWindow-DPOUhSqt.js.gz +0 -0
- colloq/_app/web/dist/assets/ReaderScreen-CV_0VAvW.js +9 -0
- colloq/_app/web/dist/assets/ReaderScreen-CV_0VAvW.js.br +0 -0
- colloq/_app/web/dist/assets/ReaderScreen-CV_0VAvW.js.gz +0 -0
- colloq/_app/web/dist/assets/SessionScreen-BrcB6CLH.js +132 -0
- colloq/_app/web/dist/assets/SessionScreen-BrcB6CLH.js.br +0 -0
- colloq/_app/web/dist/assets/SessionScreen-BrcB6CLH.js.gz +0 -0
- colloq/_app/web/dist/assets/SessionScreen-Dek9dK3C.css +1 -0
- colloq/_app/web/dist/assets/SessionScreen-Dek9dK3C.css.br +0 -0
- colloq/_app/web/dist/assets/SessionScreen-Dek9dK3C.css.gz +0 -0
- colloq/_app/web/dist/assets/actions-DLPyolgo.js +1 -0
- colloq/_app/web/dist/assets/admin-en-BHmR7Co0.js +9 -0
- colloq/_app/web/dist/assets/admin-en-BHmR7Co0.js.br +0 -0
- colloq/_app/web/dist/assets/admin-en-BHmR7Co0.js.gz +0 -0
- colloq/_app/web/dist/assets/admin-ru-Dr6Z36Zi.js +11 -0
- colloq/_app/web/dist/assets/admin-ru-Dr6Z36Zi.js.br +0 -0
- colloq/_app/web/dist/assets/admin-ru-Dr6Z36Zi.js.gz +0 -0
- colloq/_app/web/dist/assets/codemirror-6LUh0q1l.js +32 -0
- colloq/_app/web/dist/assets/codemirror-6LUh0q1l.js.br +0 -0
- colloq/_app/web/dist/assets/codemirror-6LUh0q1l.js.gz +0 -0
- colloq/_app/web/dist/assets/competitions-en-zw57uAGL.js +5 -0
- colloq/_app/web/dist/assets/competitions-en-zw57uAGL.js.br +0 -0
- colloq/_app/web/dist/assets/competitions-en-zw57uAGL.js.gz +0 -0
- colloq/_app/web/dist/assets/competitions-ru-BBQUjAx0.js +5 -0
- colloq/_app/web/dist/assets/competitions-ru-BBQUjAx0.js.br +0 -0
- colloq/_app/web/dist/assets/competitions-ru-BBQUjAx0.js.gz +0 -0
- colloq/_app/web/dist/assets/editor-theme-CVYtpZDy.js +1 -0
- colloq/_app/web/dist/assets/editor-theme-CVYtpZDy.js.br +0 -0
- colloq/_app/web/dist/assets/editor-theme-CVYtpZDy.js.gz +0 -0
- colloq/_app/web/dist/assets/index-CwbYK31L.css +1 -0
- colloq/_app/web/dist/assets/index-CwbYK31L.css.br +0 -0
- colloq/_app/web/dist/assets/index-CwbYK31L.css.gz +0 -0
- colloq/_app/web/dist/assets/index-Di16xdmz.js +2 -0
- colloq/_app/web/dist/assets/index-Di16xdmz.js.br +0 -0
- colloq/_app/web/dist/assets/index-Di16xdmz.js.gz +0 -0
- colloq/_app/web/dist/assets/katex-CS_ezkZp.css +1 -0
- colloq/_app/web/dist/assets/katex-CS_ezkZp.css.br +0 -0
- colloq/_app/web/dist/assets/katex-CS_ezkZp.css.gz +0 -0
- colloq/_app/web/dist/assets/katex-DLorvT8M.js +257 -0
- colloq/_app/web/dist/assets/katex-DLorvT8M.js.br +0 -0
- colloq/_app/web/dist/assets/katex-DLorvT8M.js.gz +0 -0
- colloq/_app/web/dist/assets/pdf-DEp6sk-T.js +55 -0
- colloq/_app/web/dist/assets/pdf-DEp6sk-T.js.br +0 -0
- colloq/_app/web/dist/assets/pdf-DEp6sk-T.js.gz +0 -0
- colloq/_app/web/dist/assets/persistence.svelte-vcuCBcT5.js +1 -0
- colloq/_app/web/dist/assets/persistence.svelte-vcuCBcT5.js.br +0 -0
- colloq/_app/web/dist/assets/persistence.svelte-vcuCBcT5.js.gz +0 -0
- colloq/_app/web/dist/assets/reader-en-UCGE3U6V.js +3 -0
- colloq/_app/web/dist/assets/reader-en-UCGE3U6V.js.br +0 -0
- colloq/_app/web/dist/assets/reader-en-UCGE3U6V.js.gz +0 -0
- colloq/_app/web/dist/assets/reader-ru-CaiNj0K8.js +3 -0
- colloq/_app/web/dist/assets/reader-ru-CaiNj0K8.js.br +0 -0
- colloq/_app/web/dist/assets/reader-ru-CaiNj0K8.js.gz +0 -0
- colloq/_app/web/dist/assets/render-CjP3RuRT.js +155 -0
- colloq/_app/web/dist/assets/render-CjP3RuRT.js.br +0 -0
- colloq/_app/web/dist/assets/render-CjP3RuRT.js.gz +0 -0
- colloq/_app/web/dist/assets/render.svelte-B4_hAJmX.js +0 -0
- colloq/_app/web/dist/assets/render.svelte-B4_hAJmX.js.br +0 -0
- colloq/_app/web/dist/assets/render.svelte-B4_hAJmX.js.gz +0 -0
- colloq/_app/web/dist/assets/room-en-Bh8L6NcO.js +3 -0
- colloq/_app/web/dist/assets/room-en-Bh8L6NcO.js.br +0 -0
- colloq/_app/web/dist/assets/room-en-Bh8L6NcO.js.gz +0 -0
- colloq/_app/web/dist/assets/room-ru-Bar2GgS0.js +3 -0
- colloq/_app/web/dist/assets/room-ru-Bar2GgS0.js.br +0 -0
- colloq/_app/web/dist/assets/room-ru-Bar2GgS0.js.gz +0 -0
- colloq/_app/web/dist/assets/seminar-link-CRaZl9Ku.js +1 -0
- colloq/_app/web/dist/assets/seminar-link-CRaZl9Ku.js.br +0 -0
- colloq/_app/web/dist/assets/seminar-link-CRaZl9Ku.js.gz +0 -0
- colloq/_app/web/dist/assets/seminar-link-DoTugxxA.css +1 -0
- colloq/_app/web/dist/assets/seminar-link-DoTugxxA.css.br +0 -0
- colloq/_app/web/dist/assets/seminar-link-DoTugxxA.css.gz +0 -0
- colloq/_app/web/dist/assets/yjs-rjB3hdnL.js +6 -0
- colloq/_app/web/dist/assets/yjs-rjB3hdnL.js.br +0 -0
- colloq/_app/web/dist/assets/yjs-rjB3hdnL.js.gz +0 -0
- colloq/_app/web/dist/fonts/JetBrainsMono-OFL.txt +93 -0
- colloq/_app/web/dist/fonts/hse-sans-400.woff2 +0 -0
- colloq/_app/web/dist/fonts/hse-sans-600.woff2 +0 -0
- colloq/_app/web/dist/fonts/hse-sans-700.woff2 +0 -0
- colloq/_app/web/dist/fonts/hse-sans-900.woff2 +0 -0
- colloq/_app/web/dist/fonts/jetbrains-mono-cyrillic-ext.woff2 +0 -0
- colloq/_app/web/dist/fonts/jetbrains-mono-cyrillic.woff2 +0 -0
- colloq/_app/web/dist/fonts/jetbrains-mono-latin-ext.woff2 +0 -0
- colloq/_app/web/dist/fonts/jetbrains-mono-latin.woff2 +0 -0
- colloq/_app/web/dist/index.html +268 -0
- colloq/_app/web/dist/og/colloq.png +0 -0
- colloq/_app/web/dist/pdf/pdf.worker.min.mjs +29 -0
- colloq/_app/web/dist/pdf/pdf.worker.min.mjs.br +0 -0
- colloq/_app/web/dist/pdf/pdf.worker.min.mjs.gz +0 -0
- colloq/_app/web/dist/plotly/plotly.min.js +3620 -0
- colloq/_app/web/dist/plotly/plotly.min.js.br +0 -0
- colloq/_app/web/dist/plotly/plotly.min.js.gz +0 -0
- colloq/_version.py +5 -0
- colloq-0.2.0.dist-info/METADATA +124 -0
- colloq-0.2.0.dist-info/RECORD +224 -0
- colloq-0.2.0.dist-info/WHEEL +4 -0
- colloq-0.2.0.dist-info/entry_points.txt +2 -0
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
# Общее для скриптов эксплуатации. Не программа — его сорсят.
|
|
2
|
+
#
|
|
3
|
+
# . ./scripts/lib.sh из корня репозитория (host.sh, service.sh, vast.sh)
|
|
4
|
+
# . ./lib.sh из scripts/, назвав ENV_FILE заранее (dns.sh)
|
|
5
|
+
#
|
|
6
|
+
# Живут здесь две вещи, и обе — про один и тот же файл: где искать каталог
|
|
7
|
+
# состояния (COLLOQ_STATE_ROOT, см. ниже) и как прочитать из .env строку.
|
|
8
|
+
#
|
|
9
|
+
# Чтение строки было списано в трёх скриптах слово в слово, и все три несли
|
|
10
|
+
# одну и ту же ошибку — `tr -d ' \r'`, то есть «удалить каждый пробел, где бы
|
|
11
|
+
# он ни стоял». Имена карт в API vast пишутся с пробелом («RTX 4090»), и
|
|
12
|
+
# `VAST_GPU=RTX 4090` из .env превращался в «RTX4090», под который на рынке нет
|
|
13
|
+
# ни одного предложения; скрипт при этом советовал вписать в .env ровно то,
|
|
14
|
+
# что уже вписано. Название учреждения, путь с пробелом, имя ретранслятора —
|
|
15
|
+
# та же история.
|
|
16
|
+
#
|
|
17
|
+
# Правило теперь одно и записано один раз: обрезаются только края, кавычки по
|
|
18
|
+
# краям снимаются парой — как это делает сервер, читая PUBLIC_URL
|
|
19
|
+
# (server/src/config.ts). Внутренность значения не трогается вовсе.
|
|
20
|
+
|
|
21
|
+
# Корень СОСТОЯНИЯ: .env, расписка идущего занятия, .colloq.pid, data/.
|
|
22
|
+
#
|
|
23
|
+
# Корней два, и совпадают они не везде. Каталог ПРИЛОЖЕНИЯ — тот, что над
|
|
24
|
+
# scripts/: web/dist, kernel/, эти самые скрипты. У поставленного через pip
|
|
25
|
+
# colloq он лежит в <site-packages>/colloq/_app, доступен только на чтение и
|
|
26
|
+
# сносится целиком каждым `pip install -U`; состояние живёт отдельно, в
|
|
27
|
+
# ~/.colloq, и его адрес приезжает сюда переменной COLLOQ_HOME.
|
|
28
|
+
#
|
|
29
|
+
# Скрипты же считали корнем состояния себя — «cd $(dirname $0)/..» в шапке, —
|
|
30
|
+
# и у установленного colloq публикация «удавалась» вникуда: PUBLIC_URL уходил
|
|
31
|
+
# в .env каталога приложения, которого не читает никто, а `colloq link` смотрел
|
|
32
|
+
# в <home>/.env и продолжал говорить «наружу не выставлен».
|
|
33
|
+
#
|
|
34
|
+
# Без COLLOQ_HOME — ровно как раньше: текущий каталог, то есть тот самый
|
|
35
|
+
# каталог над scripts/, в который скрипт уже перешёл сам. В репозитории оба
|
|
36
|
+
# корня — это он и есть, поэтому там не сдвинулся ни один путь.
|
|
37
|
+
COLLOQ_STATE_ROOT="${COLLOQ_HOME:-.}"
|
|
38
|
+
|
|
39
|
+
# Файл настроек. Скрипты работают из корня репозитория, dns.sh — из scripts/,
|
|
40
|
+
# и путь у него другой; больше между ними разницы нет.
|
|
41
|
+
ENV_FILE="${ENV_FILE:-$COLLOQ_STATE_ROOT/.env}"
|
|
42
|
+
|
|
43
|
+
# read_env ИМЯ — значение строки `ИМЯ=…` из .env, пустая строка, если её нет.
|
|
44
|
+
# Берётся последняя: дописанное в конец файла главнее, и так же смотрит на
|
|
45
|
+
# него сервер.
|
|
46
|
+
read_env() {
|
|
47
|
+
local v
|
|
48
|
+
v="$(grep -E "^$1=" "$ENV_FILE" 2>/dev/null | tail -1 | cut -d= -f2- || true)"
|
|
49
|
+
# CRLF: .env, побывавший в Windows, иначе принёс бы возврат каретки внутрь
|
|
50
|
+
# имени контейнера и адреса.
|
|
51
|
+
v="${v%$'\r'}"
|
|
52
|
+
# Пробелы и табуляции по краям — и только по краям.
|
|
53
|
+
v="${v#"${v%%[![:space:]]*}"}"
|
|
54
|
+
v="${v%"${v##*[![:space:]]}"}"
|
|
55
|
+
# Кавычки снимаются только парой: одиночная кавычка внутри значения — это
|
|
56
|
+
# часть значения, а не половина обёртки.
|
|
57
|
+
case "$v" in
|
|
58
|
+
'"'*'"') v="${v#\"}"; v="${v%\"}" ;;
|
|
59
|
+
"'"*"'") v="${v#\'}"; v="${v%\'}" ;;
|
|
60
|
+
esac
|
|
61
|
+
printf '%s' "$v"
|
|
62
|
+
}
|
|
@@ -0,0 +1,338 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
#
|
|
3
|
+
# Развернуть снятую копию — пара к `make backup`.
|
|
4
|
+
#
|
|
5
|
+
# scripts/restore.sh самую свежую пару из backups/
|
|
6
|
+
# scripts/restore.sh backups/colloq-20260905-120000.db
|
|
7
|
+
# NAME=demo scripts/restore.sh самую свежую пару среды demo
|
|
8
|
+
#
|
|
9
|
+
# Про NAME. Сред бывает несколько — по арендованной машине на каждую, — и копии
|
|
10
|
+
# у них разложены по подкаталогам: backups/demo/, backups/hse/. Без NAME
|
|
11
|
+
# смотрим в корень backups/: это копии здешнего инстанса, у него имени нет.
|
|
12
|
+
# Именно поэтому «самая свежая» ищется в одном каталоге, а не во всех сразу:
|
|
13
|
+
# развернуть базу чужого семинара — это чужие тетради, чужие преподаватели и
|
|
14
|
+
# ссылки, ведущие в чужие файлы, причём молча.
|
|
15
|
+
#
|
|
16
|
+
# Зачем это отдельной командой. `make backup` снимает базу и архив с файлами
|
|
17
|
+
# семинаров, а обратная дорога до сих пор описывалась словами «положите два
|
|
18
|
+
# файла на место». Мест на самом деле три, и одно из них умеет тихо испортить
|
|
19
|
+
# базу: рядом с colloq.db в режиме WAL лежат colloq.db-wal и colloq.db-shm, и
|
|
20
|
+
# если подложить базу из копии, оставив старый журнал, sqlite накатит на неё
|
|
21
|
+
# чужие страницы. Поэтому журнал уезжает вместе с той базой, которую он
|
|
22
|
+
# описывает, а не выбрасывается и не остаётся.
|
|
23
|
+
#
|
|
24
|
+
# Что переживает пересоздание машины и лежит в копии:
|
|
25
|
+
#
|
|
26
|
+
# colloq.db семинары, преподаватели, история версий, настройки оракула
|
|
27
|
+
# workspace/ файлы семинаров — то, что загрузили и создали ячейки
|
|
28
|
+
# data/session-secret ключ подписи: без него все выданные ссылки и куки мертвы
|
|
29
|
+
# data/setup-token токен установки — вход в панель, когда ссылка потеряна
|
|
30
|
+
# kernel/environments/*.txt списки пакетов, в том числе заведённые из панели
|
|
31
|
+
# прямо на машине: их больше негде взять, а образ по ним
|
|
32
|
+
# пересобирается одной командой
|
|
33
|
+
#
|
|
34
|
+
# Чего в копии нет и почему: собранные образы окружений (их дешевле пересобрать
|
|
35
|
+
# одной командой, чем возить десятки гигабайт: make env-build NAME=…) и .env
|
|
36
|
+
# (он едет на новую машину сам, вместе с репозиторием, — см. scripts/vast.sh).
|
|
37
|
+
set -euo pipefail
|
|
38
|
+
SCRIPT_PATH="$(cd "$(dirname "$0")" && pwd)/$(basename "$0")"
|
|
39
|
+
|
|
40
|
+
cd "$(dirname "$0")/.."
|
|
41
|
+
|
|
42
|
+
# Portable cluster recovery is explicit; a legacy archive is never silently
|
|
43
|
+
# overlaid onto a PVC. Validate before stopping writers or moving any data.
|
|
44
|
+
if [ "${1:-}" = --archive ]; then
|
|
45
|
+
STATE="${COLLOQ_STATE_DIR:-/var/lib/colloq}"
|
|
46
|
+
if ! python3 scripts/state-lock.py held --state "$STATE"; then
|
|
47
|
+
exec python3 scripts/state-lock.py run --state "$STATE" -- bash "$SCRIPT_PATH" "$@"
|
|
48
|
+
fi
|
|
49
|
+
shift
|
|
50
|
+
ARCHIVE="${1:?archive path required}"; shift
|
|
51
|
+
STATE="${COLLOQ_STATE_DIR:-/var/lib/colloq}"
|
|
52
|
+
RELEASE="${RELEASE:-$STATE/releases/current.json}"
|
|
53
|
+
extra=()
|
|
54
|
+
while [ "$#" -gt 0 ]; do
|
|
55
|
+
case "$1" in
|
|
56
|
+
--release) RELEASE="${2:?release required}"; shift 2;;
|
|
57
|
+
--replace) extra+=(--replace); shift;;
|
|
58
|
+
--recover) extra+=(--recover); shift;;
|
|
59
|
+
*) echo "Unknown restore argument: $1" >&2; exit 1;;
|
|
60
|
+
esac
|
|
61
|
+
done
|
|
62
|
+
[ -f "$RELEASE" ] || { echo 'Select the matching RELEASE before restoring.' >&2; exit 1; }
|
|
63
|
+
python3 scripts/runtime-backup.py validate --archive "$ARCHIVE" --name "${NAME:-}" --release "$RELEASE"
|
|
64
|
+
mkdir -p "$STATE"
|
|
65
|
+
bash scripts/cluster.sh stop
|
|
66
|
+
python3 scripts/runtime-backup.py restore --root "$STATE" --release "$RELEASE" --archive "$ARCHIVE" --name "${NAME:-}" --defer-finalize "${extra[@]}"
|
|
67
|
+
# A restored older backup may deliberately contain previously retired IDs.
|
|
68
|
+
# Keep the durable marker until those old reservations are removed, with
|
|
69
|
+
# every writer still stopped and the same operation lock held throughout.
|
|
70
|
+
bash scripts/cluster.sh restore-services
|
|
71
|
+
python3 scripts/runtime-backup.py finalize --root "$STATE" --release "$RELEASE" --archive "$ARCHIVE" --name "${NAME:-}"
|
|
72
|
+
# Ownership was set on the validated stage before the durable marker cleared.
|
|
73
|
+
echo 'Restore completed with writers stopped. Run cluster.sh prepare --release, then cluster.sh start.'
|
|
74
|
+
exit 0
|
|
75
|
+
fi
|
|
76
|
+
if [ -f "${COLLOQ_STATE_DIR:-/var/lib/colloq}/releases/current.json" ]; then
|
|
77
|
+
echo 'Cluster restore requires --archive PORTABLE.tar.gz --release RELEASE.json; legacy overlay is refused.' >&2
|
|
78
|
+
exit 1
|
|
79
|
+
fi
|
|
80
|
+
|
|
81
|
+
RED=$'\033[31m'; DIM=$'\033[2m'; BOLD=$'\033[1m'; OFF=$'\033[0m'
|
|
82
|
+
say() { printf '%s\n' "$*"; }
|
|
83
|
+
die() { printf '%s%s%s\n' "$RED" "$*" "$OFF" >&2; exit 1; }
|
|
84
|
+
|
|
85
|
+
# Корень СОСТОЯНИЯ — оттуда берутся data/, workspace/ и backups/.
|
|
86
|
+
#
|
|
87
|
+
# Пара к scripts/backup-local.sh, и по той же причине. Скрипт пришёл сюда из
|
|
88
|
+
# мира, где корень был один, и считал data/ с workspace/ от каталога над собой,
|
|
89
|
+
# то есть от каталога ПРИЛОЖЕНИЯ. У поставленного через pip colloq это
|
|
90
|
+
# site-packages: `colloq restore --legacy` распаковал бы копию занятия рядом с
|
|
91
|
+
# кодом — туда, куда не смотрит ни сервер, ни следующий запуск, — и стёр бы её
|
|
92
|
+
# первым же `pip install -U`. Адрес состояния приезжает переменной COLLOQ_HOME,
|
|
93
|
+
# разбор — в scripts/lib.sh · COLLOQ_STATE_ROOT.
|
|
94
|
+
#
|
|
95
|
+
# Каталог приложения при этом нужен и дальше: в нём лежат сами скрипты,
|
|
96
|
+
# docker-compose.yml и cluster.sh. Поэтому он запоминается, а не теряется.
|
|
97
|
+
. ./scripts/lib.sh
|
|
98
|
+
APP="$PWD"
|
|
99
|
+
STATE="$(cd "$COLLOQ_STATE_ROOT" 2>/dev/null && pwd || true)"
|
|
100
|
+
[ -n "$STATE" ] || die "no state directory \"${COLLOQ_STATE_ROOT}\" — check COLLOQ_HOME."
|
|
101
|
+
cd "$STATE"
|
|
102
|
+
|
|
103
|
+
# Каталог копий одной среды. Имя приезжает переменной окружения, как HOST у
|
|
104
|
+
# `make host`: так его передаёт Makefile, и так оно не мешает старому вызову с
|
|
105
|
+
# путями в аргументах. Проверяем те же знаки, что и vast.sh: имя уходит в путь,
|
|
106
|
+
# и «../» увело бы восстановление за пределы backups/.
|
|
107
|
+
ENV_NAME="${NAME:-}"
|
|
108
|
+
case "$ENV_NAME" in
|
|
109
|
+
'') : ;;
|
|
110
|
+
*[!A-Za-z0-9-]*|-*|*-) die "deployment name \"${ENV_NAME}\" is not valid: letters, digits and a hyphen inside." ;;
|
|
111
|
+
esac
|
|
112
|
+
BACKUP_DIR="backups${ENV_NAME:+/$ENV_NAME}"
|
|
113
|
+
|
|
114
|
+
DB=""
|
|
115
|
+
FILES=""
|
|
116
|
+
for arg in "$@"; do
|
|
117
|
+
case "$arg" in
|
|
118
|
+
*.db) DB="$arg" ;;
|
|
119
|
+
*.tar.gz) FILES="$arg" ;;
|
|
120
|
+
*) die "I do not understand \"${arg}\". Expected backups/colloq-<date>.db and/or backups/colloq-<date>-files.tar.gz" ;;
|
|
121
|
+
esac
|
|
122
|
+
done
|
|
123
|
+
|
|
124
|
+
if [ -z "$DB" ] && [ -z "$FILES" ]; then
|
|
125
|
+
DB="$(ls -1t "$BACKUP_DIR"/colloq-*.db 2>/dev/null | head -1 || true)"
|
|
126
|
+
if [ -z "$DB" ]; then
|
|
127
|
+
# Список сред печатается прямо в отказе: «копий нет» при полном backups/hse
|
|
128
|
+
# — это не отсутствие копии, а не то имя, и выяснять это на пустой машине
|
|
129
|
+
# посреди занятия незачем.
|
|
130
|
+
others="$(ls -1d backups/*/ 2>/dev/null | sed 's#backups/##;s#/##' | tr '\n' ' ' | sed 's/ *$//' || true)"
|
|
131
|
+
# Совет называется командой, которая есть на ЭТОЙ машине: у поставленного
|
|
132
|
+
# пакета Makefile нет, и «make backup» было бы вторым отказом подряд.
|
|
133
|
+
take="colloq backup"; [ "$STATE" = "$APP" ] && take="make backup"
|
|
134
|
+
die "there is not a single backup in $BACKUP_DIR/.
|
|
135
|
+
Take one on a running instance: $take${others:+
|
|
136
|
+
Backups of other deployments live in subdirectories: $others
|
|
137
|
+
Restore a deployment backup: make restore NAME=<name>}"
|
|
138
|
+
fi
|
|
139
|
+
fi
|
|
140
|
+
# Архив ищется по имени базы, а не по «самому свежему»: пара из базы одного дня
|
|
141
|
+
# и файлов другого — это семинар, у которого в тетради есть ссылка на файл,
|
|
142
|
+
# которого нет.
|
|
143
|
+
if [ -z "$FILES" ] && [ -n "$DB" ] && [ -f "${DB%.db}-files.tar.gz" ]; then
|
|
144
|
+
FILES="${DB%.db}-files.tar.gz"
|
|
145
|
+
fi
|
|
146
|
+
|
|
147
|
+
[ -z "$DB" ] || [ -f "$DB" ] || die "no file $DB"
|
|
148
|
+
[ -z "$FILES" ] || [ -f "$FILES" ] || die "no file $FILES"
|
|
149
|
+
|
|
150
|
+
say "${BOLD}1/3${OFF} checking there is somewhere to restore into"
|
|
151
|
+
|
|
152
|
+
# Под работающим сервером базу не подменяют. sqlite держит открытым тот файл,
|
|
153
|
+
# который открыл: старый inode останется живым до последнего закрытия, семинар
|
|
154
|
+
# продолжит писать в файл, которого уже нет на диске, а после перезапуска эта
|
|
155
|
+
# работа просто исчезнет. Причём на экране до самого перезапуска всё выглядит
|
|
156
|
+
# исправно — поэтому проверка здесь, а не в напутствии внизу.
|
|
157
|
+
# Читает .env общий read_env (scripts/lib.sh) — тот же, что у host.sh и
|
|
158
|
+
# service.sh: одна копия правила на все скрипты. Подключён он выше, вместе с
|
|
159
|
+
# корнем состояния: оттуда же берётся и путь к .env.
|
|
160
|
+
PORT="$(read_env PORT)"; PORT="${PORT:-3000}"
|
|
161
|
+
if command -v systemctl >/dev/null 2>&1 && systemctl is-active --quiet colloq 2>/dev/null; then
|
|
162
|
+
die "the colloq service is running — stop it first: make service-stop.
|
|
163
|
+
A stopped service is not yet an empty machine: restoring a backup over today's
|
|
164
|
+
work still has to be deliberate, see REPLACE=1 further down."
|
|
165
|
+
fi
|
|
166
|
+
# Спрашиваем из каталога ПРИЛОЖЕНИЯ: docker-compose.yml лежит там, а мы стоим
|
|
167
|
+
# в состоянии. У поставленного пакета compose нет вовсе — вопрос останется без
|
|
168
|
+
# ответа, и это верный ответ: контейнером там никто не поднимается.
|
|
169
|
+
if (cd "$APP" && docker compose ps --status running --services 2>/dev/null) | grep -qx app; then
|
|
170
|
+
die "app is running in docker — stop it first: make down"
|
|
171
|
+
fi
|
|
172
|
+
if [ -f .colloq.pid ] && kill -0 "$(cat .colloq.pid 2>/dev/null)" 2>/dev/null; then
|
|
173
|
+
die "a class is running on this machine — first: colloq stop"
|
|
174
|
+
fi
|
|
175
|
+
if curl -sf -o /dev/null --max-time 3 "http://localhost:$PORT/api/health" 2>/dev/null; then
|
|
176
|
+
die "something answers on localhost:$PORT — that is a second Colloq.
|
|
177
|
+
Stop it (make down · make stop) and try again."
|
|
178
|
+
fi
|
|
179
|
+
|
|
180
|
+
# Поверх непустой машины — только по просьбе.
|
|
181
|
+
#
|
|
182
|
+
# Разворачивание необратимо ровно наполовину, и это худший из вариантов: база
|
|
183
|
+
# откладывается в colloq.db.replaced-<штамп> (о котором потом никто не
|
|
184
|
+
# вспомнит), а архив ложится на workspace/ поверх, перезаписывая одноимённые
|
|
185
|
+
# файлы без всякой копии. Поэтому «здесь уже что-то есть» — это вопрос, а не
|
|
186
|
+
# повод действовать: скрипт зовут и руками («откатить на вчера»), и из
|
|
187
|
+
# scripts/vast.sh, где повод бывает случайным.
|
|
188
|
+
#
|
|
189
|
+
# Спрашиваем, только когда есть у кого: на той стороне ssh терминала нет, на
|
|
190
|
+
# stdin висит heredoc — и `read` съел бы остаток скрипта. Без терминала нужен
|
|
191
|
+
# REPLACE=1, названный вслух.
|
|
192
|
+
if [ -n "$DB" ] && [ -s data/colloq.db ]; then
|
|
193
|
+
if [ "${REPLACE:-}" = 1 ]; then
|
|
194
|
+
say "${DIM} a database is already here — restoring over it (REPLACE=1)${OFF}"
|
|
195
|
+
elif [ -t 0 ]; then
|
|
196
|
+
say "${RED}There is already a data/colloq.db here${OFF} — classes, teachers, version history."
|
|
197
|
+
say "${DIM}It will be set aside as data/colloq.db.replaced-<stamp>, and the archive will${OFF}"
|
|
198
|
+
say "${DIM}land on workspace/ — same-named files are overwritten with no backup.${OFF}"
|
|
199
|
+
printf '%srestore the backup over it? [y/N] %s' "$BOLD" "$OFF"
|
|
200
|
+
read -r answer
|
|
201
|
+
case "$answer" in y|Y|yes|YES|Yes) : ;; *) die "not restoring." ;; esac
|
|
202
|
+
else
|
|
203
|
+
die "there is already a data/colloq.db here, and no terminal to ask in.
|
|
204
|
+
This is not an empty machine: restoring a backup over it means setting the
|
|
205
|
+
current database aside as data/colloq.db.replaced-<stamp> and unpacking the
|
|
206
|
+
archive on top of workspace/.
|
|
207
|
+
If that is what you want: REPLACE=1 $0 $*"
|
|
208
|
+
fi
|
|
209
|
+
fi
|
|
210
|
+
|
|
211
|
+
mkdir -p data workspace
|
|
212
|
+
STAMP="$(date +%Y%m%d-%H%M%S)"
|
|
213
|
+
|
|
214
|
+
say "${BOLD}2/3${OFF} database"
|
|
215
|
+
if [ -n "$DB" ]; then
|
|
216
|
+
# Дешёвая проверка вместо доверия расширению: первые шестнадцать байт файла
|
|
217
|
+
# sqlite — это «SQLite format 3». Восстановить пустой файл, скачавшийся до
|
|
218
|
+
# половины, значит потерять и то, что было.
|
|
219
|
+
head -c 16 "$DB" | LC_ALL=C grep -qa 'SQLite format 3' \
|
|
220
|
+
|| die "$DB does not look like an sqlite database — the backup is broken or incomplete."
|
|
221
|
+
if command -v sqlite3 >/dev/null 2>&1; then
|
|
222
|
+
[ "$(sqlite3 "$DB" 'pragma quick_check')" = ok ] \
|
|
223
|
+
|| die "$DB does not pass the sqlite check. Take another backup."
|
|
224
|
+
fi
|
|
225
|
+
if [ -f data/colloq.db ]; then
|
|
226
|
+
# Прежняя база уезжает целиком со своим журналом. Не удаляется — «я нажал
|
|
227
|
+
# restore не той копией» должно быть поправимо; и не остаётся на месте —
|
|
228
|
+
# старый -wal, накаченный на новую базу, портит её молча.
|
|
229
|
+
mv data/colloq.db "data/colloq.db.replaced-$STAMP"
|
|
230
|
+
for j in wal shm; do
|
|
231
|
+
if [ -f "data/colloq.db-$j" ]; then
|
|
232
|
+
mv "data/colloq.db-$j" "data/colloq.db.replaced-$STAMP-$j"
|
|
233
|
+
fi
|
|
234
|
+
done
|
|
235
|
+
say "${DIM} the previous database is set aside as data/colloq.db.replaced-$STAMP${OFF}"
|
|
236
|
+
fi
|
|
237
|
+
cp "$DB" data/colloq.db
|
|
238
|
+
chmod 600 data/colloq.db
|
|
239
|
+
say " $DB → data/colloq.db"
|
|
240
|
+
else
|
|
241
|
+
say "${DIM} not touching the database — it was not in the arguments${OFF}"
|
|
242
|
+
fi
|
|
243
|
+
|
|
244
|
+
say "${BOLD}3/3${OFF} class files and keys"
|
|
245
|
+
if [ -n "$FILES" ]; then
|
|
246
|
+
# Разворачивается поверх, а не вместо: комнаты, которых в копии нет, остаются
|
|
247
|
+
# на месте. Забрать лишнее всегда можно, а вернуть стёртое — нет.
|
|
248
|
+
#
|
|
249
|
+
# -p обязателен: у data/session-secret права 0600, и без сохранения режима
|
|
250
|
+
# ключ подписи стал бы читаемым для всех, кто есть на машине.
|
|
251
|
+
tar -xzpf "$FILES"
|
|
252
|
+
# Куда легли списки окружений — зависит от того, разошлись ли корни: в
|
|
253
|
+
# репозитории это kernel/environments, у поставленного пакета — свой каталог
|
|
254
|
+
# рядом с .env. Ровно так их и клал scripts/backup-local.sh, и называть надо
|
|
255
|
+
# то же место, иначе человек пойдёт искать файлы не туда.
|
|
256
|
+
if [ "$STATE" = "$APP" ]; then lists=kernel/environments; else lists=environments; fi
|
|
257
|
+
say " $FILES → workspace/, data/, $lists/"
|
|
258
|
+
if [ -f data/session-secret ]; then
|
|
259
|
+
chmod 600 data/session-secret
|
|
260
|
+
say "${DIM} the signing key is in place — issued links and cookies survive the move${OFF}"
|
|
261
|
+
fi
|
|
262
|
+
if [ -f data/setup-token ]; then
|
|
263
|
+
chmod 600 data/setup-token
|
|
264
|
+
fi
|
|
265
|
+
else
|
|
266
|
+
say "${DIM} no file archive — only the database was restored.${OFF}"
|
|
267
|
+
say "${DIM} Notebooks and settings are in place, uploaded files are not.${OFF}"
|
|
268
|
+
fi
|
|
269
|
+
|
|
270
|
+
# Хозяин файлов — тот, от кого работает сервер, а не тот, кто восстанавливал.
|
|
271
|
+
#
|
|
272
|
+
# Под `make up` сервер в контейнере работает от `node` (uid 1000), а копию на
|
|
273
|
+
# новой машине разворачивает root: база и папки оставались root:root, и
|
|
274
|
+
# контейнер падал по кругу с «unable to open database file». Локально этого не
|
|
275
|
+
# видно вовсе — при `make run` сервер и есть тот, кто распаковал.
|
|
276
|
+
#
|
|
277
|
+
# А на выделенной машине сервер стоит службой и работает от root — там uid 1000
|
|
278
|
+
# у базы означал бы ровно обратную ошибку. Поэтому форму спрашиваем, а не
|
|
279
|
+
# угадываем: есть юнит — сервер root, нет — сервер в контейнере. И спрашиваем с
|
|
280
|
+
# оговоркой: на новой машине копию разворачивают ДО установки службы (иначе
|
|
281
|
+
# сервер откроет базу, которую мы собираемся подменить), и юнита там ещё нет —
|
|
282
|
+
# поэтому scripts/vast.sh говорит форму прямо, FORM=service.
|
|
283
|
+
#
|
|
284
|
+
# Что не зависит от формы: workspace/. В него пишет ядро комнаты, а оно всегда
|
|
285
|
+
# uid 1000 (kernel/Dockerfile, пользователь runner). Под службой сервер кладёт
|
|
286
|
+
# туда же свои файлы от root, поэтому каталогам ставится группа 1000 и бит
|
|
287
|
+
# setgid: всё новое внутри достаётся этой группе, а право писать ей даёт
|
|
288
|
+
# UMask=0002 из юнита. Без пары «setgid + umask» первая ячейка с open(…,'w')
|
|
289
|
+
# в свежей комнате падает PermissionError на зелёном экране.
|
|
290
|
+
#
|
|
291
|
+
# Тысяча здесь — умолчание, а не истина: группу ядру выдаёт useradd, и в
|
|
292
|
+
# окружении поверх чужой базы она может оказаться другой. Точный номер ставит
|
|
293
|
+
# scripts/service.sh, спросив его у самого образа; там же это и повторяется
|
|
294
|
+
# после каждой установки.
|
|
295
|
+
#
|
|
296
|
+
# Только когда мы root и только на этих двух каталогах: чужие права здесь не
|
|
297
|
+
# трогаются, а на macOS (там uid другой и всё и так своё) шаг пропускается.
|
|
298
|
+
FORM="${FORM:-}"
|
|
299
|
+
if [ -z "$FORM" ] && [ -f /etc/systemd/system/colloq.service ]; then FORM=service; fi
|
|
300
|
+
if [ "$(id -u)" = 0 ] && [ "$(uname -s)" = Linux ]; then
|
|
301
|
+
if [ "$FORM" = service ]; then
|
|
302
|
+
chown -R root:root data
|
|
303
|
+
# Группа, а не владелец. Владельца у файлов внутри workspace/ менять нельзя:
|
|
304
|
+
# то, что распаковалось от uid 1000, ядро писало как хозяин, и став
|
|
305
|
+
# root:1000 с правами 0644 оно стало бы для ядра нечитаемым на запись.
|
|
306
|
+
# Группа же 1000 плюс setgid на каталогах дают обеим сторонам заводить и
|
|
307
|
+
# удалять файлы внутри, не трогая уже лежащие.
|
|
308
|
+
chgrp -R 1000 workspace
|
|
309
|
+
find workspace -type d -exec chmod 2775 {} + 2>/dev/null || true
|
|
310
|
+
say "${DIM} data/ — root's (the server is a service), workspace/ — group 1000 (the kernel)${OFF}"
|
|
311
|
+
else
|
|
312
|
+
chown -R 1000:1000 data workspace
|
|
313
|
+
say "${DIM} data/ and workspace/ — uid 1000: that is who the server is in the container${OFF}"
|
|
314
|
+
fi
|
|
315
|
+
fi
|
|
316
|
+
|
|
317
|
+
printf '\n'
|
|
318
|
+
say "${BOLD}done${OFF}"
|
|
319
|
+
# Куда идти дальше — словом, которое есть у того, кто это читает.
|
|
320
|
+
#
|
|
321
|
+
# Прежнее напутствие звало `make up / make run / make service-install` и
|
|
322
|
+
# `make env-build NAME=…`. У поставленного через pip colloq make нет вовсе
|
|
323
|
+
# (в колесо едут приложение и scripts/, Makefile не едет — scripts/pack.mts ·
|
|
324
|
+
# SCRIPTS), и обе строки врали ровно тому, кто только что развернул копию на
|
|
325
|
+
# новой машине и ищет, чем её запустить. У пакета это `colloq start`: образ
|
|
326
|
+
# окружения он собирает сам, первым запуском (cli/src/commands/env.ts · env
|
|
327
|
+
# use). Рядом с исходниками — make: там же живёт и цель service-install
|
|
328
|
+
# выделенной машины.
|
|
329
|
+
if [ "$STATE" = "$APP" ]; then
|
|
330
|
+
say "${DIM}Start a class: make run (make dev for development)${OFF}"
|
|
331
|
+
say "${DIM}On a dedicated machine the class is held by a service: make service-install.${OFF}"
|
|
332
|
+
else
|
|
333
|
+
say "${DIM}Start a class: colloq start${OFF}"
|
|
334
|
+
fi
|
|
335
|
+
say "${DIM}Kernel environments are not restored here —${OFF}"
|
|
336
|
+
say "${DIM}the image is built on the next start of a class.${OFF}"
|
|
337
|
+
say "${DIM}Pinned competition images must be restored separately with their exact image IDs (see backup/restore docs).${OFF}"
|
|
338
|
+
say "${DIM}The Oracle key, RELAY_* and PUBLIC_URL live in .env, not in the backup.${OFF}"
|