This commit is contained in:
@@ -0,0 +1,101 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
cd "$ROOT_DIR"
|
||||
BUILD_ROOT="${STEPFORGE_BUILD_DIR:-$ROOT_DIR/build}"
|
||||
EXAMPLES_ROOT="${STEPFORGE_EXAMPLES_DIR:-$ROOT_DIR/examples}"
|
||||
ARTIFACT_DIR="$BUILD_ROOT/artifacts"
|
||||
REPORT_FILE="$BUILD_ROOT/build_report.md"
|
||||
MANIFEST_FILE="$BUILD_ROOT/artifacts_manifest.json"
|
||||
|
||||
mkdir -p "$BUILD_ROOT"
|
||||
|
||||
bash "$ROOT_DIR/scripts/bootstrap-offline.sh"
|
||||
node "$ROOT_DIR/scripts/make-sample-guide.js" --root "$EXAMPLES_ROOT"
|
||||
STEPFORGE_PACKAGE_DIR="$ARTIFACT_DIR" bash "$ROOT_DIR/scripts/package-linux.sh" >/dev/null
|
||||
|
||||
BUILD_ROOT="$BUILD_ROOT" \
|
||||
ARTIFACT_DIR="$ARTIFACT_DIR" \
|
||||
EXAMPLES_ROOT="$EXAMPLES_ROOT" \
|
||||
REPORT_FILE="$REPORT_FILE" \
|
||||
MANIFEST_FILE="$MANIFEST_FILE" \
|
||||
ROOT_DIR="$ROOT_DIR" \
|
||||
node - <<'NODE'
|
||||
const fs = require('node:fs');
|
||||
const path = require('node:path');
|
||||
const crypto = require('node:crypto');
|
||||
|
||||
const buildRoot = process.env.BUILD_ROOT;
|
||||
const artifactDir = process.env.ARTIFACT_DIR;
|
||||
const examplesRoot = process.env.EXAMPLES_ROOT;
|
||||
const reportFile = process.env.REPORT_FILE;
|
||||
const manifestFile = process.env.MANIFEST_FILE;
|
||||
const rootDir = process.env.ROOT_DIR;
|
||||
|
||||
function walk(dir, base = dir, out = []) {
|
||||
if (!fs.existsSync(dir)) return out;
|
||||
for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
|
||||
const abs = path.join(dir, entry.name);
|
||||
if (entry.isDirectory()) walk(abs, base, out);
|
||||
else out.push(path.relative(base, abs));
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
function sha256(file) {
|
||||
return crypto.createHash('sha256').update(fs.readFileSync(file)).digest('hex');
|
||||
}
|
||||
|
||||
const files = [];
|
||||
for (const rel of walk(artifactDir, artifactDir)) {
|
||||
const abs = path.join(artifactDir, rel);
|
||||
files.push({
|
||||
kind: 'artifact',
|
||||
path: path.relative(buildRoot, abs),
|
||||
size: fs.statSync(abs).size,
|
||||
sha256: sha256(abs),
|
||||
});
|
||||
}
|
||||
for (const rel of walk(examplesRoot, examplesRoot)) {
|
||||
if (!rel.startsWith('sample-')) continue;
|
||||
const abs = path.join(examplesRoot, rel);
|
||||
files.push({
|
||||
kind: 'sample',
|
||||
path: path.relative(buildRoot, abs),
|
||||
size: fs.statSync(abs).size,
|
||||
sha256: sha256(abs),
|
||||
});
|
||||
}
|
||||
|
||||
const pkg = require(path.join(rootDir, 'package.json'));
|
||||
const report = `# StepForge Build Report
|
||||
|
||||
Version: ${pkg.version}
|
||||
Generated: ${new Date().toISOString()}
|
||||
|
||||
## Outputs
|
||||
|
||||
- Portable tarball: ${files.find((f) => f.path.endsWith('.tar.gz'))?.path || 'not generated'}
|
||||
- Debian package: ${files.find((f) => f.path.endsWith('.deb'))?.path || 'not generated'}
|
||||
- Sample guide archive: ${files.find((f) => f.path.endsWith('sample-guide.sfgz'))?.path || 'not generated'}
|
||||
|
||||
## Notes
|
||||
|
||||
- The desktop shell is Electron.
|
||||
- Core storage, exports, and archive handling are local-only.
|
||||
- Sample exports and package artifacts are written by the offline build scripts.
|
||||
`;
|
||||
|
||||
fs.writeFileSync(reportFile, report);
|
||||
fs.writeFileSync(manifestFile, JSON.stringify({
|
||||
format: 'stepforge-artifacts-manifest',
|
||||
version: 1,
|
||||
generatedAt: new Date().toISOString(),
|
||||
packageVersion: pkg.version,
|
||||
files,
|
||||
}, null, 2) + '\n');
|
||||
NODE
|
||||
|
||||
echo "Build artifacts written to $BUILD_ROOT"
|
||||
Reference in New Issue
Block a user