@hominis/fireforge 0.43.1 → 0.44.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +126 -0
- package/README.md +10 -1
- package/dist/bin/fireforge.d.ts +4 -9
- package/dist/bin/fireforge.js +42 -40
- package/dist/build-info.json +4 -4
- package/dist/src/cli.js +74 -8
- package/dist/src/commands/bootstrap.js +17 -20
- package/dist/src/commands/build.js +25 -32
- package/dist/src/commands/config.js +34 -41
- package/dist/src/commands/discard.js +8 -9
- package/dist/src/commands/doctor-check-core.d.ts +4 -18
- package/dist/src/commands/doctor-check-core.js +8 -35
- package/dist/src/commands/doctor-external-toolchains.js +2 -2
- package/dist/src/commands/doctor-furnace-config-sync.d.ts +18 -0
- package/dist/src/commands/{doctor-furnace-manifest-sync.js → doctor-furnace-config-sync.js} +27 -26
- package/dist/src/commands/doctor-furnace-jar.d.ts +7 -9
- package/dist/src/commands/doctor-furnace-jar.js +7 -9
- package/dist/src/commands/doctor-furnace.js +21 -24
- package/dist/src/commands/doctor-orphaned-harness.d.ts +16 -20
- package/dist/src/commands/doctor-orphaned-harness.js +18 -44
- package/dist/src/commands/doctor-post-rebase-audit.d.ts +2 -0
- package/dist/src/commands/{doctor/post-rebase-audit.js → doctor-post-rebase-audit.js} +3 -3
- package/dist/src/commands/doctor-working-tree.d.ts +10 -12
- package/dist/src/commands/doctor-working-tree.js +11 -18
- package/dist/src/commands/doctor.js +35 -53
- package/dist/src/commands/download.js +32 -48
- package/dist/src/commands/export-all.js +29 -33
- package/dist/src/commands/export-flow.js +6 -6
- package/dist/src/commands/export-placement-conflicts.js +10 -9
- package/dist/src/commands/export-placement-gate.js +5 -5
- package/dist/src/commands/export-shared.d.ts +30 -33
- package/dist/src/commands/export-shared.js +45 -43
- package/dist/src/commands/export.js +21 -27
- package/dist/src/commands/furnace/apply.js +14 -23
- package/dist/src/commands/furnace/chrome-doc-remove.js +14 -21
- package/dist/src/commands/furnace/chrome-doc-templates.d.ts +23 -23
- package/dist/src/commands/furnace/chrome-doc-templates.js +23 -23
- package/dist/src/commands/furnace/chrome-doc-tests.js +26 -29
- package/dist/src/commands/furnace/chrome-doc.d.ts +16 -17
- package/dist/src/commands/furnace/chrome-doc.js +31 -41
- package/dist/src/commands/furnace/create-browser-test.d.ts +4 -4
- package/dist/src/commands/furnace/create-browser-test.js +8 -8
- package/dist/src/commands/furnace/create-mochikit.d.ts +6 -7
- package/dist/src/commands/furnace/create-mochikit.js +8 -9
- package/dist/src/commands/furnace/create-readback.d.ts +12 -13
- package/dist/src/commands/furnace/create-readback.js +12 -13
- package/dist/src/commands/furnace/create-templates.d.ts +22 -28
- package/dist/src/commands/furnace/create-templates.js +35 -30
- package/dist/src/commands/furnace/create-xpcshell.js +2 -2
- package/dist/src/commands/furnace/create.js +33 -23
- package/dist/src/commands/furnace/deploy.js +16 -24
- package/dist/src/commands/furnace/diff.js +9 -9
- package/dist/src/commands/furnace/init.js +33 -36
- package/dist/src/commands/furnace/override.js +23 -25
- package/dist/src/commands/furnace/preview.js +47 -67
- package/dist/src/commands/furnace/refresh.js +12 -16
- package/dist/src/commands/furnace/remove-mutations.d.ts +3 -6
- package/dist/src/commands/furnace/remove-mutations.js +9 -16
- package/dist/src/commands/furnace/remove-state.js +1 -1
- package/dist/src/commands/furnace/remove.js +33 -38
- package/dist/src/commands/furnace/rename-xpcshell.d.ts +8 -11
- package/dist/src/commands/furnace/rename-xpcshell.js +8 -11
- package/dist/src/commands/furnace/rename.js +59 -69
- package/dist/src/commands/furnace/scan.js +19 -33
- package/dist/src/commands/furnace/status.js +12 -9
- package/dist/src/commands/furnace/sync.js +9 -16
- package/dist/src/commands/furnace/validate.js +20 -20
- package/dist/src/commands/import.js +42 -35
- package/dist/src/commands/lint-per-patch.js +15 -10
- package/dist/src/commands/lint-per-run-checkjs.d.ts +13 -13
- package/dist/src/commands/lint-per-run-checkjs.js +13 -13
- package/dist/src/commands/lint-report.js +6 -7
- package/dist/src/commands/lint.d.ts +15 -16
- package/dist/src/commands/lint.js +86 -102
- package/dist/src/commands/package.js +6 -11
- package/dist/src/commands/patch/compact.js +1 -1
- package/dist/src/commands/patch/delete.js +24 -33
- package/dist/src/commands/patch/index.d.ts +5 -6
- package/dist/src/commands/patch/index.js +10 -12
- package/dist/src/commands/patch/lint-ignore.js +14 -13
- package/dist/src/commands/patch/move-files-create.d.ts +6 -6
- package/dist/src/commands/patch/move-files-create.js +8 -8
- package/dist/src/commands/patch/move-files-into.d.ts +6 -6
- package/dist/src/commands/patch/move-files-into.js +8 -8
- package/dist/src/commands/patch/patch-context.d.ts +2 -3
- package/dist/src/commands/patch/patch-context.js +2 -3
- package/dist/src/commands/patch/rename.d.ts +10 -11
- package/dist/src/commands/patch/rename.js +11 -12
- package/dist/src/commands/patch/reorder.js +8 -9
- package/dist/src/commands/patch/split-plan.js +1 -1
- package/dist/src/commands/patch/split.d.ts +8 -10
- package/dist/src/commands/patch/split.js +9 -11
- package/dist/src/commands/patch/staged-dependency-validate.js +8 -8
- package/dist/src/commands/patch/staged-dependency.js +7 -3
- package/dist/src/commands/patch/tier.d.ts +9 -9
- package/dist/src/commands/patch/tier.js +18 -15
- package/dist/src/commands/re-export-adjacent.js +9 -8
- package/dist/src/commands/re-export-bulk-scan.d.ts +9 -9
- package/dist/src/commands/re-export-bulk-scan.js +22 -21
- package/dist/src/commands/re-export-drift.js +10 -10
- package/dist/src/commands/re-export-files.d.ts +6 -7
- package/dist/src/commands/re-export-files.js +34 -44
- package/dist/src/commands/re-export-lint.d.ts +10 -13
- package/dist/src/commands/re-export-lint.js +16 -14
- package/dist/src/commands/re-export-options.d.ts +6 -6
- package/dist/src/commands/re-export-options.js +6 -6
- package/dist/src/commands/re-export-register.d.ts +4 -10
- package/dist/src/commands/re-export-register.js +5 -11
- package/dist/src/commands/re-export-scan.js +1 -1
- package/dist/src/commands/re-export-single.d.ts +3 -3
- package/dist/src/commands/re-export-single.js +33 -25
- package/dist/src/commands/re-export.js +13 -21
- package/dist/src/commands/rebase/abort.js +3 -3
- package/dist/src/commands/rebase/confirm.js +2 -1
- package/dist/src/commands/rebase/continue.d.ts +1 -1
- package/dist/src/commands/rebase/continue.js +14 -9
- package/dist/src/commands/rebase/index.js +11 -11
- package/dist/src/commands/rebase/patch-loop.d.ts +7 -1
- package/dist/src/commands/rebase/patch-loop.js +60 -39
- package/dist/src/commands/rebase/summary.js +1 -1
- package/dist/src/commands/register.js +5 -7
- package/dist/src/commands/reset.js +2 -1
- package/dist/src/commands/resolve.d.ts +16 -13
- package/dist/src/commands/resolve.js +30 -33
- package/dist/src/commands/run.js +33 -35
- package/dist/src/commands/setup-support.js +15 -19
- package/dist/src/commands/setup.js +13 -9
- package/dist/src/commands/status-check.d.ts +6 -6
- package/dist/src/commands/status-json.d.ts +6 -6
- package/dist/src/commands/status-json.js +5 -0
- package/dist/src/commands/status-output.d.ts +5 -5
- package/dist/src/commands/status-output.js +6 -6
- package/dist/src/commands/status-ownership.d.ts +16 -14
- package/dist/src/commands/status-ownership.js +16 -14
- package/dist/src/commands/status.js +42 -34
- package/dist/src/commands/test-build-phase.js +26 -13
- package/dist/src/commands/test-diagnose.js +44 -44
- package/dist/src/commands/test-register.js +1 -0
- package/dist/src/commands/test-run.d.ts +14 -16
- package/dist/src/commands/test-run.js +21 -13
- package/dist/src/commands/test-stale-gate.d.ts +15 -16
- package/dist/src/commands/test-stale-gate.js +15 -16
- package/dist/src/commands/test-verdict.d.ts +20 -3
- package/dist/src/commands/test-verdict.js +30 -0
- package/dist/src/commands/test.js +83 -76
- package/dist/src/commands/token-coverage.js +3 -4
- package/dist/src/commands/token.js +16 -18
- package/dist/src/commands/tree.js +47 -31
- package/dist/src/commands/typecheck.d.ts +10 -12
- package/dist/src/commands/typecheck.js +24 -27
- package/dist/src/commands/verify.js +13 -15
- package/dist/src/commands/watch.js +21 -23
- package/dist/src/commands/wire.js +52 -62
- package/dist/src/core/ast-utils.d.ts +8 -7
- package/dist/src/core/ast-utils.js +8 -7
- package/dist/src/core/branding.d.ts +9 -14
- package/dist/src/core/branding.js +7 -11
- package/dist/src/core/browser-wire.d.ts +1 -1
- package/dist/src/core/browser-wire.js +14 -19
- package/dist/src/core/build-audit-platform.js +25 -33
- package/dist/src/core/build-audit-registration.js +17 -25
- package/dist/src/core/build-audit-resolve.d.ts +15 -17
- package/dist/src/core/build-audit-resolve.js +27 -33
- package/dist/src/core/build-audit-transforms.js +18 -19
- package/dist/src/core/build-audit.js +28 -42
- package/dist/src/core/build-baseline-types.d.ts +29 -35
- package/dist/src/core/build-baseline.d.ts +5 -4
- package/dist/src/core/build-baseline.js +14 -14
- package/dist/src/core/build-overwrite-guard.d.ts +7 -14
- package/dist/src/core/build-overwrite-guard.js +17 -27
- package/dist/src/core/build-prepare.d.ts +2 -2
- package/dist/src/core/build-prepare.js +8 -9
- package/dist/src/core/config-state.js +12 -4
- package/dist/src/core/config-validate.js +8 -5
- package/dist/src/core/config.d.ts +5 -8
- package/dist/src/core/config.js +7 -16
- package/dist/src/core/coverage-extend.d.ts +15 -13
- package/dist/src/core/coverage-extend.js +15 -13
- package/dist/src/core/destructive.d.ts +31 -9
- package/dist/src/core/destructive.js +29 -26
- package/dist/src/core/diff-hunks.js +10 -12
- package/dist/src/core/discard-baseline.d.ts +8 -8
- package/dist/src/core/discard-baseline.js +16 -15
- package/dist/src/core/display-state.d.ts +12 -14
- package/dist/src/core/display-state.js +12 -14
- package/dist/src/core/engine-changes.d.ts +2 -4
- package/dist/src/core/engine-changes.js +2 -4
- package/dist/src/core/engine-precondition.d.ts +28 -13
- package/dist/src/core/engine-precondition.js +25 -10
- package/dist/src/core/engine-session-lock.d.ts +47 -21
- package/dist/src/core/engine-session-lock.js +168 -33
- package/dist/src/core/export-moved-code-shape.d.ts +10 -10
- package/dist/src/core/export-moved-code-shape.js +10 -10
- package/dist/src/core/file-lock.d.ts +62 -5
- package/dist/src/core/file-lock.js +196 -59
- package/dist/src/core/firefox-cache.js +1 -3
- package/dist/src/core/firefox-extract.js +10 -14
- package/dist/src/core/firefox.d.ts +7 -5
- package/dist/src/core/firefox.js +4 -5
- package/dist/src/core/furnace-apply-dry-run.d.ts +2 -2
- package/dist/src/core/furnace-apply-dry-run.js +3 -2
- package/dist/src/core/furnace-apply-ftl.d.ts +7 -9
- package/dist/src/core/furnace-apply-ftl.js +12 -12
- package/dist/src/core/furnace-apply-helpers.d.ts +7 -7
- package/dist/src/core/furnace-apply-helpers.js +19 -16
- package/dist/src/core/furnace-apply-overwrite-warn.d.ts +8 -9
- package/dist/src/core/furnace-apply-overwrite-warn.js +8 -9
- package/dist/src/core/furnace-apply-undeploy-actions.d.ts +3 -4
- package/dist/src/core/furnace-apply-undeploy-actions.js +3 -4
- package/dist/src/core/furnace-apply.d.ts +5 -8
- package/dist/src/core/furnace-apply.js +19 -24
- package/dist/src/core/furnace-checksum-utils.d.ts +14 -0
- package/dist/src/core/furnace-checksum-utils.js +16 -0
- package/dist/src/core/furnace-config.d.ts +21 -30
- package/dist/src/core/furnace-config.js +32 -54
- package/dist/src/core/furnace-constants.d.ts +8 -0
- package/dist/src/core/furnace-constants.js +10 -2
- package/dist/src/core/furnace-css-fragments.d.ts +5 -5
- package/dist/src/core/furnace-css-fragments.js +5 -5
- package/dist/src/core/furnace-jsconfig.d.ts +11 -12
- package/dist/src/core/furnace-jsconfig.js +11 -12
- package/dist/src/core/furnace-marker.d.ts +7 -8
- package/dist/src/core/furnace-marker.js +7 -8
- package/dist/src/core/furnace-operation.d.ts +31 -0
- package/dist/src/core/furnace-operation.js +54 -17
- package/dist/src/core/furnace-precondition.d.ts +61 -0
- package/dist/src/core/furnace-precondition.js +67 -0
- package/dist/src/core/furnace-registration-remove.d.ts +5 -6
- package/dist/src/core/furnace-registration-remove.js +6 -7
- package/dist/src/core/furnace-registration-validate.d.ts +13 -0
- package/dist/src/core/furnace-registration-validate.js +20 -1
- package/dist/src/core/furnace-registration.d.ts +5 -6
- package/dist/src/core/furnace-registration.js +10 -12
- package/dist/src/core/furnace-rollback.js +7 -7
- package/dist/src/core/furnace-scanner.d.ts +1 -0
- package/dist/src/core/furnace-scanner.js +1 -2
- package/dist/src/core/furnace-stale-export.d.ts +10 -10
- package/dist/src/core/furnace-stale-export.js +10 -10
- package/dist/src/core/furnace-state-persist.d.ts +6 -8
- package/dist/src/core/furnace-state-persist.js +6 -8
- package/dist/src/core/furnace-validate-accessibility.d.ts +22 -0
- package/dist/src/core/furnace-validate-accessibility.js +310 -1
- package/dist/src/core/furnace-validate-compatibility.js +141 -1
- package/dist/src/core/furnace-validate-helpers.d.ts +5 -116
- package/dist/src/core/furnace-validate-helpers.js +0 -491
- package/dist/src/core/furnace-validate-registration.d.ts +7 -0
- package/dist/src/core/furnace-validate-registration.js +115 -41
- package/dist/src/core/furnace-validate.d.ts +16 -0
- package/dist/src/core/furnace-validate.js +188 -145
- package/dist/src/core/furnace-version-drift.d.ts +10 -11
- package/dist/src/core/furnace-version-drift.js +10 -11
- package/dist/src/core/git-base.d.ts +7 -9
- package/dist/src/core/git-base.js +7 -9
- package/dist/src/core/git-diff.d.ts +20 -9
- package/dist/src/core/git-diff.js +148 -63
- package/dist/src/core/git-file-ops.d.ts +19 -19
- package/dist/src/core/git-file-ops.js +19 -19
- package/dist/src/core/git-readonly-index.d.ts +53 -19
- package/dist/src/core/git-readonly-index.js +75 -31
- package/dist/src/core/git-status.d.ts +5 -6
- package/dist/src/core/git-status.js +5 -6
- package/dist/src/core/git.d.ts +9 -10
- package/dist/src/core/git.js +54 -70
- package/dist/src/core/license-headers.d.ts +17 -23
- package/dist/src/core/license-headers.js +17 -23
- package/dist/src/core/mach-build-artifacts.d.ts +9 -9
- package/dist/src/core/mach-build-artifacts.js +57 -19
- package/dist/src/core/mach-error-hints.js +42 -29
- package/dist/src/core/mach-known-noise-filter.d.ts +15 -16
- package/dist/src/core/mach-known-noise-filter.js +18 -20
- package/dist/src/core/mach-mozconfig.d.ts +14 -0
- package/dist/src/core/mach-mozconfig.js +30 -0
- package/dist/src/core/mach-resource-shim.d.ts +43 -58
- package/dist/src/core/mach-resource-shim.js +50 -67
- package/dist/src/core/mach.d.ts +37 -41
- package/dist/src/core/mach.js +50 -51
- package/dist/src/core/marionette-port.d.ts +36 -1
- package/dist/src/core/marionette-port.js +96 -31
- package/dist/src/core/marionette-preflight.d.ts +8 -12
- package/dist/src/core/marionette-preflight.js +86 -52
- package/dist/src/core/mochitest-server-port.d.ts +42 -0
- package/dist/src/core/mochitest-server-port.js +119 -0
- package/dist/src/core/module-resolution-preflight.d.ts +9 -11
- package/dist/src/core/module-resolution-preflight.js +9 -11
- package/dist/src/core/moz-manifest-helpers.d.ts +79 -0
- package/dist/src/core/moz-manifest-helpers.js +163 -0
- package/dist/src/core/{manifest-register.d.ts → moz-manifest-register.d.ts} +1 -1
- package/dist/src/core/{manifest-register.js → moz-manifest-register.js} +13 -28
- package/dist/src/core/{manifest-rules.d.ts → moz-manifest-rules.d.ts} +10 -1
- package/dist/src/core/{manifest-rules.js → moz-manifest-rules.js} +31 -24
- package/dist/src/core/{manifest-tokenizers.d.ts → moz-manifest-tokenizers.d.ts} +3 -5
- package/dist/src/core/{manifest-tokenizers.js → moz-manifest-tokenizers.js} +9 -12
- package/dist/src/core/ownership-table.d.ts +14 -16
- package/dist/src/core/ownership-table.js +14 -16
- package/dist/src/core/parser-fallback.d.ts +15 -1
- package/dist/src/core/parser-fallback.js +22 -3
- package/dist/src/core/patch-apply-fuzz.d.ts +10 -12
- package/dist/src/core/patch-apply-fuzz.js +15 -18
- package/dist/src/core/patch-apply.d.ts +13 -34
- package/dist/src/core/patch-apply.js +16 -76
- package/dist/src/core/patch-artifact-normalize.d.ts +13 -15
- package/dist/src/core/patch-artifact-normalize.js +13 -15
- package/dist/src/core/patch-export-metadata.d.ts +12 -2
- package/dist/src/core/patch-export-metadata.js +13 -4
- package/dist/src/core/patch-export-update.d.ts +13 -1
- package/dist/src/core/patch-export-update.js +25 -8
- package/dist/src/core/patch-export.d.ts +15 -8
- package/dist/src/core/patch-export.js +10 -11
- package/dist/src/core/patch-files.d.ts +5 -6
- package/dist/src/core/patch-files.js +5 -6
- package/dist/src/core/patch-identifier-suggest.d.ts +7 -12
- package/dist/src/core/patch-identifier-suggest.js +14 -19
- package/dist/src/core/patch-lint-binary.d.ts +51 -0
- package/dist/src/core/patch-lint-binary.js +39 -0
- package/dist/src/core/{lint-cache.d.ts → patch-lint-cache.d.ts} +5 -5
- package/dist/src/core/{lint-cache.js → patch-lint-cache.js} +21 -23
- package/dist/src/core/patch-lint-checkjs.d.ts +16 -16
- package/dist/src/core/patch-lint-checkjs.js +16 -16
- package/dist/src/core/patch-lint-chrome-jsdoc.d.ts +6 -9
- package/dist/src/core/patch-lint-chrome-jsdoc.js +10 -14
- package/dist/src/core/patch-lint-creators.d.ts +8 -8
- package/dist/src/core/patch-lint-creators.js +8 -8
- package/dist/src/core/patch-lint-cross.d.ts +17 -20
- package/dist/src/core/patch-lint-cross.js +16 -16
- package/dist/src/core/patch-lint-css.d.ts +3 -5
- package/dist/src/core/patch-lint-css.js +17 -22
- package/dist/src/core/patch-lint-diff-tag.d.ts +14 -16
- package/dist/src/core/patch-lint-diff-tag.js +14 -16
- package/dist/src/core/patch-lint-jsdoc.d.ts +7 -8
- package/dist/src/core/patch-lint-jsdoc.js +26 -19
- package/dist/src/core/patch-lint-mozbuild.js +20 -20
- package/dist/src/core/patch-lint-observer.d.ts +7 -7
- package/dist/src/core/patch-lint-observer.js +7 -7
- package/dist/src/core/patch-lint.d.ts +38 -29
- package/dist/src/core/patch-lint.js +89 -121
- package/dist/src/core/patch-lock.d.ts +1 -1
- package/dist/src/core/patch-lock.js +45 -9
- package/dist/src/core/patch-manifest-consistency.d.ts +2 -1
- package/dist/src/core/patch-manifest-consistency.js +25 -27
- package/dist/src/core/patch-manifest-io.js +14 -18
- package/dist/src/core/patch-manifest-resolve.d.ts +9 -12
- package/dist/src/core/patch-manifest-resolve.js +9 -12
- package/dist/src/core/patch-manifest-validate.d.ts +6 -1
- package/dist/src/core/patch-manifest-validate.js +25 -13
- package/dist/src/core/patch-parse.d.ts +24 -13
- package/dist/src/core/patch-parse.js +19 -14
- package/dist/src/core/patch-policy.d.ts +2 -2
- package/dist/src/core/patch-policy.js +2 -2
- package/dist/src/core/patch-registration-refs.d.ts +7 -8
- package/dist/src/core/patch-registration-refs.js +9 -9
- package/dist/src/core/process-cpu-time.d.ts +12 -0
- package/dist/src/core/process-cpu-time.js +52 -0
- package/dist/src/core/rebase-session.d.ts +38 -26
- package/dist/src/core/rebase-session.js +55 -28
- package/dist/src/core/register-browser-content.js +9 -74
- package/dist/src/core/{register-test-manifest.js → register-browser-test.js} +7 -42
- package/dist/src/core/register-module.js +10 -43
- package/dist/src/core/register-scaffold.d.ts +8 -8
- package/dist/src/core/register-scaffold.js +10 -10
- package/dist/src/core/register-shared-css.d.ts +9 -12
- package/dist/src/core/register-shared-css.js +17 -87
- package/dist/src/core/register-xpcshell-test.d.ts +6 -7
- package/dist/src/core/register-xpcshell-test.js +7 -8
- package/dist/src/core/shared-ftl.js +12 -4
- package/dist/src/core/state-file.d.ts +45 -0
- package/dist/src/core/state-file.js +34 -0
- package/dist/src/core/status-binary.d.ts +18 -11
- package/dist/src/core/status-binary.js +19 -12
- package/dist/src/core/status-classify.d.ts +30 -36
- package/dist/src/core/status-classify.js +21 -26
- package/dist/src/core/test-changed-prefs.d.ts +30 -0
- package/dist/src/core/test-changed-prefs.js +78 -0
- package/dist/src/core/test-harness-crash.d.ts +25 -63
- package/dist/src/core/test-harness-crash.js +121 -142
- package/dist/src/core/test-harness-signature.d.ts +18 -0
- package/dist/src/core/test-harness-signature.js +13 -0
- package/dist/src/core/test-path-scope.d.ts +12 -15
- package/dist/src/core/test-path-scope.js +15 -18
- package/dist/src/core/test-stale-check.d.ts +17 -17
- package/dist/src/core/test-stale-check.js +50 -43
- package/dist/src/core/test-stall-triage.d.ts +51 -0
- package/dist/src/core/test-stall-triage.js +126 -0
- package/dist/src/core/token-category.js +5 -7
- package/dist/src/core/token-coverage.js +9 -9
- package/dist/src/core/token-dark-mode.d.ts +9 -11
- package/dist/src/core/token-dark-mode.js +9 -11
- package/dist/src/core/token-docs.d.ts +2 -0
- package/dist/src/core/token-docs.js +2 -0
- package/dist/src/core/token-manager.d.ts +10 -2
- package/dist/src/core/token-manager.js +17 -8
- package/dist/src/core/token-scaffold.d.ts +7 -7
- package/dist/src/core/token-scaffold.js +7 -7
- package/dist/src/core/token-variant.d.ts +4 -4
- package/dist/src/core/token-variant.js +4 -4
- package/dist/src/core/toolchain-preflight.d.ts +20 -21
- package/dist/src/core/toolchain-preflight.js +28 -31
- package/dist/src/core/tree-guard.js +12 -2
- package/dist/src/core/tree-store.d.ts +41 -27
- package/dist/src/core/tree-store.js +63 -42
- package/dist/src/core/typecheck-shim.d.ts +23 -24
- package/dist/src/core/typecheck-shim.js +23 -24
- package/dist/src/core/typecheck.js +8 -8
- package/dist/src/core/wire-destroy.d.ts +3 -3
- package/dist/src/core/wire-destroy.js +7 -15
- package/dist/src/core/wire-dom-fragment.d.ts +9 -17
- package/dist/src/core/wire-dom-fragment.js +11 -44
- package/dist/src/core/wire-init.d.ts +2 -3
- package/dist/src/core/wire-init.js +8 -19
- package/dist/src/core/wire-subscript.d.ts +2 -3
- package/dist/src/core/wire-subscript.js +4 -13
- package/dist/src/core/wire-utils.d.ts +7 -8
- package/dist/src/core/wire-utils.js +7 -8
- package/dist/src/core/xpcshell-appdir.d.ts +38 -45
- package/dist/src/core/xpcshell-appdir.js +38 -45
- package/dist/src/errors/base.d.ts +37 -16
- package/dist/src/errors/base.js +37 -16
- package/dist/src/errors/build.d.ts +13 -1
- package/dist/src/errors/build.js +14 -2
- package/dist/src/errors/codes.d.ts +16 -0
- package/dist/src/errors/codes.js +16 -0
- package/dist/src/errors/furnace.d.ts +4 -4
- package/dist/src/errors/git.d.ts +6 -10
- package/dist/src/errors/git.js +6 -10
- package/dist/src/errors/patch.d.ts +7 -7
- package/dist/src/errors/patch.js +7 -7
- package/dist/src/errors/rebase.d.ts +4 -4
- package/dist/src/errors/rebase.js +4 -4
- package/dist/src/index.d.ts +7 -1
- package/dist/src/index.js +5 -0
- package/dist/src/types/commands/index.d.ts +2 -2
- package/dist/src/types/commands/options.d.ts +88 -70
- package/dist/src/types/commands/patches.d.ts +24 -34
- package/dist/src/types/commands/project.d.ts +5 -34
- package/dist/src/types/config.d.ts +25 -23
- package/dist/src/types/config.js +6 -1
- package/dist/src/types/furnace.d.ts +37 -13
- package/dist/src/types/furnace.js +19 -1
- package/dist/src/types/index.d.ts +3 -3
- package/dist/src/utils/build-info.d.ts +7 -8
- package/dist/src/utils/build-info.js +12 -11
- package/dist/src/utils/errors.d.ts +6 -8
- package/dist/src/utils/errors.js +6 -8
- package/dist/src/utils/logger.d.ts +27 -10
- package/dist/src/utils/logger.js +28 -16
- package/dist/src/utils/machine-output.d.ts +12 -0
- package/dist/src/utils/machine-output.js +33 -0
- package/dist/src/utils/options.d.ts +31 -14
- package/dist/src/utils/options.js +86 -30
- package/dist/src/utils/paths.d.ts +10 -8
- package/dist/src/utils/paths.js +10 -8
- package/dist/src/utils/platform.d.ts +0 -25
- package/dist/src/utils/platform.js +1 -42
- package/dist/src/utils/process-group.d.ts +9 -4
- package/dist/src/utils/process-group.js +19 -5
- package/dist/src/utils/process.d.ts +42 -7
- package/dist/src/utils/process.js +44 -17
- package/dist/src/utils/ps-duration.d.ts +31 -0
- package/dist/src/utils/ps-duration.js +70 -0
- package/dist/src/utils/regex.d.ts +9 -10
- package/dist/src/utils/regex.js +9 -10
- package/dist/src/utils/validation.d.ts +58 -28
- package/dist/src/utils/validation.js +60 -33
- package/package.json +2 -2
- package/dist/src/commands/doctor/post-rebase-audit.d.ts +0 -2
- package/dist/src/commands/doctor-furnace-manifest-sync.d.ts +0 -18
- package/dist/src/core/manifest-helpers.d.ts +0 -38
- package/dist/src/core/manifest-helpers.js +0 -120
- /package/dist/src/core/{lint-projection.d.ts → patch-lint-projection.d.ts} +0 -0
- /package/dist/src/core/{lint-projection.js → patch-lint-projection.js} +0 -0
- /package/dist/src/core/{register-test-manifest.d.ts → register-browser-test.d.ts} +0 -0
|
@@ -5,21 +5,20 @@
|
|
|
5
5
|
* Overrides are forks of Firefox source files taken at a specific point in
|
|
6
6
|
* time. If Firefox moves forward and the override's `baseVersion` is not
|
|
7
7
|
* refreshed, the override may apply against a file whose upstream shape has
|
|
8
|
-
* changed —
|
|
8
|
+
* changed — the single biggest silent failure mode for furnace.
|
|
9
9
|
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
10
|
+
* Deliberately pure and string-only: no I/O, and no parsing of Firefox
|
|
11
|
+
* version components. String equality is sufficient because `fireforge.json`
|
|
12
|
+
* stores a canonical version string (e.g. `"140.9.0esr"`) and overrides are
|
|
13
|
+
* created with exactly that string copied from
|
|
14
|
+
* `forgeConfig.firefox.version`. Any mismatch is worth surfacing — even
|
|
15
|
+
* "140.0" vs "140.9.0esr" is a real drift signal.
|
|
16
16
|
*
|
|
17
17
|
* The result GATES apply/deploy: both warn and then FAIL without --force
|
|
18
18
|
* (see furnaceApplyCommand / furnaceDeployCommand), and `furnace sync`
|
|
19
|
-
* re-checks it after refresh before applying. Status reports drift
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
* re-breaking the gate.
|
|
19
|
+
* re-checks it after refresh before applying. Status reports drift alongside
|
|
20
|
+
* the component overview. Keep this doc in sync with the gates — it is not
|
|
21
|
+
* advisory.
|
|
23
22
|
*/
|
|
24
23
|
import type { FurnaceConfig } from '../types/furnace.js';
|
|
25
24
|
/** Severity of the version drift between an override's base and the current Firefox version. */
|
|
@@ -6,21 +6,20 @@
|
|
|
6
6
|
* Overrides are forks of Firefox source files taken at a specific point in
|
|
7
7
|
* time. If Firefox moves forward and the override's `baseVersion` is not
|
|
8
8
|
* refreshed, the override may apply against a file whose upstream shape has
|
|
9
|
-
* changed —
|
|
9
|
+
* changed — the single biggest silent failure mode for furnace.
|
|
10
10
|
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
11
|
+
* Deliberately pure and string-only: no I/O, and no parsing of Firefox
|
|
12
|
+
* version components. String equality is sufficient because `fireforge.json`
|
|
13
|
+
* stores a canonical version string (e.g. `"140.9.0esr"`) and overrides are
|
|
14
|
+
* created with exactly that string copied from
|
|
15
|
+
* `forgeConfig.firefox.version`. Any mismatch is worth surfacing — even
|
|
16
|
+
* "140.0" vs "140.9.0esr" is a real drift signal.
|
|
17
17
|
*
|
|
18
18
|
* The result GATES apply/deploy: both warn and then FAIL without --force
|
|
19
19
|
* (see furnaceApplyCommand / furnaceDeployCommand), and `furnace sync`
|
|
20
|
-
* re-checks it after refresh before applying. Status reports drift
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
* re-breaking the gate.
|
|
20
|
+
* re-checks it after refresh before applying. Status reports drift alongside
|
|
21
|
+
* the component overview. Keep this doc in sync with the gates — it is not
|
|
22
|
+
* advisory.
|
|
24
23
|
*/
|
|
25
24
|
/**
|
|
26
25
|
* Parses a version string into its major, minor, and patch numeric
|
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Environment variable that overrides the monolithic `git add -A` timeout
|
|
3
|
-
* (milliseconds).
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
* them retry without recompiling.
|
|
3
|
+
* (milliseconds). Operators on slow or loaded filesystems can legitimately
|
|
4
|
+
* exceed the 10-minute default during a baseline indexing pass; making the
|
|
5
|
+
* cap overridable lets them retry without recompiling.
|
|
7
6
|
*/
|
|
8
7
|
export declare const GIT_ADD_TIMEOUT_ENV_VAR = "FIREFORGE_GIT_ADD_TIMEOUT_MS";
|
|
9
8
|
/**
|
|
@@ -20,11 +19,10 @@ export declare const GIT_ADD_CHUNK_TIMEOUT_ENV_VAR = "FIREFORGE_GIT_ADD_CHUNK_TI
|
|
|
20
19
|
*/
|
|
21
20
|
export declare const GIT_ADD_TIMEOUT_MS: number;
|
|
22
21
|
/**
|
|
23
|
-
* Resolved timeout for each chunk of the chunked fallback path.
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
* workflow.
|
|
22
|
+
* Resolved timeout for each chunk of the chunked fallback path. Generous by
|
|
23
|
+
* design: the fallback is already the last line of defence before aborting,
|
|
24
|
+
* so erring toward "complete the indexing" over "fail fast" matches the
|
|
25
|
+
* real-world recovery workflow.
|
|
28
26
|
*/
|
|
29
27
|
export declare const GIT_ADD_CHUNK_TIMEOUT_MS: number;
|
|
30
28
|
/**
|
|
@@ -4,10 +4,9 @@ import { exec, executableExists } from '../utils/process.js';
|
|
|
4
4
|
import { readOnlyGitIndexEnv } from './git-readonly-index.js';
|
|
5
5
|
/**
|
|
6
6
|
* Environment variable that overrides the monolithic `git add -A` timeout
|
|
7
|
-
* (milliseconds).
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
* them retry without recompiling.
|
|
7
|
+
* (milliseconds). Operators on slow or loaded filesystems can legitimately
|
|
8
|
+
* exceed the 10-minute default during a baseline indexing pass; making the
|
|
9
|
+
* cap overridable lets them retry without recompiling.
|
|
11
10
|
*/
|
|
12
11
|
export const GIT_ADD_TIMEOUT_ENV_VAR = 'FIREFORGE_GIT_ADD_TIMEOUT_MS';
|
|
13
12
|
/**
|
|
@@ -37,11 +36,10 @@ function resolveTimeoutFromEnv(envVar, fallbackMs) {
|
|
|
37
36
|
*/
|
|
38
37
|
export const GIT_ADD_TIMEOUT_MS = resolveTimeoutFromEnv(GIT_ADD_TIMEOUT_ENV_VAR, DEFAULT_GIT_ADD_TIMEOUT_MS);
|
|
39
38
|
/**
|
|
40
|
-
* Resolved timeout for each chunk of the chunked fallback path.
|
|
41
|
-
*
|
|
42
|
-
*
|
|
43
|
-
*
|
|
44
|
-
* workflow.
|
|
39
|
+
* Resolved timeout for each chunk of the chunked fallback path. Generous by
|
|
40
|
+
* design: the fallback is already the last line of defence before aborting,
|
|
41
|
+
* so erring toward "complete the indexing" over "fail fast" matches the
|
|
42
|
+
* real-world recovery workflow.
|
|
45
43
|
*/
|
|
46
44
|
export const GIT_ADD_CHUNK_TIMEOUT_MS = resolveTimeoutFromEnv(GIT_ADD_CHUNK_TIMEOUT_ENV_VAR, DEFAULT_GIT_ADD_CHUNK_TIMEOUT_MS);
|
|
47
45
|
/**
|
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Gets the diff for a specific file.
|
|
3
|
+
*
|
|
4
|
+
* `--binary` is load-bearing: without it git degrades a binary file's section
|
|
5
|
+
* to the informational `Binary files a/x and b/x differ`, which carries none
|
|
6
|
+
* of the bytes and cannot be replayed by `git apply`. It only expands the
|
|
7
|
+
* BINARY section's index line to full hashes (text sections keep their
|
|
8
|
+
* abbreviated form), so text output stays byte-identical.
|
|
3
9
|
* @param repoDir - Repository directory
|
|
4
10
|
* @param filePath - Path to the file (relative to repo)
|
|
5
11
|
* @returns Diff content
|
|
@@ -32,22 +38,27 @@ export declare function generateFullFilePatch(repoDir: string, filePath: string)
|
|
|
32
38
|
export declare function generateModificationDiff(repoDir: string, filePath: string, baseContent: string): Promise<string>;
|
|
33
39
|
/**
|
|
34
40
|
* Gets the diff for all modified files, including untracked (new) files.
|
|
41
|
+
*
|
|
42
|
+
* Tracked binary files round-trip through `git diff --binary`; untracked ones
|
|
43
|
+
* go through {@link generateBinaryFilePatch} below. Both arms must stay
|
|
44
|
+
* binary-aware — see {@link getFileDiff} for why.
|
|
35
45
|
* @param repoDir - Repository directory
|
|
36
46
|
* @returns Diff content
|
|
37
47
|
*/
|
|
38
48
|
export declare function getAllDiff(repoDir: string): Promise<string>;
|
|
39
49
|
/**
|
|
40
50
|
* Builds a combined diff against HEAD for the provided files without touching
|
|
41
|
-
* the real git index. Tracked files use `git diff HEAD
|
|
42
|
-
* synthesized new-file diffs
|
|
51
|
+
* the real git index. Tracked files use `git diff --binary HEAD` (binary
|
|
52
|
+
* sections included); untracked files use synthesized new-file diffs, or
|
|
53
|
+
* {@link generateBinaryFilePatch} when the file is binary.
|
|
54
|
+
*
|
|
55
|
+
* Performance: the work is batched into a handful of `git` invocations (one
|
|
56
|
+
* `ls-tree` to classify, one `diff` over all tracked files, one `hash-object`
|
|
57
|
+
* over all new text files) rather than ~2 spawns per file, which dominates
|
|
58
|
+
* the cold-run cost on a Firefox-sized checkout. Binary, directory, and
|
|
59
|
+
* recursion paths stay per-file because they are rare and (for binary)
|
|
60
|
+
* mutate the index.
|
|
43
61
|
*
|
|
44
|
-
* Performance: the work is batched into a handful of `git` invocations
|
|
45
|
-
* (one `ls-tree` to classify, one `diff` over all tracked files, one
|
|
46
|
-
* `hash-object` over all new text files) rather than the ~2 spawns per file the
|
|
47
|
-
* previous per-file loop issued — that fan-out dominated the cold-run cost on a
|
|
48
|
-
* Firefox-sized checkout (~700 serial spawns, ~99s). Binary, directory, and
|
|
49
|
-
* recursion paths stay per-file because they are rare and (for binary) mutate
|
|
50
|
-
* the index.
|
|
51
62
|
* @param repoDir - Repository directory
|
|
52
63
|
* @param files - File paths to diff (relative to repo root)
|
|
53
64
|
* @returns Combined diff content
|
|
@@ -9,17 +9,24 @@ import { verbose } from '../utils/logger.js';
|
|
|
9
9
|
import { exec } from '../utils/process.js';
|
|
10
10
|
import { chunkPathspecs, ensureGit, git } from './git-base.js';
|
|
11
11
|
import { fileExistsInHead, hashObjectBatch, isBinaryFile, listTrackedInHead, } from './git-file-ops.js';
|
|
12
|
-
import { readOnlyGitIndexEnv } from './git-readonly-index.js';
|
|
12
|
+
import { mintDisposableGitIndex, readOnlyGitIndexEnv } from './git-readonly-index.js';
|
|
13
13
|
import { getUntrackedFiles, getUntrackedFilesInDir } from './git-status.js';
|
|
14
|
-
async function execGitWithAllowedExitCodes(repoDir, args, allowedExitCodes = [0]) {
|
|
14
|
+
async function execGitWithAllowedExitCodes(repoDir, args, allowedExitCodes = [0], envOverride) {
|
|
15
15
|
// Honour a read-only command's private-index scope: the `--intent-to-add`
|
|
16
16
|
// / `update-index` staging dance below is a genuine
|
|
17
17
|
// index write, and inside a read-only command it must land on the
|
|
18
18
|
// private index, not the primary checkout's.
|
|
19
|
+
//
|
|
20
|
+
// `envOverride` wins over that scope: a caller that minted an index for
|
|
21
|
+
// one specific invocation has said something more specific than the
|
|
22
|
+
// ambient scope did.
|
|
19
23
|
const readOnlyIndexEnv = readOnlyGitIndexEnv(repoDir);
|
|
24
|
+
const env = readOnlyIndexEnv !== undefined || envOverride !== undefined
|
|
25
|
+
? { ...readOnlyIndexEnv, ...envOverride }
|
|
26
|
+
: undefined;
|
|
20
27
|
const result = await exec('git', args, {
|
|
21
28
|
cwd: repoDir,
|
|
22
|
-
...(
|
|
29
|
+
...(env !== undefined ? { env } : {}),
|
|
23
30
|
});
|
|
24
31
|
if (allowedExitCodes.includes(result.exitCode)) {
|
|
25
32
|
return result;
|
|
@@ -28,13 +35,19 @@ async function execGitWithAllowedExitCodes(repoDir, args, allowedExitCodes = [0]
|
|
|
28
35
|
}
|
|
29
36
|
/**
|
|
30
37
|
* Gets the diff for a specific file.
|
|
38
|
+
*
|
|
39
|
+
* `--binary` is load-bearing: without it git degrades a binary file's section
|
|
40
|
+
* to the informational `Binary files a/x and b/x differ`, which carries none
|
|
41
|
+
* of the bytes and cannot be replayed by `git apply`. It only expands the
|
|
42
|
+
* BINARY section's index line to full hashes (text sections keep their
|
|
43
|
+
* abbreviated form), so text output stays byte-identical.
|
|
31
44
|
* @param repoDir - Repository directory
|
|
32
45
|
* @param filePath - Path to the file (relative to repo)
|
|
33
46
|
* @returns Diff content
|
|
34
47
|
*/
|
|
35
48
|
export async function getFileDiff(repoDir, filePath) {
|
|
36
49
|
await ensureGit();
|
|
37
|
-
return git(['diff', 'HEAD', '--', filePath], repoDir);
|
|
50
|
+
return git(['diff', '--binary', 'HEAD', '--', filePath], repoDir);
|
|
38
51
|
}
|
|
39
52
|
/**
|
|
40
53
|
* Abbreviates a full git blob hash to the 10-character form used in the
|
|
@@ -51,13 +64,14 @@ function abbreviateBlobHash(fullHash) {
|
|
|
51
64
|
return '0000000000';
|
|
52
65
|
}
|
|
53
66
|
/**
|
|
54
|
-
* Pure formatter for a new (untracked) file's unified diff.
|
|
55
|
-
*
|
|
56
|
-
* {@link
|
|
57
|
-
*
|
|
58
|
-
*
|
|
59
|
-
*
|
|
60
|
-
*
|
|
67
|
+
* Pure formatter for a new (untracked) file's unified diff. Shared by the
|
|
68
|
+
* batched cold-run path in {@link getDiffForFilesAgainstHead} and the
|
|
69
|
+
* standalone {@link generateNewFileDiff} — the only thing that differs is
|
|
70
|
+
* where `blobHash` comes from (a single batched `git hash-object` vs a
|
|
71
|
+
* per-file one), never the formatting. Preserves the empty-file form, the
|
|
72
|
+
* trailing-newline handling, and the "No newline at end of file" marker
|
|
73
|
+
* byte-for-byte.
|
|
74
|
+
*
|
|
61
75
|
* @param filePath - Path to the file (relative to repo)
|
|
62
76
|
* @param content - File content
|
|
63
77
|
* @param blobHash - Abbreviated blob hash for the index line
|
|
@@ -106,12 +120,10 @@ function buildNewFileDiffBody(filePath, content, blobHash) {
|
|
|
106
120
|
*/
|
|
107
121
|
export async function generateNewFileDiff(repoDir, filePath) {
|
|
108
122
|
const fullPath = join(repoDir, filePath);
|
|
109
|
-
// Defensive check: a directory here means a caller bypassed the
|
|
110
|
-
//
|
|
111
|
-
//
|
|
112
|
-
//
|
|
113
|
-
// recurring bug class (see the belt-and-suspenders note in
|
|
114
|
-
// `getDiffForFilesAgainstHead`).
|
|
123
|
+
// Defensive check: a directory here means a caller bypassed the expansion
|
|
124
|
+
// layers and handed the leaf reader a path it cannot read. Surface it with
|
|
125
|
+
// an actionable message naming the offending path rather than the raw
|
|
126
|
+
// `EISDIR` that `readText` would throw.
|
|
115
127
|
const fileStat = await stat(fullPath);
|
|
116
128
|
if (fileStat.isDirectory()) {
|
|
117
129
|
throw new GitError(`expected a file but found a directory at '${filePath}' — caller must expand directory entries before diffing`, `hash-object ${filePath}`);
|
|
@@ -199,22 +211,65 @@ export async function generateModificationDiff(repoDir, filePath, baseContent) {
|
|
|
199
211
|
}
|
|
200
212
|
/**
|
|
201
213
|
* Gets the diff for all modified files, including untracked (new) files.
|
|
214
|
+
*
|
|
215
|
+
* Tracked binary files round-trip through `git diff --binary`; untracked ones
|
|
216
|
+
* go through {@link generateBinaryFilePatch} below. Both arms must stay
|
|
217
|
+
* binary-aware — see {@link getFileDiff} for why.
|
|
202
218
|
* @param repoDir - Repository directory
|
|
203
219
|
* @returns Diff content
|
|
204
220
|
*/
|
|
205
221
|
export async function getAllDiff(repoDir) {
|
|
206
222
|
await ensureGit();
|
|
207
223
|
// Get diff for tracked files
|
|
208
|
-
const trackedDiff = await git(['diff', 'HEAD'], repoDir);
|
|
224
|
+
const trackedDiff = await git(['diff', '--binary', 'HEAD'], repoDir);
|
|
209
225
|
// Get untracked files (properly expanded, not directories)
|
|
210
226
|
const untrackedFiles = await getUntrackedFiles(repoDir);
|
|
211
|
-
//
|
|
227
|
+
// Classify first. `isBinaryFile` reads the file's first 8 KB directly and
|
|
228
|
+
// spawns nothing, so the only per-file process in this loop is the
|
|
229
|
+
// `git hash-object` inside `generateNewFileDiff` — one spawn per untracked
|
|
230
|
+
// TEXT file, uncapped, against a Firefox tree where "untracked" can mean a
|
|
231
|
+
// very large number. Hence classify → one batched hash → render.
|
|
232
|
+
//
|
|
233
|
+
// Everything else here is deliberately untouched: `git diff HEAD` (with
|
|
234
|
+
// renames, unlike the `--no-renames` scoped sibling), the `ls-files`
|
|
235
|
+
// ordering, tracked-block-first emission, and the `'\n'` empty-result
|
|
236
|
+
// sentinel are all observable. `getAllDiff`'s output is SHA-256'd into
|
|
237
|
+
// every tree fingerprint (tree-store.ts) and written verbatim into `.patch`
|
|
238
|
+
// files (export-all.ts), so its bytes are a contract.
|
|
239
|
+
const binaryFiles = [];
|
|
240
|
+
const textFiles = [];
|
|
241
|
+
for (const file of untrackedFiles) {
|
|
242
|
+
if (await isBinaryFile(repoDir, file)) {
|
|
243
|
+
binaryFiles.push(file);
|
|
244
|
+
}
|
|
245
|
+
else {
|
|
246
|
+
textFiles.push(file);
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
const textHashes = await hashObjectBatch(repoDir, textFiles.map((file) => join(repoDir, file)));
|
|
250
|
+
// Binary patches stage into the index and must stay serial; text patches
|
|
251
|
+
// are pure formatting over the already-batched hashes.
|
|
252
|
+
const binaryDiffs = new Map();
|
|
253
|
+
for (const file of binaryFiles) {
|
|
254
|
+
binaryDiffs.set(file, await generateBinaryFilePatch(repoDir, file));
|
|
255
|
+
}
|
|
212
256
|
const untrackedDiffs = [];
|
|
213
257
|
for (const file of untrackedFiles) {
|
|
214
|
-
const
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
258
|
+
const binary = binaryDiffs.get(file);
|
|
259
|
+
if (binary !== undefined) {
|
|
260
|
+
untrackedDiffs.push(binary);
|
|
261
|
+
continue;
|
|
262
|
+
}
|
|
263
|
+
const fullPath = join(repoDir, file);
|
|
264
|
+
// Same defensive directory check `generateNewFileDiff` carries: a
|
|
265
|
+
// directory here means a caller bypassed the expansion layers, and its
|
|
266
|
+
// comment records this as a recurring bug class.
|
|
267
|
+
const fileStat = await stat(fullPath);
|
|
268
|
+
if (fileStat.isDirectory()) {
|
|
269
|
+
throw new GitError(`expected a file but found a directory at '${file}' — caller must expand directory entries before diffing`, `hash-object ${file}`);
|
|
270
|
+
}
|
|
271
|
+
const content = await readText(fullPath);
|
|
272
|
+
untrackedDiffs.push(buildNewFileDiffBody(file, content, abbreviateBlobHash(textHashes.get(fullPath))));
|
|
218
273
|
}
|
|
219
274
|
// Combine all diffs — each already ends with \n, so concatenate directly
|
|
220
275
|
// to avoid inserting blank lines between diff sections.
|
|
@@ -249,9 +304,15 @@ function splitDiffSections(combined) {
|
|
|
249
304
|
return sections;
|
|
250
305
|
}
|
|
251
306
|
/**
|
|
252
|
-
* Runs one `git diff --no-renames HEAD` over the tracked files
|
|
253
|
-
* ARG_MAX) and returns a `Map<path, section>` whose sections are
|
|
254
|
-
* to the per-file `git diff HEAD -- <file>` they
|
|
307
|
+
* Runs one `git diff --binary --no-renames HEAD` over the tracked files
|
|
308
|
+
* (chunked under ARG_MAX) and returns a `Map<path, section>` whose sections are
|
|
309
|
+
* byte-identical to the per-file `git diff --binary HEAD -- <file>` they
|
|
310
|
+
* replace.
|
|
311
|
+
*
|
|
312
|
+
* `--binary` is load-bearing: a tracked binary file would otherwise degrade to
|
|
313
|
+
* the un-appliable `Binary files a/x and b/x differ` stub. It expands only the
|
|
314
|
+
* binary section's index line to full hashes, so text sections are unaffected
|
|
315
|
+
* — see {@link getFileDiff}.
|
|
255
316
|
*
|
|
256
317
|
* `--no-renames` is load-bearing: a multi-path diff under a user's
|
|
257
318
|
* `diff.renames=true`/`=copies` could otherwise emit a single 2-path rename
|
|
@@ -274,7 +335,7 @@ function splitDiffSections(combined) {
|
|
|
274
335
|
async function buildTrackedSections(repoDir, trackedFiles) {
|
|
275
336
|
const sectionsByPath = new Map();
|
|
276
337
|
for (const chunk of chunkPathspecs(trackedFiles)) {
|
|
277
|
-
const combined = await git(['diff', '--no-renames', 'HEAD', '--', ...chunk], repoDir);
|
|
338
|
+
const combined = await git(['diff', '--binary', '--no-renames', 'HEAD', '--', ...chunk], repoDir);
|
|
278
339
|
const namesOutput = await git(['diff', '--no-renames', 'HEAD', '-z', '--name-only', '--', ...chunk], repoDir);
|
|
279
340
|
const names = namesOutput.split('\0').filter((name) => name.length > 0);
|
|
280
341
|
const sections = splitDiffSections(combined);
|
|
@@ -299,16 +360,17 @@ async function buildTrackedSections(repoDir, trackedFiles) {
|
|
|
299
360
|
}
|
|
300
361
|
/**
|
|
301
362
|
* Builds a combined diff against HEAD for the provided files without touching
|
|
302
|
-
* the real git index. Tracked files use `git diff HEAD
|
|
303
|
-
* synthesized new-file diffs
|
|
363
|
+
* the real git index. Tracked files use `git diff --binary HEAD` (binary
|
|
364
|
+
* sections included); untracked files use synthesized new-file diffs, or
|
|
365
|
+
* {@link generateBinaryFilePatch} when the file is binary.
|
|
366
|
+
*
|
|
367
|
+
* Performance: the work is batched into a handful of `git` invocations (one
|
|
368
|
+
* `ls-tree` to classify, one `diff` over all tracked files, one `hash-object`
|
|
369
|
+
* over all new text files) rather than ~2 spawns per file, which dominates
|
|
370
|
+
* the cold-run cost on a Firefox-sized checkout. Binary, directory, and
|
|
371
|
+
* recursion paths stay per-file because they are rare and (for binary)
|
|
372
|
+
* mutate the index.
|
|
304
373
|
*
|
|
305
|
-
* Performance: the work is batched into a handful of `git` invocations
|
|
306
|
-
* (one `ls-tree` to classify, one `diff` over all tracked files, one
|
|
307
|
-
* `hash-object` over all new text files) rather than the ~2 spawns per file the
|
|
308
|
-
* previous per-file loop issued — that fan-out dominated the cold-run cost on a
|
|
309
|
-
* Firefox-sized checkout (~700 serial spawns, ~99s). Binary, directory, and
|
|
310
|
-
* recursion paths stay per-file because they are rare and (for binary) mutate
|
|
311
|
-
* the index.
|
|
312
374
|
* @param repoDir - Repository directory
|
|
313
375
|
* @param files - File paths to diff (relative to repo root)
|
|
314
376
|
* @returns Combined diff content
|
|
@@ -318,12 +380,10 @@ export async function getDiffForFilesAgainstHead(repoDir, files) {
|
|
|
318
380
|
// Expand any directory entries (paths ending with `/`) into their
|
|
319
381
|
// individual untracked files before diffing. `git status --porcelain=v1`
|
|
320
382
|
// reports collapsed untracked directories as `?? dir/`, and every caller
|
|
321
|
-
// that feeds the aggregate working-tree state into this function must
|
|
322
|
-
//
|
|
323
|
-
//
|
|
324
|
-
//
|
|
325
|
-
// site re-introduced the bug in 0.17.0 — guarding here makes the
|
|
326
|
-
// regression impossible at this layer.
|
|
383
|
+
// that feeds the aggregate working-tree state into this function must not
|
|
384
|
+
// trigger an EISDIR when the diff pass reads `dir/` as if it were a file.
|
|
385
|
+
// The caller-side expansion in `lint.ts` and `export-all.ts` covers the
|
|
386
|
+
// common path; guarding here makes a single bad call site harmless.
|
|
327
387
|
const expandedFiles = [];
|
|
328
388
|
for (const file of files) {
|
|
329
389
|
if (file.endsWith('/')) {
|
|
@@ -357,15 +417,13 @@ export async function getDiffForFilesAgainstHead(repoDir, files) {
|
|
|
357
417
|
if (!(await pathExists(fullPath))) {
|
|
358
418
|
continue;
|
|
359
419
|
}
|
|
360
|
-
// Second defence against
|
|
361
|
-
//
|
|
362
|
-
//
|
|
363
|
-
//
|
|
364
|
-
//
|
|
365
|
-
//
|
|
366
|
-
//
|
|
367
|
-
// loud when the directory has no readable content rather than
|
|
368
|
-
// silently skipping it.
|
|
420
|
+
// Second defence against EISDIR: a non-HEAD path that exists on disk is
|
|
421
|
+
// usually a new file, but can also be a directory that arrived without
|
|
422
|
+
// the trailing slash `expandUntrackedDirectoryEntries` would have
|
|
423
|
+
// produced (caller stripped it, submodule entry, tracked-file-replaced-
|
|
424
|
+
// by-dir). Expand it via the same helper used by the slash branch and
|
|
425
|
+
// recurse so each contained file is diffed individually; fail loud when
|
|
426
|
+
// the directory has no readable content rather than silently skipping it.
|
|
369
427
|
const fileStat = await stat(fullPath);
|
|
370
428
|
if (fileStat.isDirectory()) {
|
|
371
429
|
const innerFiles = await getUntrackedFilesInDir(repoDir, file);
|
|
@@ -427,7 +485,7 @@ export async function getDiffForFilesAgainstHead(repoDir, files) {
|
|
|
427
485
|
*/
|
|
428
486
|
export async function getStagedDiffForFiles(repoDir, files) {
|
|
429
487
|
await ensureGit();
|
|
430
|
-
return git(['diff', '--cached', 'HEAD', '--', ...files], repoDir);
|
|
488
|
+
return git(['diff', '--binary', '--cached', 'HEAD', '--', ...files], repoDir);
|
|
431
489
|
}
|
|
432
490
|
/**
|
|
433
491
|
* Serializes the index-mutating untracked-binary path. The bounded per-patch
|
|
@@ -465,18 +523,45 @@ export async function generateBinaryFilePatch(repoDir, filePath) {
|
|
|
465
523
|
]);
|
|
466
524
|
if (result.stdout.trim())
|
|
467
525
|
return result.stdout;
|
|
468
|
-
//
|
|
469
|
-
//
|
|
470
|
-
//
|
|
526
|
+
// The diff for an untracked file has to come from an index entry, so one
|
|
527
|
+
// has to be written. Writing it to a PRIVATE index is what keeps that
|
|
528
|
+
// write invisible: the primary `.git/index` never moves, so a concurrent
|
|
529
|
+
// `fireforge test` fingerprinting `engine/` with `git status` cannot
|
|
530
|
+
// observe the transient `--intent-to-add` entry and void its own verdict
|
|
531
|
+
// on our bookkeeping. That was a real failure mode — parallel gate lanes
|
|
532
|
+
// killed three runs with `FAIL reason=inconclusive` on branding PNGs
|
|
533
|
+
// flapping between `A` and `??`.
|
|
534
|
+
//
|
|
535
|
+
// Nothing is restored afterwards because nothing shared was changed, and
|
|
536
|
+
// no lock is taken because two concurrent callers get two indexes. Both
|
|
537
|
+
// the restore dance and the in-process lock survive below purely for the
|
|
538
|
+
// fallback, where the primary index really is the one being written.
|
|
539
|
+
const disposable = await mintDisposableGitIndex(repoDir);
|
|
540
|
+
if (disposable !== undefined) {
|
|
541
|
+
try {
|
|
542
|
+
await execGitWithAllowedExitCodes(repoDir, ['add', '--intent-to-add', '--', filePath], [0], disposable.env);
|
|
543
|
+
const diffResult = await execGitWithAllowedExitCodes(repoDir, ['diff', '--binary', '--', filePath], [0], disposable.env);
|
|
544
|
+
return diffResult.stdout;
|
|
545
|
+
}
|
|
546
|
+
finally {
|
|
547
|
+
await disposable.dispose();
|
|
548
|
+
}
|
|
549
|
+
}
|
|
550
|
+
// Fallback: no private index could be minted (a non-git directory, an
|
|
551
|
+
// unreadable index, no writable tmpdir). Degrading to the shared index is
|
|
552
|
+
// the pre-existing behaviour rather than a new risk, and refusing instead
|
|
553
|
+
// would fail an export over an optimisation. The stage/unstage pair
|
|
554
|
+
// mutates the index, so it must not interleave with another concurrent
|
|
555
|
+
// binary patch (see runWithBinaryStagingLock).
|
|
556
|
+
verbose(`Binary patch for ${filePath} is staging on the shared index (no private index).`);
|
|
471
557
|
return runWithBinaryStagingLock(async () => {
|
|
472
|
-
// Snapshot the path's exact index entry before touching it.
|
|
473
|
-
//
|
|
474
|
-
//
|
|
475
|
-
//
|
|
476
|
-
//
|
|
477
|
-
//
|
|
478
|
-
//
|
|
479
|
-
// instead makes the cleanup exact regardless of how the entry got there.
|
|
558
|
+
// Snapshot the path's exact index entry before touching it. A blanket
|
|
559
|
+
// `git reset HEAD -- <file>` cleanup restores the path to its HEAD state
|
|
560
|
+
// — for a path absent from HEAD that means *removing* whatever entry the
|
|
561
|
+
// index carried, silently discarding any staged state that arrived
|
|
562
|
+
// between the read-only diff above and this staging block (a concurrent
|
|
563
|
+
// writer, or a staged-add whose worktree file was deleted). Restoring
|
|
564
|
+
// the captured entry is exact regardless of how the entry got there.
|
|
480
565
|
const priorEntry = (await execGitWithAllowedExitCodes(repoDir, ['ls-files', '--stage', '--', filePath])).stdout;
|
|
481
566
|
try {
|
|
482
567
|
await execGitWithAllowedExitCodes(repoDir, ['add', '--intent-to-add', '--', filePath]);
|
|
@@ -31,17 +31,17 @@ export declare function unstageFiles(repoDir: string, files: string[]): Promise<
|
|
|
31
31
|
*/
|
|
32
32
|
export declare function fileExistsInHead(repoDir: string, filePath: string): Promise<boolean>;
|
|
33
33
|
/**
|
|
34
|
-
* Batched equivalent of {@link fileExistsInHead}: returns the subset of
|
|
35
|
-
* that are tracked in HEAD, using a single `git ls-tree` per ARG_MAX
|
|
36
|
-
* instead of one spawn per file. This is the cold-run hot path — a
|
|
37
|
-
* checkout has hundreds of affected files
|
|
38
|
-
*
|
|
34
|
+
* Batched equivalent of {@link fileExistsInHead}: returns the subset of
|
|
35
|
+
* `files` that are tracked in HEAD, using a single `git ls-tree` per ARG_MAX
|
|
36
|
+
* chunk instead of one spawn per file. This is the cold-run hot path — a
|
|
37
|
+
* Firefox-sized checkout has hundreds of affected files.
|
|
38
|
+
*
|
|
39
|
+
* `-r` lists nested blobs by full repo-relative path; `--name-only -z` makes
|
|
40
|
+
* the output a trivial NUL-split with no quoting to undo. Membership in the
|
|
41
|
+
* returned Set is exactly `await fileExistsInHead(repoDir, file)` for any
|
|
42
|
+
* non-directory `file`. Throws (via {@link git}) when HEAD itself is
|
|
43
|
+
* unresolvable, matching the per-file helper's failure mode.
|
|
39
44
|
*
|
|
40
|
-
* `-r` lists nested blobs by full repo-relative path; `--name-only -z` makes the
|
|
41
|
-
* output a trivial NUL-split with no quoting to undo. Membership in the returned
|
|
42
|
-
* Set is exactly `await fileExistsInHead(repoDir, file)` for any non-directory
|
|
43
|
-
* `file`. Throws (via {@link git}) when HEAD itself is unresolvable, matching the
|
|
44
|
-
* per-file helper's failure mode.
|
|
45
45
|
* @param repoDir - Repository directory
|
|
46
46
|
* @param files - Repo-relative paths to classify
|
|
47
47
|
* @returns The subset of `files` present in HEAD
|
|
@@ -55,15 +55,15 @@ export declare function listTrackedInHead(repoDir: string, files: string[]): Pro
|
|
|
55
55
|
*
|
|
56
56
|
* Uses {@link import('../utils/process.js').exec} rather than {@link git}
|
|
57
57
|
* (which throws on a non-zero exit) because `git hash-object f1 f2 …` is
|
|
58
|
-
* all-or-nothing: it aborts at the first unreadable path and emits nothing
|
|
59
|
-
* the rest. To
|
|
60
|
-
* only its own index line — a chunk that does not return exactly one hash
|
|
61
|
-
* input falls back to hashing that chunk's paths individually. A path
|
|
62
|
-
* still unhashable is
|
|
63
|
-
* `0000000000` zero-hash fallback
|
|
64
|
-
*
|
|
65
|
-
*
|
|
66
|
-
*
|
|
58
|
+
* all-or-nothing: it aborts at the first unreadable path and emits nothing
|
|
59
|
+
* for the rest. To keep the per-file contract — where one bad path zeroes
|
|
60
|
+
* only its own index line — a chunk that does not return exactly one hash
|
|
61
|
+
* per input falls back to hashing that chunk's paths individually. A path
|
|
62
|
+
* that is still unhashable is left out of the map; the caller applies the
|
|
63
|
+
* `0000000000` zero-hash fallback for any miss. Hashing stays in git rather
|
|
64
|
+
* than in-process so filters and `.gitattributes` are applied per path and
|
|
65
|
+
* the result cannot diverge under `core.autocrlf`/`text` attributes.
|
|
66
|
+
*
|
|
67
67
|
* @param repoDir - Repository directory
|
|
68
68
|
* @param fullPaths - Absolute file paths to hash
|
|
69
69
|
* @returns Map from each input path to its full blob hash (misses omitted)
|
|
@@ -88,17 +88,17 @@ export async function fileExistsInHead(repoDir, filePath) {
|
|
|
88
88
|
return (await git(['ls-tree', 'HEAD', '--', filePath], repoDir)).trim().length > 0;
|
|
89
89
|
}
|
|
90
90
|
/**
|
|
91
|
-
* Batched equivalent of {@link fileExistsInHead}: returns the subset of
|
|
92
|
-
* that are tracked in HEAD, using a single `git ls-tree` per ARG_MAX
|
|
93
|
-
* instead of one spawn per file. This is the cold-run hot path — a
|
|
94
|
-
* checkout has hundreds of affected files
|
|
95
|
-
*
|
|
91
|
+
* Batched equivalent of {@link fileExistsInHead}: returns the subset of
|
|
92
|
+
* `files` that are tracked in HEAD, using a single `git ls-tree` per ARG_MAX
|
|
93
|
+
* chunk instead of one spawn per file. This is the cold-run hot path — a
|
|
94
|
+
* Firefox-sized checkout has hundreds of affected files.
|
|
95
|
+
*
|
|
96
|
+
* `-r` lists nested blobs by full repo-relative path; `--name-only -z` makes
|
|
97
|
+
* the output a trivial NUL-split with no quoting to undo. Membership in the
|
|
98
|
+
* returned Set is exactly `await fileExistsInHead(repoDir, file)` for any
|
|
99
|
+
* non-directory `file`. Throws (via {@link git}) when HEAD itself is
|
|
100
|
+
* unresolvable, matching the per-file helper's failure mode.
|
|
96
101
|
*
|
|
97
|
-
* `-r` lists nested blobs by full repo-relative path; `--name-only -z` makes the
|
|
98
|
-
* output a trivial NUL-split with no quoting to undo. Membership in the returned
|
|
99
|
-
* Set is exactly `await fileExistsInHead(repoDir, file)` for any non-directory
|
|
100
|
-
* `file`. Throws (via {@link git}) when HEAD itself is unresolvable, matching the
|
|
101
|
-
* per-file helper's failure mode.
|
|
102
102
|
* @param repoDir - Repository directory
|
|
103
103
|
* @param files - Repo-relative paths to classify
|
|
104
104
|
* @returns The subset of `files` present in HEAD
|
|
@@ -129,15 +129,15 @@ export async function listTrackedInHead(repoDir, files) {
|
|
|
129
129
|
*
|
|
130
130
|
* Uses {@link import('../utils/process.js').exec} rather than {@link git}
|
|
131
131
|
* (which throws on a non-zero exit) because `git hash-object f1 f2 …` is
|
|
132
|
-
* all-or-nothing: it aborts at the first unreadable path and emits nothing
|
|
133
|
-
* the rest. To
|
|
134
|
-
* only its own index line — a chunk that does not return exactly one hash
|
|
135
|
-
* input falls back to hashing that chunk's paths individually. A path
|
|
136
|
-
* still unhashable is
|
|
137
|
-
* `0000000000` zero-hash fallback
|
|
138
|
-
*
|
|
139
|
-
*
|
|
140
|
-
*
|
|
132
|
+
* all-or-nothing: it aborts at the first unreadable path and emits nothing
|
|
133
|
+
* for the rest. To keep the per-file contract — where one bad path zeroes
|
|
134
|
+
* only its own index line — a chunk that does not return exactly one hash
|
|
135
|
+
* per input falls back to hashing that chunk's paths individually. A path
|
|
136
|
+
* that is still unhashable is left out of the map; the caller applies the
|
|
137
|
+
* `0000000000` zero-hash fallback for any miss. Hashing stays in git rather
|
|
138
|
+
* than in-process so filters and `.gitattributes` are applied per path and
|
|
139
|
+
* the result cannot diverge under `core.autocrlf`/`text` attributes.
|
|
140
|
+
*
|
|
141
141
|
* @param repoDir - Repository directory
|
|
142
142
|
* @param fullPaths - Absolute file paths to hash
|
|
143
143
|
* @returns Map from each input path to its full blob hash (misses omitted)
|