82 lines
4 KiB
Python
82 lines
4 KiB
Python
#!/usr/bin/env python3
|
|
"""Build the portable Linux amd64 TUI bundle and retain dependency licences."""
|
|
import gzip
|
|
import json
|
|
import os
|
|
import re
|
|
import subprocess
|
|
import sys
|
|
import tempfile
|
|
import urllib.request
|
|
from pathlib import Path
|
|
|
|
REPO = Path(__file__).resolve().parents[1]
|
|
sys.path.insert(0, str(REPO / 'lib'))
|
|
from launcher import digest, source_hash
|
|
|
|
|
|
def json_stream(text):
|
|
decoder = json.JSONDecoder()
|
|
while text.strip():
|
|
item, end = decoder.raw_decode(text.lstrip())
|
|
yield item
|
|
text = text.lstrip()[end:]
|
|
|
|
|
|
def build():
|
|
version = (REPO / 'VERSION').read_text().strip()
|
|
if not re.fullmatch(r'\d+\.\d+\.\d+', version):
|
|
raise ValueError('VERSION must contain a numeric release version.')
|
|
env = dict(os.environ, CGO_ENABLED='0', GOOS='linux', GOARCH='amd64', GOAMD64='v1',
|
|
GOEXPERIMENT='', GOFLAGS='-mod=readonly', GOTOOLCHAIN='local')
|
|
output = REPO / 'assets/bin'
|
|
output.mkdir(parents=True, exist_ok=True)
|
|
with tempfile.TemporaryDirectory(prefix='fiw-dots-release-') as temp:
|
|
executable = Path(temp) / 'fiw-dots'
|
|
subprocess.run(['go', 'build', '-trimpath', '-buildvcs=false',
|
|
'-ldflags=-s -w -X main.tuiVersion=' + version,
|
|
'-o', str(executable), './cmd/dots'], cwd=REPO, env=env, check=True)
|
|
data = executable.read_bytes()
|
|
archive = gzip.compress(data, mtime=0)
|
|
name = 'fiw-dots-linux-amd64.gz'
|
|
metadata = {'version': version, 'source_sha256': source_hash(),
|
|
'binaries': {'linux-amd64': {'file': name, 'sha256': digest(data),
|
|
'gzip_sha256': digest(archive), 'size': len(data)}}}
|
|
packages = subprocess.run(['go', 'list', '-deps', '-json', './cmd/dots'], cwd=REPO, env=env,
|
|
text=True, capture_output=True, check=True)
|
|
modules = {package['Module']['Path']: package['Module'] for package in json_stream(packages.stdout)
|
|
if package.get('Module') and not package['Module'].get('Main')}
|
|
notices = ['# Third-party licences for the bundled TUI\n']
|
|
for _, module in sorted(modules.items()):
|
|
directory = Path(module['Dir'])
|
|
licences = sorted(path for path in directory.iterdir() if path.is_file()
|
|
and path.name.lower().startswith(('license', 'copying', 'notice')))
|
|
if not licences:
|
|
raise RuntimeError('Missing licence notice for ' + module['Path'])
|
|
for path in licences:
|
|
notices += ['\n## ' + module['Path'] + ' ' + module['Version'] + ' / ' + path.name + '\n', path.read_text()]
|
|
goroot = subprocess.run(['go', 'env', 'GOROOT'], env=env, text=True, capture_output=True, check=True).stdout.strip()
|
|
license_path = Path(goroot) / 'LICENSE'
|
|
if license_path.is_file():
|
|
go_license = license_path.read_text()
|
|
else:
|
|
# Gentoo omits the upstream licence file from GOROOT. Obtain that
|
|
# exact toolchain's notice from the official Go source repository.
|
|
goversion = subprocess.run(['go', 'env', 'GOVERSION'], env=env, text=True, capture_output=True, check=True).stdout.strip()
|
|
match = re.match(r'go\d+\.\d+(?:\.\d+)?', goversion)
|
|
if not match:
|
|
raise RuntimeError('Cannot identify the Go toolchain licence source.')
|
|
url = 'https://raw.githubusercontent.com/golang/go/' + match.group() + '/LICENSE'
|
|
with urllib.request.urlopen(url, timeout=20) as response:
|
|
go_license = response.read().decode()
|
|
notices += ['\n## Go standard library and runtime\n', go_license]
|
|
(output / name).write_bytes(archive)
|
|
(output / 'tui.json').write_text(json.dumps(metadata, indent=2) + '\n')
|
|
(output / 'SHA256SUMS').write_text(digest(archive) + ' ' + name + '\n')
|
|
(output / 'LICENSES.txt').write_text('\n'.join(notices))
|
|
print('Built v' + version + ': ' + str(len(data)) + ' bytes; compressed ' + str(len(archive)) + ' bytes.')
|
|
print('Source and binary fingerprints: assets/bin/tui.json')
|
|
|
|
|
|
if __name__ == '__main__':
|
|
build()
|