mirror of
https://github.com/mountain-loop/yaak.git
synced 2026-03-29 21:51:59 +02:00
Replace inline Python with Node for lockfile patching
Add flatpak/fix-lockfile.mjs (vendored from npm-package-lock-add-resolved, MIT) to add missing resolved/integrity fields to package-lock.json. Use it in generate-sources.sh, and use a simpler inline Node one-liner in the manifest for the offline build-time patch.
This commit is contained in:
@@ -61,14 +61,18 @@ modules:
|
||||
- install -Dm755 protoc-bin/protoc crates-tauri/yaak-app/vendored/protoc/yaakprotoc
|
||||
- mkdir -p crates-tauri/yaak-app/vendored/protoc/include && cp -r protoc-bin/google crates-tauri/yaak-app/vendored/protoc/include/google
|
||||
|
||||
# Patch lockfile: add resolved URLs for nested workspace deps
|
||||
# Patch lockfile: add resolved URLs for nested workspace deps that npm
|
||||
# omits (see https://github.com/npm/cli/issues/4460)
|
||||
- >-
|
||||
python3 -c "import json;
|
||||
p='package-lock.json';f=open(p);d=json.load(f);f.close();
|
||||
[info.update({'resolved':'https://registry.npmjs.org/'+n.split('/node_modules/')[-1]+'/-/'+n.split('/')[-1]+'-'+info['version']+'.tgz'})
|
||||
for n,info in d.get('packages',{}).items()
|
||||
if '/node_modules/' in n and 'resolved' not in info and not info.get('link') and info.get('version')];
|
||||
f=open(p,'w');json.dump(d,f);f.close()"
|
||||
node -e "const fs=require('fs');
|
||||
const p='package-lock.json';
|
||||
const d=JSON.parse(fs.readFileSync(p,'utf-8'));
|
||||
for(const[n,info]of Object.entries(d.packages||{})){
|
||||
if(!n||info.link||info.resolved||!n.includes('node_modules/')||!info.version)continue;
|
||||
const pkg=n.split('node_modules/').pop();
|
||||
const base=pkg.split('/').pop();
|
||||
info.resolved='https://registry.npmjs.org/'+pkg+'/-/'+base+'-'+info.version+'.tgz';
|
||||
}fs.writeFileSync(p,JSON.stringify(d,null,2));"
|
||||
|
||||
# Install npm dependencies offline
|
||||
- npm ci --offline
|
||||
|
||||
73
flatpak/fix-lockfile.mjs
Normal file
73
flatpak/fix-lockfile.mjs
Normal file
@@ -0,0 +1,73 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
// Adds missing `resolved` and `integrity` fields to npm package-lock.json.
|
||||
//
|
||||
// npm sometimes omits these fields for nested dependencies inside workspace
|
||||
// packages. This breaks offline installs and tools like flatpak-node-generator
|
||||
// that need explicit tarball URLs for every package.
|
||||
//
|
||||
// Based on https://github.com/grant-dennison/npm-package-lock-add-resolved
|
||||
// (MIT License, Copyright (c) 2024 Grant Dennison)
|
||||
|
||||
import { readFile, writeFile } from "node:fs/promises";
|
||||
import { get } from "node:https";
|
||||
|
||||
const lockfilePath = process.argv[2] || "package-lock.json";
|
||||
|
||||
function fetchJson(url) {
|
||||
return new Promise((resolve, reject) => {
|
||||
get(url, (res) => {
|
||||
let data = "";
|
||||
res.on("data", (chunk) => {
|
||||
data += chunk;
|
||||
});
|
||||
res.on("end", () => {
|
||||
if (res.statusCode === 200) {
|
||||
resolve(JSON.parse(data));
|
||||
} else {
|
||||
reject(`${url} returned ${res.statusCode} ${res.statusMessage}`);
|
||||
}
|
||||
});
|
||||
res.on("error", reject);
|
||||
}).on("error", reject);
|
||||
});
|
||||
}
|
||||
|
||||
async function fillResolved(name, p) {
|
||||
const version = p.version.replace(/^.*@/, "");
|
||||
console.log(`Retrieving metadata for ${name}@${version}`);
|
||||
const metadataUrl = `https://registry.npmjs.com/${name}/${version}`;
|
||||
const metadata = await fetchJson(metadataUrl);
|
||||
p.resolved = metadata.dist.tarball;
|
||||
p.integrity = metadata.dist.integrity;
|
||||
}
|
||||
|
||||
let changesMade = false;
|
||||
|
||||
async function fillAllResolved(packages) {
|
||||
for (const packagePath in packages) {
|
||||
if (packagePath === "") continue;
|
||||
const p = packages[packagePath];
|
||||
if (!p.inBundle && !p.bundled && (!p.resolved || !p.integrity)) {
|
||||
const packageName =
|
||||
p.name ||
|
||||
/^npm:(.+?)@.+$/.exec(p.version)?.[1] ||
|
||||
packagePath.replace(/^.*node_modules\/(?=.+?$)/, "");
|
||||
await fillResolved(packageName, p);
|
||||
changesMade = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const oldContents = await readFile(lockfilePath, "utf-8");
|
||||
const packageLock = JSON.parse(oldContents);
|
||||
|
||||
await fillAllResolved(packageLock.packages ?? []);
|
||||
|
||||
if (changesMade) {
|
||||
const newContents = JSON.stringify(packageLock, null, 2) + "\n";
|
||||
await writeFile(lockfilePath, newContents);
|
||||
console.log(`Updated ${lockfilePath}`);
|
||||
} else {
|
||||
console.log("No changes needed.");
|
||||
}
|
||||
@@ -44,72 +44,35 @@ echo " Done: flatpak/cargo-sources.json"
|
||||
|
||||
echo "Generating node-sources.json..."
|
||||
|
||||
# flatpak-node-generator doesn't handle npm workspace packages (local paths
|
||||
# without "resolved" or "link" fields). Strip them from a temp copy of the
|
||||
# lockfile before running the generator.
|
||||
# npm sometimes omits `resolved` and `integrity` fields from the lockfile for
|
||||
# nested dependencies inside workspace packages. flatpak-node-generator needs
|
||||
# these fields to know which tarballs to download. We fix the lockfile in a temp
|
||||
# copy before running the generator.
|
||||
#
|
||||
# We also strip workspace link entries (no download needed for local packages).
|
||||
TMPDIR=$(mktemp -d)
|
||||
trap 'rm -rf "$TMPDIR"' EXIT
|
||||
|
||||
python3 -c "
|
||||
import json, sys, shutil
|
||||
with open(sys.argv[1]) as f:
|
||||
data = json.load(f)
|
||||
packages = data.get('packages', {})
|
||||
to_remove = []
|
||||
needs_resolve = []
|
||||
for name, info in packages.items():
|
||||
if not name:
|
||||
continue
|
||||
if info.get('link'):
|
||||
continue
|
||||
if 'resolved' in info:
|
||||
continue
|
||||
# No 'resolved' and not a link — local workspace package or nested dep.
|
||||
if '/node_modules/' in name:
|
||||
# Nested node_modules entry inside a workspace package — needs
|
||||
# resolved URL and integrity for flatpak-node-generator.
|
||||
needs_resolve.append((name, info))
|
||||
else:
|
||||
to_remove.append(name)
|
||||
cp "$REPO_ROOT/package-lock.json" "$TMPDIR/package-lock.json"
|
||||
cp "$REPO_ROOT/package.json" "$TMPDIR/package.json"
|
||||
|
||||
# Fetch missing resolved/integrity from the npm registry
|
||||
import urllib.request
|
||||
_packument_cache = {}
|
||||
for name, info in needs_resolve:
|
||||
pkg = name.split('/node_modules/')[-1]
|
||||
version = info.get('version', '')
|
||||
if not version:
|
||||
to_remove.append(name)
|
||||
continue
|
||||
if pkg not in _packument_cache:
|
||||
url = f'https://registry.npmjs.org/{pkg}'
|
||||
try:
|
||||
req = urllib.request.Request(url, headers={'Accept': 'application/json'})
|
||||
with urllib.request.urlopen(req) as resp:
|
||||
_packument_cache[pkg] = json.loads(resp.read())
|
||||
except Exception as e:
|
||||
print(f'Warning: failed to fetch {url}: {e}', file=sys.stderr)
|
||||
to_remove.append(name)
|
||||
continue
|
||||
packument = _packument_cache[pkg]
|
||||
ver_info = packument.get('versions', {}).get(version, {})
|
||||
dist = ver_info.get('dist', {})
|
||||
if dist.get('tarball') and dist.get('integrity'):
|
||||
info['resolved'] = dist['tarball']
|
||||
info['integrity'] = dist['integrity']
|
||||
print(f'Resolved {pkg}@{version}', file=sys.stderr)
|
||||
else:
|
||||
print(f'Warning: no dist info for {pkg}@{version}, removing', file=sys.stderr)
|
||||
to_remove.append(name)
|
||||
# Add missing resolved/integrity fields
|
||||
node "$SCRIPT_DIR/fix-lockfile.mjs" "$TMPDIR/package-lock.json"
|
||||
|
||||
for name in to_remove:
|
||||
del packages[name]
|
||||
with open(sys.argv[2], 'w') as f:
|
||||
json.dump(data, f, indent=2)
|
||||
# Copy package.json so the generator can read the root entry
|
||||
shutil.copy2(sys.argv[3], sys.argv[4])
|
||||
print(f'Stripped {len(to_remove)} local workspace packages from lockfile', file=sys.stderr)
|
||||
" "$REPO_ROOT/package-lock.json" "$TMPDIR/package-lock.json" "$REPO_ROOT/package.json" "$TMPDIR/package.json"
|
||||
# Strip workspace link entries (flatpak-node-generator doesn't handle them)
|
||||
node -e "
|
||||
const fs = require('fs');
|
||||
const p = process.argv[1];
|
||||
const data = JSON.parse(fs.readFileSync(p, 'utf-8'));
|
||||
const packages = data.packages || {};
|
||||
for (const [name, info] of Object.entries(packages)) {
|
||||
if (!name) continue;
|
||||
if (info.link || (!info.resolved && !name.includes('node_modules/'))) {
|
||||
delete packages[name];
|
||||
}
|
||||
}
|
||||
fs.writeFileSync(p, JSON.stringify(data, null, 2));
|
||||
" "$TMPDIR/package-lock.json"
|
||||
|
||||
flatpak-node-generator --no-requests-cache -o "$SCRIPT_DIR/node-sources.json" npm "$TMPDIR/package-lock.json"
|
||||
echo " Done: flatpak/node-sources.json"
|
||||
|
||||
Reference in New Issue
Block a user