import pathlib,json,hashlib,subprocess,sqlite3,datetime,shutil base=pathlib.Path('/www/dk_project/dk_app/trilium') release=pathlib.Path('/tmp/trilium-korean-release') for name,expected in json.loads((release/'source-hashes.json').read_text()).items(): actual=hashlib.sha256((base/name).read_bytes()).hexdigest() if actual!=expected: raise RuntimeError('Source changed: '+name) stamp=datetime.datetime.now().strftime('%Y%m%d-%H%M%S') backup=base/'backups'/('before-korean-apply-'+stamp) backup.mkdir(mode=0o700,parents=True) sqlite3.connect(f'file:{base}/data/document.db?mode=ro',uri=True).backup(sqlite3.connect(backup/'document.db')) subprocess.run(['tar','-czf',str(backup/'patches.tar.gz'),'-C',str(base),'patched','i18n_ko','docker-compose.yml'],check=True) for src,dest in [('translation.json','i18n_ko/translation.json'),('layout_commons.js','patched/layout_commons.js'),('ckeditor-ko.js','patched/ckeditor-ko.js'),('main.cjs','patched/main.cjs')]: (base/dest).write_bytes((release/src).read_bytes()) plan=base/'data/korean-notes-pending.json' plan.write_bytes((release/'demo-migration.json').read_bytes()) stat=(base/'data/document.db').stat() import os os.chown(plan,stat.st_uid,stat.st_gid) os.chmod(plan,0o600) compose=base/'docker-compose.yml' text=compose.read_text() old=' - ./patched/layout_commons.js:/usr/src/app/public/src/layout_commons.js:ro' if old not in text: raise RuntimeError('Compose layout mount not found') new=' - ./patched/ckeditor-ko.js:/usr/src/app/public/src/ckeditor-ko.js:ro' if new not in text:text=text.replace(old,old+'\n'+new) compose.write_text(text) subprocess.run(['docker','compose','-f',str(compose),'config','--quiet'],check=True) subprocess.run(['docker','compose','-f',str(compose),'up','-d','--no-deps','trilium'],check=True) print(json.dumps({'backup':str(backup),'status':'deployed'}))