feat(deploy): reliability API routes, atomic releases, version single-source
This commit is contained in:
@@ -0,0 +1,124 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Build helpers shared by Mark VIII deploy scripts.
|
||||
|
||||
stamp_version() stamps release metadata into BUILD COPIES ONLY: callers
|
||||
always pass a staging/build directory, never the source tree, so the repo
|
||||
stays clean while every deployed artifact reports the same VERSION.
|
||||
"""
|
||||
|
||||
import json
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
|
||||
VERSION_RE = re.compile(r'^[0-9][A-Za-z0-9._-]{0,31}$')
|
||||
SERVER_VERSION_LINE = "SERVER_VERSION = '%s'\n"
|
||||
|
||||
|
||||
def _stamp_manifest(path, version):
|
||||
try:
|
||||
with open(path, encoding='utf-8') as f:
|
||||
data = json.load(f)
|
||||
except (OSError, ValueError):
|
||||
return False
|
||||
if not isinstance(data, dict):
|
||||
return False
|
||||
data['version'] = version
|
||||
with open(path, 'w', encoding='ascii') as f:
|
||||
json.dump(data, f, indent=2)
|
||||
f.write('\n')
|
||||
return True
|
||||
|
||||
|
||||
def _stamp_payload_sh(path, version):
|
||||
try:
|
||||
with open(path, encoding='utf-8') as f:
|
||||
lines = f.readlines()
|
||||
except OSError:
|
||||
return False
|
||||
out = []
|
||||
replaced = False
|
||||
for line in lines:
|
||||
m = None if replaced \
|
||||
else re.match(r'^(\s*#\s*[Vv]ersion:).*$', line)
|
||||
if m:
|
||||
out.append(m.group(1) + ' ' + version + '\n')
|
||||
replaced = True
|
||||
else:
|
||||
out.append(line)
|
||||
if not replaced:
|
||||
insert = 1 if lines and lines[0].startswith('#!') else 0
|
||||
out.insert(insert, '# Version: %s\n' % version)
|
||||
with open(path, 'w', encoding='utf-8') as f:
|
||||
f.writelines(out)
|
||||
return True
|
||||
|
||||
|
||||
def _server_insert_index(lines):
|
||||
"""Index just past any shebang/comments/blanks and module docstring."""
|
||||
i = 0
|
||||
n = len(lines)
|
||||
if i < n and lines[i].startswith('#!'):
|
||||
i += 1
|
||||
while i < n and (lines[i].strip().startswith('#')
|
||||
or not lines[i].strip()):
|
||||
i += 1
|
||||
if i < n:
|
||||
stripped = lines[i].lstrip()
|
||||
quote = stripped[:3]
|
||||
if quote in ('"""', "'''"):
|
||||
closed_here = quote in stripped[3:]
|
||||
i += 1
|
||||
if not closed_here:
|
||||
while i < n and quote not in lines[i]:
|
||||
i += 1
|
||||
i += 1
|
||||
return min(i, len(lines))
|
||||
|
||||
|
||||
def _stamp_server_py(path, version):
|
||||
try:
|
||||
with open(path, encoding='utf-8') as f:
|
||||
lines = f.readlines()
|
||||
except OSError:
|
||||
return False
|
||||
lines = [l for l in lines if not l.startswith('SERVER_VERSION')]
|
||||
idx = _server_insert_index(lines)
|
||||
lines.insert(idx, SERVER_VERSION_LINE % version)
|
||||
with open(path, 'w', encoding='utf-8') as f:
|
||||
f.writelines(lines)
|
||||
return True
|
||||
|
||||
|
||||
def stamp_version(build_dir, version):
|
||||
"""Stamp <version> into build copies found under build_dir.
|
||||
|
||||
Updates every ``_hak5_manifest.json`` (version field), ``payload.sh``
|
||||
(header Version line) and ``server.py`` (injected SERVER_VERSION
|
||||
constant near the top). Idempotent: re-running never duplicates the
|
||||
injected constant or header. Returns the list of stamped paths."""
|
||||
if not VERSION_RE.match(str(version)):
|
||||
raise ValueError('invalid version string: %r' % (version,))
|
||||
stamped = []
|
||||
for root, dirs, files in os.walk(build_dir):
|
||||
for fname in ('_hak5_manifest.json', 'payload.sh', 'server.py'):
|
||||
if fname in files:
|
||||
path = os.path.join(root, fname)
|
||||
if fname == '_hak5_manifest.json':
|
||||
ok = _stamp_manifest(path, version)
|
||||
elif fname == 'payload.sh':
|
||||
ok = _stamp_payload_sh(path, version)
|
||||
else:
|
||||
ok = _stamp_server_py(path, version)
|
||||
if ok:
|
||||
stamped.append(path)
|
||||
return sorted(stamped)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
if len(sys.argv) != 3:
|
||||
print('usage: build_common.py <build_dir> <version>',
|
||||
file=sys.stderr)
|
||||
sys.exit(2)
|
||||
for path in stamp_version(sys.argv[1], sys.argv[2]):
|
||||
print('stamped: %s' % path)
|
||||
Reference in New Issue
Block a user