133 lines
5.5 KiB
Python
133 lines
5.5 KiB
Python
"""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)
|