mirror of
https://github.com/logos-co/logos-modules.git
synced 2026-08-31 12:01:08 +00:00
305 lines
9.6 KiB
Bash
Executable File
305 lines
9.6 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
set -euo pipefail
|
|
set -x
|
|
|
|
# package-modules.sh — Merge single-variant .lgx packages into multi-variant ones.
|
|
#
|
|
# Expected environment:
|
|
# LGX — path to the lgx binary
|
|
# ARTIFACTS_DIR — path to downloaded artifacts (default: "artifacts")
|
|
#
|
|
# Expected directory layout under ARTIFACTS_DIR:
|
|
# <variant>/<module>/<package>.lgx
|
|
#
|
|
# Each input .lgx is a single-variant package produced by nix-bundle-lgx.
|
|
# This script verifies that manifests match across variants (ignoring the "main"
|
|
# field which differs per platform), then uses the lgx tool to create a fresh
|
|
# multi-variant package from the extracted per-platform files.
|
|
#
|
|
# All metadata is extracted from the single-variant lgx manifests — no submodule
|
|
# checkout is required.
|
|
|
|
script_dir="$(cd -- "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
repo_dir="$(cd "$script_dir/.." && pwd)"
|
|
|
|
: "${LGX:?LGX env var must point to the lgx binary}"
|
|
: "${ARTIFACTS_DIR:=artifacts}"
|
|
|
|
output_dir="$repo_dir/output"
|
|
mkdir -p "$output_dir"
|
|
|
|
ALL_VARIANTS=("linux-amd64" "linux-arm64" "darwin-arm64")
|
|
|
|
if [[ ! -f "$repo_dir/.gitmodules" ]]; then
|
|
echo "No .gitmodules found in $repo_dir" >&2
|
|
exit 1
|
|
fi
|
|
|
|
modules=$(git config --file "$repo_dir/.gitmodules" --get-regexp path | awk '{print $2}')
|
|
|
|
if [[ -z "$modules" ]]; then
|
|
echo "No module paths found in .gitmodules" >&2
|
|
exit 1
|
|
fi
|
|
|
|
# Store module metadata for list.json generation
|
|
module_entries=()
|
|
|
|
for module in $modules; do
|
|
echo "=== Processing $module ==="
|
|
|
|
# Collect all single-variant lgx files for this module
|
|
declare -A variant_lgx_map=()
|
|
available_variants=()
|
|
|
|
for variant in "${ALL_VARIANTS[@]}"; do
|
|
variant_module_dir="$ARTIFACTS_DIR/${variant}/${module}"
|
|
if [[ -d "$variant_module_dir" ]]; then
|
|
lgx_file=$(find "$variant_module_dir" -maxdepth 1 -name '*.lgx' 2>/dev/null | head -n 1)
|
|
if [[ -n "$lgx_file" ]]; then
|
|
variant_lgx_map["$variant"]="$lgx_file"
|
|
available_variants+=("$variant")
|
|
fi
|
|
fi
|
|
done
|
|
|
|
if [[ ${#available_variants[@]} -eq 0 ]]; then
|
|
echo "No lgx artifacts found for $module, skipping."
|
|
continue
|
|
fi
|
|
|
|
echo "Available variants for $module: ${available_variants[*]}"
|
|
|
|
# Collect lgx file paths for verification
|
|
lgx_file_args=()
|
|
for variant in "${available_variants[@]}"; do
|
|
lgx_file_args+=("${variant_lgx_map[$variant]}")
|
|
done
|
|
|
|
# --- Verify manifests match across all single-variant lgx files (ignoring "main") ---
|
|
python3 - "${lgx_file_args[@]}" <<'PY'
|
|
import tarfile, json, sys
|
|
|
|
def read_manifest(lgx_path):
|
|
with tarfile.open(lgx_path, 'r:gz') as tar:
|
|
for member in tar.getmembers():
|
|
if member.name == 'manifest.json':
|
|
return json.loads(tar.extractfile(member).read())
|
|
return None
|
|
|
|
manifests = []
|
|
for path in sys.argv[1:]:
|
|
m = read_manifest(path)
|
|
if m is None:
|
|
print(f"ERROR: no manifest.json found in {path}", file=sys.stderr)
|
|
sys.exit(1)
|
|
manifests.append((path, m))
|
|
|
|
# Compare all manifests ignoring the "main" field (differs per platform, e.g. .dylib vs .so)
|
|
def manifest_without_main(m):
|
|
return {k: v for k, v in m.items() if k != "main"}
|
|
|
|
reference_path, reference = manifests[0]
|
|
ref_comparable = manifest_without_main(reference)
|
|
|
|
for path, m in manifests[1:]:
|
|
comparable = manifest_without_main(m)
|
|
if comparable != ref_comparable:
|
|
print(f"ERROR: manifest mismatch between {reference_path} and {path}", file=sys.stderr)
|
|
print(f" Reference: {json.dumps(ref_comparable, sort_keys=True)}", file=sys.stderr)
|
|
print(f" Mismatch: {json.dumps(comparable, sort_keys=True)}", file=sys.stderr)
|
|
sys.exit(1)
|
|
|
|
print(f"Manifests verified: all {len(manifests)} variant(s) match (ignoring main field).")
|
|
PY
|
|
|
|
# --- Extract metadata from the first single-variant lgx manifest ---
|
|
first_lgx="${variant_lgx_map[${available_variants[0]}]}"
|
|
|
|
manifest_json=$(python3 - "$first_lgx" <<'PY'
|
|
import tarfile, json, sys
|
|
with tarfile.open(sys.argv[1], 'r:gz') as tar:
|
|
for member in tar.getmembers():
|
|
if member.name == 'manifest.json':
|
|
print(tar.extractfile(member).read().decode())
|
|
break
|
|
PY
|
|
)
|
|
|
|
package_name=$(echo "$manifest_json" | python3 -c "import json, sys; print(json.load(sys.stdin).get('name', ''))")
|
|
|
|
if [[ -z "$package_name" ]]; then
|
|
# Fall back to lgx filename
|
|
package_name=$(basename "$first_lgx" .lgx)
|
|
fi
|
|
|
|
lgx_package_path="$output_dir/${package_name}.lgx"
|
|
|
|
# --- Create multi-variant lgx package using the lgx tool ---
|
|
|
|
rm -f "${package_name}.lgx"
|
|
"$LGX" create "$package_name"
|
|
mv "${package_name}.lgx" "$lgx_package_path"
|
|
|
|
# Patch manifest with metadata extracted from the single-variant lgx
|
|
echo "Updating package manifest with metadata..."
|
|
python3 - "$lgx_package_path" "$manifest_json" <<'PY'
|
|
import json, sys, tarfile, io
|
|
|
|
lgx_path = sys.argv[1]
|
|
metadata = json.loads(sys.argv[2])
|
|
|
|
with tarfile.open(lgx_path, 'r:gz') as tar:
|
|
members = []
|
|
for member in tar.getmembers():
|
|
if member.isfile():
|
|
members.append((member, tar.extractfile(member).read()))
|
|
else:
|
|
members.append((member, None))
|
|
|
|
patched = []
|
|
for member, data in members:
|
|
if member.name == 'manifest.json':
|
|
manifest = json.loads(data)
|
|
for key in ('name', 'version', 'description', 'author', 'type', 'category', 'dependencies', 'icon'):
|
|
if metadata.get(key):
|
|
manifest[key] = metadata[key]
|
|
data = json.dumps(manifest, indent=2).encode()
|
|
member.size = len(data)
|
|
patched.append((member, data))
|
|
|
|
with tarfile.open(lgx_path, 'w:gz', format=tarfile.GNU_FORMAT) as tar:
|
|
for member, data in patched:
|
|
if data is not None:
|
|
tar.addfile(member, io.BytesIO(data))
|
|
else:
|
|
tar.addfile(member)
|
|
PY
|
|
|
|
# Add each variant by extracting files from its single-variant lgx
|
|
for variant in "${available_variants[@]}"; do
|
|
lgx_file="${variant_lgx_map[$variant]}"
|
|
|
|
# Read the per-variant main file from this variant's lgx manifest
|
|
variant_main=$(python3 - "$lgx_file" "$variant" <<'PY'
|
|
import tarfile, json, sys
|
|
with tarfile.open(sys.argv[1], 'r:gz') as tar:
|
|
for member in tar.getmembers():
|
|
if member.name == 'manifest.json':
|
|
m = json.loads(tar.extractfile(member).read())
|
|
main = m.get('main', {})
|
|
print(main.get(sys.argv[2], ''))
|
|
break
|
|
PY
|
|
)
|
|
|
|
# Extract variant files from the single-variant lgx into a temp directory
|
|
extract_dir=$(mktemp -d)
|
|
python3 - "$lgx_file" "$variant" "$extract_dir" <<'PY'
|
|
import tarfile, sys, os
|
|
|
|
lgx_path = sys.argv[1]
|
|
variant = sys.argv[2]
|
|
extract_dir = sys.argv[3]
|
|
|
|
prefix = f"variants/{variant}/"
|
|
|
|
with tarfile.open(lgx_path, 'r:gz') as tar:
|
|
for member in tar.getmembers():
|
|
if member.name.startswith(prefix) and member.isfile():
|
|
rel = member.name[len(prefix):]
|
|
target = os.path.join(extract_dir, rel)
|
|
os.makedirs(os.path.dirname(target), exist_ok=True)
|
|
with tar.extractfile(member) as src:
|
|
with open(target, 'wb') as dst:
|
|
dst.write(src.read())
|
|
os.chmod(target, member.mode)
|
|
PY
|
|
|
|
# Determine main file for lgx add
|
|
if [[ -z "$variant_main" || ! -f "$extract_dir/$variant_main" ]]; then
|
|
echo "ERROR: main file '${variant_main:-<unset>}' not found for variant $variant of $module, skipping variant." >&2
|
|
rm -rf "$extract_dir"
|
|
continue
|
|
fi
|
|
|
|
main_path="$variant_main"
|
|
|
|
echo "Adding variant $variant to ${package_name}.lgx (main: $main_path)"
|
|
"$LGX" add "$lgx_package_path" \
|
|
--variant "$variant" \
|
|
--files "$extract_dir/." \
|
|
--main "$main_path" \
|
|
-y || {
|
|
echo "Failed to add variant $variant to LGX package for $package_name" >&2
|
|
exit 1
|
|
}
|
|
|
|
rm -rf "$extract_dir"
|
|
echo "Successfully added variant $variant to ${package_name}.lgx"
|
|
done
|
|
|
|
# Store entry for list.json generation (metadata from the lgx manifest)
|
|
variants_csv=$(IFS=,; echo "${available_variants[*]}")
|
|
module_entries+=("$module::$manifest_json::${package_name}.lgx::${variants_csv}")
|
|
done
|
|
|
|
# Generate list.json
|
|
list_json_path="$output_dir/list.json"
|
|
|
|
python3 - "$list_json_path" "${module_entries[@]}" <<'PY'
|
|
import json, os, sys
|
|
|
|
list_path = sys.argv[1]
|
|
entries = sys.argv[2:]
|
|
|
|
result_index = {}
|
|
|
|
for raw in entries:
|
|
if "::" not in raw:
|
|
continue
|
|
parts = raw.split("::", 3)
|
|
if len(parts) < 3:
|
|
continue
|
|
|
|
name, metadata_json, package_filename = parts[0], parts[1], parts[2]
|
|
variants_csv = parts[3] if len(parts) > 3 else ""
|
|
|
|
try:
|
|
metadata = json.loads(metadata_json)
|
|
except json.JSONDecodeError:
|
|
metadata = {}
|
|
|
|
item = {"name": name}
|
|
item["package"] = package_filename
|
|
|
|
if "type" in metadata:
|
|
item["type"] = metadata["type"]
|
|
if "name" in metadata:
|
|
item["moduleName"] = metadata["name"]
|
|
if "description" in metadata:
|
|
item["description"] = metadata["description"]
|
|
if "dependencies" in metadata:
|
|
item["dependencies"] = metadata["dependencies"]
|
|
if "category" in metadata:
|
|
item["category"] = metadata["category"]
|
|
if "author" in metadata:
|
|
item["author"] = metadata["author"]
|
|
if metadata.get("version"):
|
|
item["version"] = metadata["version"]
|
|
if variants_csv:
|
|
item["variants"] = [v for v in variants_csv.split(",") if v]
|
|
|
|
result_index[name] = item
|
|
|
|
result = [result_index[k] for k in sorted(result_index)]
|
|
os.makedirs(os.path.dirname(list_path), exist_ok=True)
|
|
with open(list_path, "w") as f:
|
|
json.dump(result, f, indent=2)
|
|
PY
|
|
|
|
echo ""
|
|
echo "All modules packaged successfully."
|
|
echo "LGX packages created in $output_dir"
|
|
echo "Package list written to $list_json_path"
|