Centralize Tensamin packages modules and release automation
Some checks failed
action.yml / Centralize Tensamin packages modules and release automation (push) Failing after 0s
Canary release / release (push) Failing after 21s

This commit is contained in:
Alois 2026-10-04 19:19:56 +02:00
commit 123205c97d
Signed by: alois
SSH key fingerprint: SHA256:GBzT2DXvAuGV9XIV5W3WrzVpjU54FThmxHXdbz95J24
28 changed files with 32292 additions and 10 deletions

133
lib/prepare-source.py Normal file
View file

@ -0,0 +1,133 @@
"""Make every Rust consumer use the same local MTP and type maps."""
import os
import pathlib
import re
import shutil
import sys
import tomllib
project, source, mtp, maps, iota, destination = sys.argv[1:]
root = pathlib.Path(destination)
shutil.copytree(source, root, symlinks=True)
root.chmod(root.stat().st_mode | 0o200)
if project != "mtp":
shutil.copytree(mtp, root / ".mtp", symlinks=True)
mtp_root = root if project == "mtp" else root / ".mtp"
crates = {}
for manifest in mtp_root.rglob("Cargo.toml"):
data = tomllib.loads(manifest.read_text())
if "name" in data.get("package", {}):
crates[data["package"]["name"]] = manifest.parent
if project == "omega":
shutil.copytree(pathlib.Path(iota) / "iota-identity", root / ".identity")
for path in [root, *root.rglob("*")]:
if not path.is_symlink():
path.chmod(path.stat().st_mode | 0o200)
if project == "omega":
manifest = root / "Cargo.toml"
manifest.write_text(manifest.read_text().replace('../iota/iota-identity', './.identity'))
for manifest in root.rglob("Cargo.toml"):
text = manifest.read_text()
# Preserve feature selections while replacing every independent git revision.
def local_dependency(match, manifest=manifest):
name, attributes = match.groups()
path = pathlib.Path(os.path.relpath(crates[name], manifest.parent))
attributes = re.sub(r'git\s*=\s*"[^"]+"\s*,?\s*', '', attributes)
attributes = re.sub(r'(rev|branch|tag)\s*=\s*"[^"]+"\s*,?\s*', '', attributes)
return f'{name} = {{ path = "{path}", {attributes}'
text = re.sub(r'(mtp(?:-[\w-]+)?)\s*=\s*\{([^}]*git\s*=\s*"[^"]*[Mm]ethanium/mtp[^}]*)(?=\})', local_dependency, text)
if manifest == root / "Cargo.toml" and project == "iota":
text = text.replace('exclude = [', 'exclude = [".mtp", ')
manifest.write_text(text)
maps_dir = root / "mtp-type-maps"
if maps_dir.is_symlink() or maps_dir.is_file():
maps_dir.unlink()
elif maps_dir.exists():
shutil.rmtree(maps_dir)
shutil.copytree(maps, maps_dir)
# Cargo reads only configuration from the invocation directory and its parents.
config = root / ".cargo" / "config.toml"
if config.exists():
config.unlink()
if project == "iota":
# Keep native executables usable before a system installation, without a
# shell launcher or store paths in the portable release.
paths = root / "iota-paths/src/lib.rs"
text = paths.read_text()
text = text.replace(
'return Err(PathError::MissingRequiredOverride("IOTA_SOCKET"));',
'''let home = absolute_env("HOME")?
.ok_or(PathError::MissingPlatformDirectory("home directory"))?;
let runtime = absolute_env("XDG_RUNTIME_DIR")?
.unwrap_or(xdg_or_home("XDG_STATE_HOME", &home, ".local/state")?);
return Ok(IpcEndpoint::UnixSocket(runtime.join("iota/iota.sock")));''',
)
for program in ["daemon", "updater"]:
text = text.replace(
f'.unwrap_or_else(|| install_root().join("current/bin/iota-{program}"))',
f'''.unwrap_or_else(|| {{
let sibling = env::current_exe().ok()
.and_then(|path| path.parent().map(|parent| parent.join("iota-{program}")));
sibling.filter(|path| path.is_file())
.unwrap_or_else(|| install_root().join("current/bin/iota-{program}"))
}})''',
)
text = text.replace(
'.unwrap_or(defaults.asset_dir);',
'''.unwrap_or_else(|| {
env::current_exe().ok()
.and_then(|path| path.parent()?.parent().map(|parent| parent.join("share/iota/web")))
.filter(|path| path.is_dir())
.unwrap_or(defaults.asset_dir)
});''',
)
paths.write_text(text)
daemon = root / "iota-daemon/src/main.rs"
daemon.write_text(daemon.read_text().replace(
' if !iota_terms::consent::load(&paths.state_dir).has_all_required() {',
''' if let Err(error) = paths.prepare_writable_directories() {
eprintln!("Cannot prepare Iota directories: {error}");
return ExitCode::FAILURE;
}
if !iota_terms::consent::load(&paths.state_dir).has_all_required() {''',
1,
))
# Ship and install every pinned static asset through the existing ZIP
# contract, so the validator and installer agree about the payload.
assets = sorted(path.relative_to(root).as_posix() for path in (root / "static/web").rglob("*") if path.is_file())
contract = root / "iota-installer/bundle-files.txt"
contract.write_text(contract.read_text().rstrip() + "\n" + "\n".join(assets) + "\n")
installer = root / "iota-installer/src/lib.rs"
text = installer.read_text().replace(
' for unit in [',
''' for name in REQUIRED.lines().filter(|name| name.starts_with("static/web/")) {
install(
&staging.path().join(name),
&format!("/usr/local/share/iota/web/{}", &name["static/web/".len()..]),
"0644",
)?;
}
for unit in [''',
1,
)
installer.write_text(text)
# Drop git identities for the crates now supplied through local paths. Cargo
# updates the dependency graph during update-all, never inside a sandboxed build.
lock = root / "Cargo.lock"
if lock.exists():
text = lock.read_text()
text = re.sub(r'(\[\[package\]\]\nname = "mtp[^\n]*\n.*?)(?=\n\[\[package\]\]|\Z)',
lambda m: re.sub(r'^source = .*\n|^checksum = .*\n', '', m[0], flags=re.MULTILINE), text, flags=re.DOTALL)
text = re.sub(r'(mtp[\w-]* [\d.]+) \(git\+[^)]+\)', r'\1', text)
lock.write_text(text)