@hominis/fireforge 0.45.0 → 0.46.1
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 +409 -446
- package/dist/bin/fireforge.d.ts +1 -1
- package/dist/bin/fireforge.js +21 -15
- package/dist/build-info.json +4 -4
- package/dist/src/cli-usage-error.d.ts +46 -0
- package/dist/src/cli-usage-error.js +81 -0
- package/dist/src/cli.d.ts +7 -2
- package/dist/src/cli.js +47 -47
- package/dist/src/commands/bootstrap-checks.js +2 -1
- package/dist/src/commands/bootstrap.js +3 -4
- package/dist/src/commands/build.js +27 -17
- package/dist/src/commands/config.js +9 -9
- package/dist/src/commands/destructive-decision.d.ts +19 -0
- package/dist/src/commands/destructive-decision.js +31 -0
- package/dist/src/commands/discard.js +5 -5
- package/dist/src/commands/doctor-check-core.d.ts +4 -10
- package/dist/src/commands/doctor-check-core.js +0 -8
- package/dist/src/commands/doctor-external-toolchains.js +2 -2
- package/dist/src/commands/doctor-furnace-config-sync.d.ts +2 -2
- package/dist/src/commands/doctor-furnace-config-sync.js +20 -20
- package/dist/src/commands/doctor-furnace-jar.d.ts +1 -1
- package/dist/src/commands/doctor-furnace-jar.js +1 -1
- package/dist/src/commands/doctor-furnace.js +22 -22
- package/dist/src/commands/doctor-orphaned-harness.d.ts +10 -17
- package/dist/src/commands/doctor-orphaned-harness.js +14 -23
- package/dist/src/commands/doctor-patch-manifest.d.ts +2 -1
- package/dist/src/commands/doctor-patch-manifest.js +7 -6
- package/dist/src/commands/doctor-post-rebase-audit.js +3 -3
- package/dist/src/commands/doctor-source-pin.d.ts +12 -12
- package/dist/src/commands/doctor-source-pin.js +14 -14
- package/dist/src/commands/doctor-working-tree.d.ts +3 -3
- package/dist/src/commands/doctor-working-tree.js +3 -3
- package/dist/src/commands/doctor.d.ts +3 -1
- package/dist/src/commands/doctor.js +15 -16
- package/dist/src/commands/download.js +50 -37
- package/dist/src/commands/export-all.js +29 -12
- package/dist/src/commands/export-flow.d.ts +5 -5
- package/dist/src/commands/export-flow.js +29 -59
- package/dist/src/commands/export-placement-conflicts.d.ts +3 -3
- package/dist/src/commands/export-placement-conflicts.js +12 -12
- package/dist/src/commands/export-placement-gate.d.ts +2 -2
- package/dist/src/commands/export-placement-gate.js +7 -13
- package/dist/src/commands/export-placement-policy.d.ts +1 -1
- package/dist/src/commands/export-placement-policy.js +4 -6
- package/dist/src/commands/export-shared.d.ts +51 -32
- package/dist/src/commands/export-shared.js +17 -32
- package/dist/src/commands/export.js +14 -5
- package/dist/src/commands/furnace/apply.js +16 -16
- package/dist/src/commands/furnace/authoring-config.d.ts +13 -0
- package/dist/src/commands/furnace/authoring-config.js +19 -0
- package/dist/src/commands/furnace/chrome-doc-remove.d.ts +1 -1
- package/dist/src/commands/furnace/chrome-doc-remove.js +2 -2
- package/dist/src/commands/furnace/chrome-doc-templates.d.ts +14 -14
- package/dist/src/commands/furnace/chrome-doc-templates.js +17 -17
- package/dist/src/commands/furnace/chrome-doc-tests.d.ts +2 -2
- package/dist/src/commands/furnace/chrome-doc-tests.js +4 -4
- package/dist/src/commands/furnace/chrome-doc.d.ts +8 -8
- package/dist/src/commands/furnace/chrome-doc.js +18 -18
- package/dist/src/commands/furnace/create-browser-test.d.ts +1 -1
- package/dist/src/commands/furnace/create-browser-test.js +7 -12
- package/dist/src/commands/furnace/create-dry-run.d.ts +4 -4
- package/dist/src/commands/furnace/create-dry-run.js +6 -9
- package/dist/src/commands/furnace/create-features.d.ts +2 -2
- package/dist/src/commands/furnace/create-features.js +2 -2
- package/dist/src/commands/furnace/create-mochikit.d.ts +4 -4
- package/dist/src/commands/furnace/create-mochikit.js +7 -7
- package/dist/src/commands/furnace/create-templates.d.ts +31 -15
- package/dist/src/commands/furnace/create-templates.js +20 -19
- package/dist/src/commands/furnace/create-xpcshell.d.ts +5 -5
- package/dist/src/commands/furnace/create-xpcshell.js +8 -8
- package/dist/src/commands/furnace/create.d.ts +1 -1
- package/dist/src/commands/furnace/create.js +35 -29
- package/dist/src/commands/furnace/deploy.js +15 -6
- package/dist/src/commands/furnace/diff.js +7 -7
- package/dist/src/commands/furnace/index.js +1 -1
- package/dist/src/commands/furnace/init.js +17 -16
- package/dist/src/commands/furnace/list.js +2 -2
- package/dist/src/commands/furnace/override.d.ts +1 -1
- package/dist/src/commands/furnace/override.js +43 -34
- package/dist/src/commands/furnace/preview.js +17 -17
- package/dist/src/commands/furnace/refresh.js +15 -7
- package/dist/src/commands/furnace/remove-mutations.d.ts +9 -10
- package/dist/src/commands/furnace/remove-mutations.js +19 -19
- package/dist/src/commands/furnace/remove-state.d.ts +1 -1
- package/dist/src/commands/furnace/remove-state.js +1 -1
- package/dist/src/commands/furnace/remove.js +4 -8
- package/dist/src/commands/furnace/rename-browser-test.js +10 -15
- package/dist/src/commands/furnace/rename-xpcshell.d.ts +2 -2
- package/dist/src/commands/furnace/rename-xpcshell.js +3 -3
- package/dist/src/commands/furnace/rename.js +36 -36
- package/dist/src/commands/furnace/scan.js +3 -3
- package/dist/src/commands/furnace/status.js +19 -16
- package/dist/src/commands/furnace/sync.js +6 -6
- package/dist/src/commands/furnace/test-file-name.d.ts +28 -0
- package/dist/src/commands/furnace/test-file-name.js +39 -0
- package/dist/src/commands/furnace/validate.js +11 -12
- package/dist/src/commands/furnace/validation-output.d.ts +21 -9
- package/dist/src/commands/furnace/validation-output.js +3 -8
- package/dist/src/commands/import.js +22 -29
- package/dist/src/commands/lint-per-patch.d.ts +2 -2
- package/dist/src/commands/lint-per-patch.js +27 -12
- package/dist/src/commands/lint-per-run-checkjs.d.ts +14 -15
- package/dist/src/commands/lint-per-run-checkjs.js +14 -15
- package/dist/src/commands/lint-report.d.ts +3 -3
- package/dist/src/commands/lint-report.js +4 -4
- package/dist/src/commands/lint.d.ts +5 -4
- package/dist/src/commands/lint.js +36 -36
- package/dist/src/commands/manifest.d.ts +4 -4
- package/dist/src/commands/manifest.js +1 -1
- package/dist/src/commands/package.js +4 -6
- package/dist/src/commands/patch/compact.d.ts +2 -2
- package/dist/src/commands/patch/compact.js +19 -20
- package/dist/src/commands/patch/delete.d.ts +1 -1
- package/dist/src/commands/patch/delete.js +23 -33
- package/dist/src/commands/patch/entry-projection.d.ts +13 -0
- package/dist/src/commands/patch/entry-projection.js +24 -0
- package/dist/src/commands/patch/lint-ignore.d.ts +3 -12
- package/dist/src/commands/patch/lint-ignore.js +33 -44
- package/dist/src/commands/patch/move-files-create.d.ts +2 -2
- package/dist/src/commands/patch/move-files-create.js +29 -15
- package/dist/src/commands/patch/move-files-into.d.ts +2 -2
- package/dist/src/commands/patch/move-files-into.js +41 -37
- package/dist/src/commands/patch/move-files.js +5 -14
- package/dist/src/commands/patch/patch-context.d.ts +1 -1
- package/dist/src/commands/patch/rename.d.ts +4 -4
- package/dist/src/commands/patch/rename.js +35 -49
- package/dist/src/commands/patch/reorder.js +35 -48
- package/dist/src/commands/patch/split-plan.d.ts +7 -8
- package/dist/src/commands/patch/split-plan.js +10 -13
- package/dist/src/commands/patch/split.d.ts +2 -2
- package/dist/src/commands/patch/split.js +50 -48
- package/dist/src/commands/patch/staged-dependency-validate.d.ts +1 -1
- package/dist/src/commands/patch/staged-dependency-validate.js +3 -3
- package/dist/src/commands/patch/staged-dependency.d.ts +1 -1
- package/dist/src/commands/patch/staged-dependency.js +22 -28
- package/dist/src/commands/patch/tier.d.ts +2 -2
- package/dist/src/commands/patch/tier.js +20 -30
- package/dist/src/commands/patch-rename-map.d.ts +19 -0
- package/dist/src/commands/patch-rename-map.js +36 -0
- package/dist/src/commands/pending-resolution.d.ts +15 -0
- package/dist/src/commands/pending-resolution.js +25 -0
- package/dist/src/commands/re-export-adjacent.d.ts +25 -3
- package/dist/src/commands/re-export-adjacent.js +40 -24
- package/dist/src/commands/re-export-bulk-scan.d.ts +3 -3
- package/dist/src/commands/re-export-bulk-scan.js +23 -27
- package/dist/src/commands/re-export-drift.d.ts +10 -10
- package/dist/src/commands/re-export-drift.js +33 -33
- package/dist/src/commands/re-export-files.d.ts +2 -3
- package/dist/src/commands/re-export-files.js +52 -44
- package/dist/src/commands/re-export-lint.d.ts +29 -30
- package/dist/src/commands/re-export-lint.js +36 -29
- package/dist/src/commands/re-export-options.d.ts +1 -1
- package/dist/src/commands/re-export-options.js +1 -1
- package/dist/src/commands/re-export-register.d.ts +1 -1
- package/dist/src/commands/re-export-register.js +1 -1
- package/dist/src/commands/re-export-scan.d.ts +1 -1
- package/dist/src/commands/re-export-scan.js +12 -9
- package/dist/src/commands/re-export-single.d.ts +23 -4
- package/dist/src/commands/re-export-single.js +39 -31
- package/dist/src/commands/re-export.js +35 -17
- package/dist/src/commands/rebase/abort.js +9 -14
- package/dist/src/commands/rebase/continue.js +20 -19
- package/dist/src/commands/rebase/index.d.ts +1 -1
- package/dist/src/commands/rebase/index.js +5 -5
- package/dist/src/commands/rebase/patch-loop.d.ts +2 -2
- package/dist/src/commands/rebase/patch-loop.js +20 -24
- package/dist/src/commands/register.js +5 -5
- package/dist/src/commands/reset.js +1 -1
- package/dist/src/commands/resolve.d.ts +2 -2
- package/dist/src/commands/resolve.js +21 -13
- package/dist/src/commands/run.d.ts +0 -13
- package/dist/src/commands/run.js +38 -51
- package/dist/src/commands/setup-support.d.ts +16 -4
- package/dist/src/commands/setup-support.js +20 -20
- package/dist/src/commands/setup.js +4 -10
- package/dist/src/commands/source.js +9 -2
- package/dist/src/commands/status-check.d.ts +3 -3
- package/dist/src/commands/status-check.js +6 -6
- package/dist/src/commands/status-json.d.ts +14 -13
- package/dist/src/commands/status-json.js +9 -8
- package/dist/src/commands/status-output.d.ts +3 -3
- package/dist/src/commands/status-output.js +5 -5
- package/dist/src/commands/status-ownership.d.ts +3 -3
- package/dist/src/commands/status-ownership.js +3 -3
- package/dist/src/commands/status.js +25 -26
- package/dist/src/commands/test-build-phase.d.ts +3 -3
- package/dist/src/commands/test-build-phase.js +48 -24
- package/dist/src/commands/test-diagnose.d.ts +1 -1
- package/dist/src/commands/test-diagnose.js +20 -20
- package/dist/src/commands/test-modes.d.ts +4 -4
- package/dist/src/commands/test-modes.js +4 -5
- package/dist/src/commands/test-register.js +5 -3
- package/dist/src/commands/test-run.d.ts +11 -11
- package/dist/src/commands/test-run.js +40 -33
- package/dist/src/commands/test-stale-gate.d.ts +12 -12
- package/dist/src/commands/test-stale-gate.js +17 -17
- package/dist/src/commands/test-verdict.d.ts +19 -5
- package/dist/src/commands/test-verdict.js +26 -11
- package/dist/src/commands/test.d.ts +3 -3
- package/dist/src/commands/test.js +73 -36
- package/dist/src/commands/token-coverage.js +3 -3
- package/dist/src/commands/token-list.d.ts +26 -0
- package/dist/src/commands/token-list.js +153 -0
- package/dist/src/commands/token.js +26 -10
- package/dist/src/commands/tree.js +26 -21
- package/dist/src/commands/typecheck.d.ts +6 -6
- package/dist/src/commands/typecheck.js +16 -16
- package/dist/src/commands/verify.d.ts +3 -3
- package/dist/src/commands/verify.js +10 -10
- package/dist/src/commands/watch.js +11 -11
- package/dist/src/commands/wire.js +17 -16
- package/dist/src/core/ast-utils.d.ts +7 -7
- package/dist/src/core/ast-utils.js +8 -8
- package/dist/src/core/branding.d.ts +5 -12
- package/dist/src/core/branding.js +6 -5
- package/dist/src/core/browser-wire.d.ts +1 -1
- package/dist/src/core/browser-wire.js +10 -7
- package/dist/src/core/build-audit-platform.d.ts +32 -3
- package/dist/src/core/build-audit-platform.js +153 -13
- package/dist/src/core/build-audit-registration.d.ts +5 -5
- package/dist/src/core/build-audit-registration.js +10 -9
- package/dist/src/core/build-audit-resolve.d.ts +5 -5
- package/dist/src/core/build-audit-resolve.js +6 -6
- package/dist/src/core/build-audit-skip.d.ts +57 -0
- package/dist/src/core/build-audit-skip.js +112 -0
- package/dist/src/core/build-audit-transforms.d.ts +2 -2
- package/dist/src/core/build-audit-transforms.js +3 -3
- package/dist/src/core/build-audit.d.ts +21 -8
- package/dist/src/core/build-audit.js +142 -40
- package/dist/src/core/build-baseline-types.d.ts +19 -18
- package/dist/src/core/build-baseline-types.js +1 -1
- package/dist/src/core/build-baseline.d.ts +48 -31
- package/dist/src/core/build-baseline.js +20 -43
- package/dist/src/core/build-jar-escalation.d.ts +8 -8
- package/dist/src/core/build-jar-escalation.js +18 -17
- package/dist/src/core/build-overwrite-guard.d.ts +4 -4
- package/dist/src/core/build-overwrite-guard.js +14 -14
- package/dist/src/core/build-prepare.d.ts +4 -12
- package/dist/src/core/build-prepare.js +22 -26
- package/dist/src/core/config-mutate.js +4 -4
- package/dist/src/core/config-paths.d.ts +2 -6
- package/dist/src/core/config-paths.js +4 -2
- package/dist/src/core/config-state.d.ts +0 -6
- package/dist/src/core/config-state.js +3 -21
- package/dist/src/core/config-validate-build-audit.d.ts +8 -0
- package/dist/src/core/config-validate-build-audit.js +80 -0
- package/dist/src/core/config-validate-file-size.d.ts +1 -1
- package/dist/src/core/config-validate-file-size.js +3 -3
- package/dist/src/core/config-validate-patch-policy.d.ts +2 -2
- package/dist/src/core/config-validate-patch-policy.js +3 -3
- package/dist/src/core/config-validate-test-toolchains.d.ts +2 -2
- package/dist/src/core/config-validate-test-toolchains.js +4 -5
- package/dist/src/core/config-validate.js +22 -12
- package/dist/src/core/config.d.ts +12 -12
- package/dist/src/core/config.js +21 -25
- package/dist/src/core/coverage-extend.d.ts +16 -16
- package/dist/src/core/coverage-extend.js +20 -20
- package/dist/src/core/destructive.d.ts +14 -14
- package/dist/src/core/destructive.js +9 -9
- package/dist/src/core/diff-hunks.d.ts +2 -2
- package/dist/src/core/diff-hunks.js +7 -7
- package/dist/src/core/discard-baseline.d.ts +10 -10
- package/dist/src/core/discard-baseline.js +22 -23
- package/dist/src/core/display-state.d.ts +11 -11
- package/dist/src/core/display-state.js +12 -12
- package/dist/src/core/engine-changes.d.ts +2 -2
- package/dist/src/core/engine-changes.js +2 -2
- package/dist/src/core/engine-precondition.d.ts +5 -13
- package/dist/src/core/engine-precondition.js +5 -10
- package/dist/src/core/engine-session-lock.d.ts +18 -18
- package/dist/src/core/engine-session-lock.js +50 -54
- package/dist/src/core/export-moved-code-shape.d.ts +7 -7
- package/dist/src/core/export-moved-code-shape.js +10 -10
- package/dist/src/core/file-lock-owner.d.ts +103 -0
- package/dist/src/core/file-lock-owner.js +259 -0
- package/dist/src/core/file-lock.d.ts +14 -19
- package/dist/src/core/file-lock.js +90 -128
- package/dist/src/core/firefox-cache.d.ts +13 -1
- package/dist/src/core/firefox-cache.js +61 -36
- package/dist/src/core/firefox-download.d.ts +15 -0
- package/dist/src/core/firefox-download.js +38 -22
- package/dist/src/core/firefox-extract.d.ts +8 -7
- package/dist/src/core/firefox-extract.js +45 -27
- package/dist/src/core/firefox.d.ts +34 -36
- package/dist/src/core/firefox.js +13 -44
- package/dist/src/core/furnace-apply-dry-run.d.ts +1 -6
- package/dist/src/core/furnace-apply-dry-run.js +2 -8
- package/dist/src/core/furnace-apply-ftl.d.ts +5 -5
- package/dist/src/core/furnace-apply-ftl.js +8 -8
- package/dist/src/core/furnace-apply-helpers.d.ts +9 -20
- package/dist/src/core/furnace-apply-helpers.js +28 -39
- package/dist/src/core/furnace-apply-output.js +1 -1
- package/dist/src/core/furnace-apply-overwrite-warn.d.ts +9 -9
- package/dist/src/core/furnace-apply-overwrite-warn.js +13 -11
- package/dist/src/core/furnace-apply-undeploy-actions.d.ts +1 -1
- package/dist/src/core/furnace-apply-undeploy-actions.js +1 -1
- package/dist/src/core/furnace-apply.d.ts +4 -4
- package/dist/src/core/furnace-apply.js +50 -29
- package/dist/src/core/furnace-checksum-utils.d.ts +5 -5
- package/dist/src/core/furnace-checksum-utils.js +5 -5
- package/dist/src/core/furnace-config-custom.d.ts +1 -1
- package/dist/src/core/furnace-config-custom.js +2 -2
- package/dist/src/core/furnace-config-order.js +1 -1
- package/dist/src/core/furnace-config-tokens.d.ts +3 -3
- package/dist/src/core/furnace-config-tokens.js +3 -3
- package/dist/src/core/furnace-config-validate.js +2 -2
- package/dist/src/core/furnace-config.d.ts +5 -5
- package/dist/src/core/furnace-config.js +40 -53
- package/dist/src/core/furnace-constants.d.ts +6 -6
- package/dist/src/core/furnace-constants.js +9 -8
- package/dist/src/core/furnace-css-fragments.d.ts +6 -6
- package/dist/src/core/furnace-css-fragments.js +11 -11
- package/dist/src/core/furnace-dir-entry.d.ts +20 -0
- package/dist/src/core/furnace-dir-entry.js +21 -0
- package/dist/src/core/furnace-jsconfig.d.ts +7 -7
- package/dist/src/core/furnace-jsconfig.js +22 -20
- package/dist/src/core/furnace-operation.d.ts +22 -19
- package/dist/src/core/furnace-operation.js +38 -34
- package/dist/src/core/furnace-precondition.d.ts +10 -10
- package/dist/src/core/furnace-precondition.js +8 -8
- package/dist/src/core/furnace-refresh.d.ts +18 -6
- package/dist/src/core/furnace-refresh.js +5 -8
- package/dist/src/core/furnace-registration-ast.d.ts +2 -3
- package/dist/src/core/furnace-registration-ast.js +9 -12
- package/dist/src/core/furnace-registration-remove.d.ts +4 -4
- package/dist/src/core/furnace-registration-remove.js +6 -6
- package/dist/src/core/furnace-registration-validate.d.ts +2 -2
- package/dist/src/core/furnace-registration-validate.js +2 -2
- package/dist/src/core/furnace-registration.d.ts +7 -6
- package/dist/src/core/furnace-registration.js +29 -36
- package/dist/src/core/furnace-rollback.d.ts +1 -1
- package/dist/src/core/furnace-rollback.js +5 -5
- package/dist/src/core/furnace-scanner.js +3 -6
- package/dist/src/core/furnace-stale-export.d.ts +17 -16
- package/dist/src/core/furnace-stale-export.js +16 -15
- package/dist/src/core/furnace-staleness.d.ts +2 -2
- package/dist/src/core/furnace-staleness.js +2 -2
- package/dist/src/core/furnace-state-persist.d.ts +12 -12
- package/dist/src/core/furnace-state-persist.js +10 -10
- package/dist/src/core/furnace-step-errors.d.ts +6 -6
- package/dist/src/core/furnace-step-errors.js +6 -6
- package/dist/src/core/furnace-validate-accessibility.js +14 -14
- package/dist/src/core/furnace-validate-compatibility.js +9 -9
- package/dist/src/core/furnace-validate-registration.d.ts +2 -2
- package/dist/src/core/furnace-validate-registration.js +18 -20
- package/dist/src/core/furnace-validate-structure.d.ts +1 -1
- package/dist/src/core/furnace-validate-structure.js +4 -4
- package/dist/src/core/furnace-validate.js +9 -9
- package/dist/src/core/furnace-version-drift.d.ts +5 -5
- package/dist/src/core/furnace-version-drift.js +5 -5
- package/dist/src/core/git-base.d.ts +6 -4
- package/dist/src/core/git-base.js +29 -7
- package/dist/src/core/git-diff-new-file.d.ts +40 -0
- package/dist/src/core/git-diff-new-file.js +119 -0
- package/dist/src/core/git-diff.d.ts +13 -13
- package/dist/src/core/git-diff.js +121 -189
- package/dist/src/core/git-file-ops.d.ts +6 -13
- package/dist/src/core/git-file-ops.js +11 -35
- package/dist/src/core/git-readonly-index.d.ts +12 -14
- package/dist/src/core/git-readonly-index.js +12 -16
- package/dist/src/core/git-status.d.ts +9 -2
- package/dist/src/core/git-status.js +23 -11
- package/dist/src/core/git.d.ts +3 -9
- package/dist/src/core/git.js +28 -57
- package/dist/src/core/harness-orphans.d.ts +17 -17
- package/dist/src/core/harness-orphans.js +28 -27
- package/dist/src/core/history-log.d.ts +19 -0
- package/dist/src/core/history-log.js +29 -0
- package/dist/src/core/license-headers.d.ts +19 -18
- package/dist/src/core/license-headers.js +29 -28
- package/dist/src/core/mach-build-artifacts.d.ts +21 -21
- package/dist/src/core/mach-build-artifacts.js +23 -23
- package/dist/src/core/mach-error-hints.d.ts +5 -10
- package/dist/src/core/mach-error-hints.js +14 -14
- package/dist/src/core/mach-known-noise-filter.d.ts +42 -38
- package/dist/src/core/mach-known-noise-filter.js +57 -56
- package/dist/src/core/mach-mozconfig.d.ts +6 -6
- package/dist/src/core/mach-mozconfig.js +17 -16
- package/dist/src/core/mach-python.d.ts +3 -0
- package/dist/src/core/mach-python.js +13 -7
- package/dist/src/core/mach-resource-shim.d.ts +24 -12
- package/dist/src/core/mach-resource-shim.js +124 -21
- package/dist/src/core/mach.d.ts +59 -73
- package/dist/src/core/mach.js +47 -115
- package/dist/src/core/marionette-port.d.ts +15 -30
- package/dist/src/core/marionette-port.js +46 -89
- package/dist/src/core/marionette-preflight.d.ts +6 -6
- package/dist/src/core/marionette-preflight.js +32 -50
- package/dist/src/core/markdown-table.d.ts +9 -9
- package/dist/src/core/markdown-table.js +14 -14
- package/dist/src/core/mochitest-server-port.d.ts +8 -8
- package/dist/src/core/mochitest-server-port.js +17 -17
- package/dist/src/core/module-resolution-preflight.d.ts +8 -8
- package/dist/src/core/module-resolution-preflight.js +11 -11
- package/dist/src/core/moz-manifest-helpers.d.ts +7 -7
- package/dist/src/core/moz-manifest-helpers.js +7 -7
- package/dist/src/core/moz-manifest-register.d.ts +1 -1
- package/dist/src/core/moz-manifest-register.js +2 -2
- package/dist/src/core/moz-manifest-rules.js +46 -42
- package/dist/src/core/moz-manifest-tokenizers.js +1 -1
- package/dist/src/core/ownership-table.d.ts +5 -5
- package/dist/src/core/ownership-table.js +7 -7
- package/dist/src/core/parser-fallback.d.ts +3 -3
- package/dist/src/core/parser-fallback.js +3 -3
- package/dist/src/core/patch-apply-fuzz.d.ts +5 -5
- package/dist/src/core/patch-apply-fuzz.js +13 -13
- package/dist/src/core/patch-apply.d.ts +13 -14
- package/dist/src/core/patch-apply.js +36 -42
- package/dist/src/core/patch-export-coverage.d.ts +0 -9
- package/dist/src/core/patch-export-coverage.js +1 -30
- package/dist/src/core/patch-export-update.d.ts +21 -4
- package/dist/src/core/patch-export-update.js +7 -6
- package/dist/src/core/patch-export.d.ts +20 -30
- package/dist/src/core/patch-export.js +55 -77
- package/dist/src/core/patch-files.d.ts +0 -4
- package/dist/src/core/patch-files.js +0 -11
- package/dist/src/core/patch-identifier-suggest.d.ts +1 -1
- package/dist/src/core/patch-identifier-suggest.js +4 -4
- package/dist/src/core/patch-lint-binary.d.ts +12 -18
- package/dist/src/core/patch-lint-cache.d.ts +18 -2
- package/dist/src/core/patch-lint-cache.js +16 -19
- package/dist/src/core/patch-lint-checkjs.d.ts +55 -38
- package/dist/src/core/patch-lint-checkjs.js +78 -64
- package/dist/src/core/patch-lint-chrome-jsdoc.d.ts +8 -9
- package/dist/src/core/patch-lint-chrome-jsdoc.js +10 -11
- package/dist/src/core/patch-lint-creators.d.ts +5 -9
- package/dist/src/core/patch-lint-creators.js +3 -3
- package/dist/src/core/patch-lint-cross.d.ts +27 -19
- package/dist/src/core/patch-lint-cross.js +67 -110
- package/dist/src/core/patch-lint-css.d.ts +1 -1
- package/dist/src/core/patch-lint-css.js +15 -11
- package/dist/src/core/patch-lint-diff-tag.d.ts +5 -5
- package/dist/src/core/patch-lint-diff-tag.js +5 -5
- package/dist/src/core/patch-lint-diff.d.ts +4 -4
- package/dist/src/core/patch-lint-diff.js +4 -4
- package/dist/src/core/patch-lint-file-size.d.ts +3 -3
- package/dist/src/core/patch-lint-file-size.js +6 -6
- package/dist/src/core/patch-lint-forward-registration.d.ts +58 -0
- package/dist/src/core/patch-lint-forward-registration.js +210 -0
- package/dist/src/core/patch-lint-jsdoc.d.ts +2 -2
- package/dist/src/core/patch-lint-jsdoc.js +46 -46
- package/dist/src/core/patch-lint-module-registration.d.ts +3 -9
- package/dist/src/core/patch-lint-module-registration.js +1 -1
- package/dist/src/core/patch-lint-mozbuild.d.ts +1 -1
- package/dist/src/core/patch-lint-mozbuild.js +10 -10
- package/dist/src/core/patch-lint-observer.d.ts +3 -3
- package/dist/src/core/patch-lint-observer.js +7 -7
- package/dist/src/core/patch-lint-ownership.d.ts +6 -6
- package/dist/src/core/patch-lint-ownership.js +6 -6
- package/dist/src/core/patch-lint-prettier.d.ts +6 -6
- package/dist/src/core/patch-lint-prettier.js +7 -7
- package/dist/src/core/patch-lint-queue-types.d.ts +60 -0
- package/dist/src/core/patch-lint-queue-types.js +12 -0
- package/dist/src/core/patch-lint-staged-registration.d.ts +61 -0
- package/dist/src/core/patch-lint-staged-registration.js +90 -0
- package/dist/src/core/patch-lint-unmanaged-companion.d.ts +23 -23
- package/dist/src/core/patch-lint-unmanaged-companion.js +26 -26
- package/dist/src/core/patch-lint.d.ts +41 -35
- package/dist/src/core/patch-lint.js +52 -49
- package/dist/src/core/patch-lock.d.ts +1 -1
- package/dist/src/core/patch-lock.js +11 -11
- package/dist/src/core/patch-manifest-consistency.d.ts +7 -7
- package/dist/src/core/patch-manifest-consistency.js +16 -17
- package/dist/src/core/patch-manifest-files-affected.d.ts +1 -1
- package/dist/src/core/patch-manifest-files-affected.js +3 -3
- package/dist/src/core/patch-manifest-io.d.ts +14 -14
- package/dist/src/core/patch-manifest-io.js +35 -34
- package/dist/src/core/patch-manifest-query.d.ts +1 -1
- package/dist/src/core/patch-manifest-query.js +4 -4
- package/dist/src/core/patch-manifest-resolve.d.ts +5 -5
- package/dist/src/core/patch-manifest-resolve.js +7 -7
- package/dist/src/core/patch-manifest-validate.js +3 -3
- package/dist/src/core/patch-manifest.d.ts +2 -2
- package/dist/src/core/patch-manifest.js +2 -2
- package/dist/src/core/patch-parse.d.ts +32 -21
- package/dist/src/core/patch-parse.js +40 -15
- package/dist/src/core/patch-policy.js +15 -27
- package/dist/src/core/patch-registration-refs.d.ts +4 -4
- package/dist/src/core/patch-registration-refs.js +7 -7
- package/dist/src/core/patch-source-metadata.d.ts +1 -3
- package/dist/src/core/patch-source-metadata.js +0 -4
- package/dist/src/core/patch-transform.d.ts +8 -16
- package/dist/src/core/patch-transform.js +13 -23
- package/dist/src/core/process-cpu-time.d.ts +1 -1
- package/dist/src/core/process-cpu-time.js +6 -6
- package/dist/src/core/rebase-session.d.ts +9 -15
- package/dist/src/core/rebase-session.js +13 -25
- package/dist/src/core/register-browser-content.js +3 -2
- package/dist/src/core/register-browser-test.js +2 -1
- package/dist/src/core/register-module.js +2 -1
- package/dist/src/core/register-result.d.ts +1 -1
- package/dist/src/core/register-result.js +1 -1
- package/dist/src/core/register-scaffold.d.ts +2 -2
- package/dist/src/core/register-scaffold.js +8 -7
- package/dist/src/core/register-shared-css.d.ts +3 -3
- package/dist/src/core/register-shared-css.js +6 -5
- package/dist/src/core/register-xpcshell-test.d.ts +2 -2
- package/dist/src/core/register-xpcshell-test.js +2 -2
- package/dist/src/core/run-log-redact.d.ts +38 -0
- package/dist/src/core/run-log-redact.js +69 -0
- package/dist/src/core/run-log.d.ts +21 -10
- package/dist/src/core/run-log.js +76 -27
- package/dist/src/core/shared-ftl.d.ts +2 -2
- package/dist/src/core/shared-ftl.js +6 -6
- package/dist/src/core/signal-critical.d.ts +2 -2
- package/dist/src/core/signal-critical.js +4 -6
- package/dist/src/core/smoke-patterns.d.ts +5 -6
- package/dist/src/core/smoke-patterns.js +15 -20
- package/dist/src/core/state-file.d.ts +15 -4
- package/dist/src/core/state-file.js +14 -1
- package/dist/src/core/status-binary.d.ts +8 -8
- package/dist/src/core/status-binary.js +12 -12
- package/dist/src/core/status-classify.d.ts +17 -17
- package/dist/src/core/status-classify.js +13 -12
- package/dist/src/core/test-changed-prefs.d.ts +12 -12
- package/dist/src/core/test-changed-prefs.js +40 -25
- package/dist/src/core/test-harness-crash.d.ts +39 -39
- package/dist/src/core/test-harness-crash.js +69 -69
- package/dist/src/core/test-harness-output.d.ts +7 -7
- package/dist/src/core/test-harness-output.js +7 -7
- package/dist/src/core/test-harness-verdict-notes.d.ts +13 -14
- package/dist/src/core/test-harness-verdict-notes.js +4 -4
- package/dist/src/core/test-path-scope.d.ts +8 -8
- package/dist/src/core/test-path-scope.js +11 -11
- package/dist/src/core/test-stale-check.d.ts +22 -23
- package/dist/src/core/test-stale-check.js +31 -30
- package/dist/src/core/test-stale-symlink.d.ts +1 -1
- package/dist/src/core/test-stale-symlink.js +1 -1
- package/dist/src/core/test-stall-triage.d.ts +9 -9
- package/dist/src/core/test-stall-triage.js +22 -22
- package/dist/src/core/test-xpcshell-retry.d.ts +26 -7
- package/dist/src/core/test-xpcshell-retry.js +14 -11
- package/dist/src/core/token-category.d.ts +35 -2
- package/dist/src/core/token-category.js +67 -58
- package/dist/src/core/token-coverage.js +4 -5
- package/dist/src/core/token-dark-mode.d.ts +9 -9
- package/dist/src/core/token-dark-mode.js +13 -25
- package/dist/src/core/token-docs.d.ts +1 -1
- package/dist/src/core/token-inventory.d.ts +56 -0
- package/dist/src/core/token-inventory.js +109 -0
- package/dist/src/core/token-manager.d.ts +4 -4
- package/dist/src/core/token-manager.js +22 -22
- package/dist/src/core/token-scaffold.d.ts +4 -4
- package/dist/src/core/token-scaffold.js +4 -4
- package/dist/src/core/token-variant.d.ts +14 -14
- package/dist/src/core/token-variant.js +52 -53
- package/dist/src/core/toolchain-preflight.d.ts +15 -15
- package/dist/src/core/toolchain-preflight.js +23 -23
- package/dist/src/core/tree-cow.d.ts +3 -5
- package/dist/src/core/tree-cow.js +8 -8
- package/dist/src/core/tree-guard.d.ts +3 -3
- package/dist/src/core/tree-guard.js +23 -23
- package/dist/src/core/tree-store.d.ts +15 -15
- package/dist/src/core/tree-store.js +39 -38
- package/dist/src/core/typecheck-shim.d.ts +16 -15
- package/dist/src/core/typecheck-shim.js +26 -25
- package/dist/src/core/typecheck.d.ts +12 -12
- package/dist/src/core/typecheck.js +33 -33
- package/dist/src/core/wire-destroy.d.ts +2 -2
- package/dist/src/core/wire-destroy.js +5 -5
- package/dist/src/core/wire-dom-fragment.d.ts +3 -3
- package/dist/src/core/wire-dom-fragment.js +12 -23
- package/dist/src/core/wire-init.d.ts +2 -2
- package/dist/src/core/wire-init.js +7 -7
- package/dist/src/core/wire-subscript.d.ts +1 -1
- package/dist/src/core/wire-subscript.js +3 -3
- package/dist/src/core/wire-utils.d.ts +9 -9
- package/dist/src/core/wire-utils.js +16 -28
- package/dist/src/core/xpcshell-appdir.d.ts +20 -20
- package/dist/src/core/xpcshell-appdir.js +28 -30
- package/dist/src/core/xpcshell-profile-dir.d.ts +3 -3
- package/dist/src/core/xpcshell-profile-dir.js +7 -7
- package/dist/src/errors/base.d.ts +69 -16
- package/dist/src/errors/base.js +95 -26
- package/dist/src/errors/build.d.ts +6 -6
- package/dist/src/errors/build.js +26 -34
- package/dist/src/errors/codes.d.ts +10 -10
- package/dist/src/errors/codes.js +10 -10
- package/dist/src/errors/config.d.ts +0 -14
- package/dist/src/errors/config.js +13 -34
- package/dist/src/errors/download.d.ts +13 -0
- package/dist/src/errors/download.js +53 -24
- package/dist/src/errors/furnace.d.ts +2 -2
- package/dist/src/errors/furnace.js +8 -9
- package/dist/src/errors/git.d.ts +9 -9
- package/dist/src/errors/git.js +21 -31
- package/dist/src/errors/patch.d.ts +3 -3
- package/dist/src/errors/patch.js +11 -13
- package/dist/src/errors/rebase.d.ts +1 -1
- package/dist/src/errors/rebase.js +8 -8
- package/dist/src/errors/run.d.ts +1 -1
- package/dist/src/errors/run.js +1 -1
- package/dist/src/index.d.ts +4 -4
- package/dist/src/index.js +4 -4
- package/dist/src/types/commands/options.d.ts +155 -200
- package/dist/src/types/commands/patches.d.ts +19 -19
- package/dist/src/types/commands/project.d.ts +3 -3
- package/dist/src/types/config.d.ts +52 -19
- package/dist/src/types/furnace.d.ts +17 -17
- package/dist/src/types/index.d.ts +0 -1
- package/dist/src/types/json.d.ts +3 -3
- package/dist/src/types/json.js +2 -2
- package/dist/src/types/typecheck.d.ts +3 -3
- package/dist/src/utils/assert.d.ts +4 -16
- package/dist/src/utils/assert.js +7 -24
- package/dist/src/utils/build-info.d.ts +6 -6
- package/dist/src/utils/build-info.js +6 -6
- package/dist/src/utils/child-env.d.ts +7 -6
- package/dist/src/utils/child-env.js +5 -5
- package/dist/src/utils/concurrency.d.ts +2 -2
- package/dist/src/utils/concurrency.js +2 -2
- package/dist/src/utils/elapsed.js +10 -1
- package/dist/src/utils/errors.d.ts +8 -8
- package/dist/src/utils/errors.js +8 -8
- package/dist/src/utils/fs.d.ts +1 -1
- package/dist/src/utils/fs.js +15 -20
- package/dist/src/utils/hash.d.ts +12 -0
- package/dist/src/utils/hash.js +16 -0
- package/dist/src/utils/line-dispatch.d.ts +15 -0
- package/dist/src/utils/line-dispatch.js +48 -0
- package/dist/src/utils/logger.d.ts +4 -4
- package/dist/src/utils/logger.js +11 -11
- package/dist/src/utils/machine-output.js +2 -2
- package/dist/src/utils/options.d.ts +14 -20
- package/dist/src/utils/options.js +26 -27
- package/dist/src/utils/package-root.js +5 -14
- package/dist/src/utils/paths.d.ts +4 -4
- package/dist/src/utils/paths.js +4 -4
- package/dist/src/utils/platform.d.ts +0 -4
- package/dist/src/utils/process-group.d.ts +10 -9
- package/dist/src/utils/process-group.js +37 -36
- package/dist/src/utils/process.d.ts +70 -55
- package/dist/src/utils/process.js +129 -179
- package/dist/src/utils/ps-duration.d.ts +4 -4
- package/dist/src/utils/ps-duration.js +9 -9
- package/dist/src/utils/regex.d.ts +4 -4
- package/dist/src/utils/regex.js +7 -7
- package/dist/src/utils/sleep.d.ts +26 -0
- package/dist/src/utils/sleep.js +31 -0
- package/dist/src/utils/stdio-drain.d.ts +7 -7
- package/dist/src/utils/stdio-drain.js +8 -8
- package/dist/src/utils/validation.d.ts +12 -49
- package/dist/src/utils/validation.js +26 -36
- package/docs/README.md +2 -2
- package/docs/configuration.md +163 -69
- package/docs/exit-codes.md +66 -49
- package/docs/furnace.md +20 -19
- package/docs/lifecycle-invariants.md +414 -247
- package/docs/machine-output.md +58 -34
- package/docs/patch-workflow.md +48 -44
- package/docs/run-logs.md +72 -28
- package/docs/testing.md +105 -98
- package/docs/verification-trees.md +23 -22
- package/package.json +7 -6
- package/dist/src/commands/rebase.d.ts +0 -4
- package/dist/src/commands/rebase.js +0 -5
- package/dist/src/core/patch-artifact-normalize.d.ts +0 -21
- package/dist/src/core/patch-artifact-normalize.js +0 -24
- package/dist/src/core/patch-lint-reexports.d.ts +0 -7
- package/dist/src/core/patch-lint-reexports.js +0 -8
- package/dist/src/core/wire-targets.d.ts +0 -7
- package/dist/src/core/wire-targets.js +0 -8
|
@@ -0,0 +1,259 @@
|
|
|
1
|
+
// SPDX-License-Identifier: EUPL-1.2
|
|
2
|
+
/**
|
|
3
|
+
* Owner record of a `withFileLock` directory: the file that says which
|
|
4
|
+
* process holds the lock, so stale recovery can tell a dead holder from a
|
|
5
|
+
* slow one and release can refuse to remove a lock it no longer owns.
|
|
6
|
+
*
|
|
7
|
+
* Split out of `file-lock.ts` so the record's format, its write-and-verify
|
|
8
|
+
* contract, and the PID-reuse guard live in one place with their own tests.
|
|
9
|
+
*/
|
|
10
|
+
import { readFileSync } from 'node:fs';
|
|
11
|
+
import { readFile, rm, writeFile } from 'node:fs/promises';
|
|
12
|
+
import { join } from 'node:path';
|
|
13
|
+
import { GeneralError } from '../errors/base.js';
|
|
14
|
+
import { isProcessAlive, toError } from '../utils/errors.js';
|
|
15
|
+
import { verbose } from '../utils/logger.js';
|
|
16
|
+
import { sleep } from '../utils/sleep.js';
|
|
17
|
+
/**
|
|
18
|
+
* Filename of a lock directory's owner record, relative to the lock dir.
|
|
19
|
+
*
|
|
20
|
+
* Re-exported by `file-lock.ts` so external readers (`tree-store.ts`) share
|
|
21
|
+
* the constant instead of re-spelling `'pid'`. The file format is
|
|
22
|
+
* documented on {@link readLockOwner}.
|
|
23
|
+
*/
|
|
24
|
+
export const LOCK_PID_FILE = 'pid';
|
|
25
|
+
/**
|
|
26
|
+
* Prefix of the mechanical owner-record line that carries the acquisition
|
|
27
|
+
* wall time. It lives among the metadata lines (line 3 onward) so older
|
|
28
|
+
* readers, which treat everything past line 2 as free-form diagnostics,
|
|
29
|
+
* still parse the record. The current reader lifts it out of `metadata`.
|
|
30
|
+
* Diagnostic only. See {@link START_TICK_PREFIX} for the liveness field.
|
|
31
|
+
*/
|
|
32
|
+
const ACQUIRED_AT_PREFIX = 'acquired-at-ms=';
|
|
33
|
+
/**
|
|
34
|
+
* Prefix of the owner-record line carrying the holder's own process start
|
|
35
|
+
* tick (`/proc/self/stat` field 22, in USER_HZ since boot). Written only
|
|
36
|
+
* where procfs exposes it (Linux). Boot-relative ticks are what the
|
|
37
|
+
* PID-reuse guard compares: unlike a wall-clock time they are immune to
|
|
38
|
+
* the clock being stepped by NTP/chrony/`date -s` between acquisition and
|
|
39
|
+
* probe, and a process's start tick never changes for its lifetime, so the
|
|
40
|
+
* comparison is exact rather than a tolerance window.
|
|
41
|
+
*/
|
|
42
|
+
const START_TICK_PREFIX = 'start-tick=';
|
|
43
|
+
/**
|
|
44
|
+
* How many times the post-write read-back is retried when the read itself
|
|
45
|
+
* errors (not when the record is absent or differs). An on-access scanner
|
|
46
|
+
* on Windows briefly holding the just-written file (`EBUSY`), or a FUSE
|
|
47
|
+
* mount's momentary `EIO`, must not be indistinguishable from "the record
|
|
48
|
+
* never landed": that verdict releases a lock this process has correctly
|
|
49
|
+
* acquired and aborts the run before it starts.
|
|
50
|
+
*/
|
|
51
|
+
const READ_BACK_ATTEMPTS = 5;
|
|
52
|
+
/** Pause between read-back attempts. */
|
|
53
|
+
const READ_BACK_RETRY_MS = 20;
|
|
54
|
+
/**
|
|
55
|
+
* Parses the on-disk record text. Returns `undefined` when the PID line
|
|
56
|
+
* does not parse as a finite integer.
|
|
57
|
+
*/
|
|
58
|
+
function parseLockOwnerRecord(pidContent) {
|
|
59
|
+
const [pidLine, tokenLine, ...trailingLines] = pidContent.split('\n');
|
|
60
|
+
const pid = parseInt((pidLine ?? '').trim(), 10);
|
|
61
|
+
if (!Number.isFinite(pid))
|
|
62
|
+
return undefined;
|
|
63
|
+
const metadata = [];
|
|
64
|
+
let acquiredAtMs;
|
|
65
|
+
let startTick;
|
|
66
|
+
for (const rawLine of trailingLines) {
|
|
67
|
+
const line = rawLine.trim();
|
|
68
|
+
if (line.length === 0)
|
|
69
|
+
continue;
|
|
70
|
+
if (line.startsWith(ACQUIRED_AT_PREFIX)) {
|
|
71
|
+
const parsed = Number.parseInt(line.slice(ACQUIRED_AT_PREFIX.length), 10);
|
|
72
|
+
if (Number.isFinite(parsed))
|
|
73
|
+
acquiredAtMs ??= parsed;
|
|
74
|
+
continue;
|
|
75
|
+
}
|
|
76
|
+
if (line.startsWith(START_TICK_PREFIX)) {
|
|
77
|
+
const parsed = Number.parseInt(line.slice(START_TICK_PREFIX.length), 10);
|
|
78
|
+
if (Number.isFinite(parsed))
|
|
79
|
+
startTick ??= parsed;
|
|
80
|
+
continue;
|
|
81
|
+
}
|
|
82
|
+
metadata.push(line);
|
|
83
|
+
}
|
|
84
|
+
const token = tokenLine?.trim();
|
|
85
|
+
const owner = { present: true, pid, metadata };
|
|
86
|
+
if (token !== undefined && token.length > 0)
|
|
87
|
+
owner.token = token;
|
|
88
|
+
if (acquiredAtMs !== undefined)
|
|
89
|
+
owner.acquiredAtMs = acquiredAtMs;
|
|
90
|
+
if (startTick !== undefined)
|
|
91
|
+
owner.startTick = startTick;
|
|
92
|
+
return owner;
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Reads the owner PID (line 1), acquisition token (line 2), the mechanical
|
|
96
|
+
* `acquired-at-ms=` / `start-tick=` lines (when present), and diagnostic
|
|
97
|
+
* metadata (the remaining lines 3+) from a lock directory's PID file.
|
|
98
|
+
* Returns `{ present: false }` when the PID file is missing, unreadable, or
|
|
99
|
+
* the PID does not parse as a finite integer (caller falls back to the
|
|
100
|
+
* age-only staleness heuristic).
|
|
101
|
+
*
|
|
102
|
+
* File format note: external readers do `parseInt(content.trim(), 10)`,
|
|
103
|
+
* which parses the leading digits of a multi-line file, so the token and
|
|
104
|
+
* mechanical lines stay compatible.
|
|
105
|
+
*
|
|
106
|
+
* @param lockPath - Lock directory whose owner record to read
|
|
107
|
+
* @returns The parsed owner record, or `{ present: false }`
|
|
108
|
+
*/
|
|
109
|
+
export async function readLockOwner(lockPath) {
|
|
110
|
+
try {
|
|
111
|
+
const owner = parseLockOwnerRecord(await readFile(join(lockPath, LOCK_PID_FILE), 'utf-8'));
|
|
112
|
+
if (owner !== undefined)
|
|
113
|
+
return owner;
|
|
114
|
+
}
|
|
115
|
+
catch {
|
|
116
|
+
// PID file missing or unreadable. Treat as absent.
|
|
117
|
+
}
|
|
118
|
+
return { present: false };
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Reads the just-written record back, retrying a read error a few times
|
|
122
|
+
* before giving up. A missing or malformed record is returned as-is (the
|
|
123
|
+
* caller treats it as a failed write). Only errno-level failures retry.
|
|
124
|
+
*/
|
|
125
|
+
async function readBackLockOwner(lockPath) {
|
|
126
|
+
let lastError;
|
|
127
|
+
for (let attempt = 0; attempt < READ_BACK_ATTEMPTS; attempt++) {
|
|
128
|
+
try {
|
|
129
|
+
return parseLockOwnerRecord(await readFile(join(lockPath, LOCK_PID_FILE), 'utf-8'));
|
|
130
|
+
}
|
|
131
|
+
catch (error) {
|
|
132
|
+
lastError = error;
|
|
133
|
+
if (attempt < READ_BACK_ATTEMPTS - 1)
|
|
134
|
+
await sleep(READ_BACK_RETRY_MS);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
throw new Error(`owner record could not be read back: ${toError(lastError).message}`);
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* Stamps this process's ownership (PID, per-acquisition token, acquisition
|
|
141
|
+
* time, own start tick, diagnostic metadata) into a lock directory it has
|
|
142
|
+
* just created, and reads the record back to prove it landed.
|
|
143
|
+
*
|
|
144
|
+
* The write is fatal. It used to be best-effort, on the theory that stale
|
|
145
|
+
* recovery would fall back to the age heuristic, but that heuristic reaps
|
|
146
|
+
* any owner-less lock after five minutes, and the build lock legitimately
|
|
147
|
+
* holds for hours. A holder whose record failed to write was therefore
|
|
148
|
+
* reaped mid-build and a second process entered the critical section. On
|
|
149
|
+
* failure the just-created lock directory is removed (nothing else can own
|
|
150
|
+
* it yet) and a {@link GeneralError} names the cause.
|
|
151
|
+
*
|
|
152
|
+
* @param lockPath - Lock directory this process has just `mkdir`'d
|
|
153
|
+
* @param token - Per-acquisition UUID, later checked by release
|
|
154
|
+
* @param ownerMetadata - Extra human-diagnostic lines (see `FileLockOptions.ownerMetadata`)
|
|
155
|
+
* @throws {GeneralError} When the record cannot be written or does not read back as written
|
|
156
|
+
*/
|
|
157
|
+
export async function writeLockOwner(lockPath, token, ownerMetadata) {
|
|
158
|
+
const metadata = ownerMetadata
|
|
159
|
+
?.map((line) => line.replace(/\r?\n/g, ' ').trim())
|
|
160
|
+
.filter((line) => line.length > 0 &&
|
|
161
|
+
!line.startsWith(ACQUIRED_AT_PREFIX) &&
|
|
162
|
+
!line.startsWith(START_TICK_PREFIX)) ?? [];
|
|
163
|
+
const ownStartTick = readProcessStartTick(process.pid);
|
|
164
|
+
const mechanicalLines = [
|
|
165
|
+
`${ACQUIRED_AT_PREFIX}${Date.now()}`,
|
|
166
|
+
...(ownStartTick === undefined ? [] : [`${START_TICK_PREFIX}${ownStartTick}`]),
|
|
167
|
+
];
|
|
168
|
+
const record = `${process.pid}\n${token}\n${[...mechanicalLines, ...metadata].map((line) => `${line}\n`).join('')}`;
|
|
169
|
+
let failure;
|
|
170
|
+
try {
|
|
171
|
+
await writeFile(join(lockPath, LOCK_PID_FILE), record, 'utf-8');
|
|
172
|
+
const readBack = await readBackLockOwner(lockPath);
|
|
173
|
+
if (readBack !== undefined && readBack.pid === process.pid && readBack.token === token) {
|
|
174
|
+
return;
|
|
175
|
+
}
|
|
176
|
+
failure = new Error('owner record did not read back as written');
|
|
177
|
+
}
|
|
178
|
+
catch (error) {
|
|
179
|
+
failure = error;
|
|
180
|
+
}
|
|
181
|
+
try {
|
|
182
|
+
await rm(lockPath, { recursive: true, force: true });
|
|
183
|
+
}
|
|
184
|
+
catch (cleanupError) {
|
|
185
|
+
verbose(`Could not remove unowned lock ${lockPath}: ${toError(cleanupError).message}`);
|
|
186
|
+
}
|
|
187
|
+
throw new GeneralError(`Could not record ownership of lock ${lockPath}: ${toError(failure).message}. ` +
|
|
188
|
+
'The lock was released without running the operation — a lock with no readable owner ' +
|
|
189
|
+
'would be reaped as stale after five minutes and a second process could enter the ' +
|
|
190
|
+
'critical section. Check permissions and free space on the lock directory, then retry.', failure);
|
|
191
|
+
}
|
|
192
|
+
/**
|
|
193
|
+
* Boot-relative start tick of a process, where the platform exposes it
|
|
194
|
+
* cheaply.
|
|
195
|
+
*
|
|
196
|
+
* Linux only: field 22 of `/proc/<pid>/stat`, in USER_HZ since boot.
|
|
197
|
+
* Elsewhere (macOS, Windows) obtaining a start time means spawning
|
|
198
|
+
* `ps`/`wmic` per probe, which is not worth paying on every poll of a
|
|
199
|
+
* contended lock. Those platforms return `undefined` and liveness stays
|
|
200
|
+
* PID-only.
|
|
201
|
+
*
|
|
202
|
+
* Not converted to wall-clock time via `/proc/stat` `btime`, on purpose:
|
|
203
|
+
* on current kernels `btime` is derived from the realtime clock and moves
|
|
204
|
+
* with every clock step, so a wall-clock comparison against a recorded
|
|
205
|
+
* acquisition time misjudges a live holder as a reused PID after NTP steps
|
|
206
|
+
* the clock forward, and reaps a lock that is in use.
|
|
207
|
+
*
|
|
208
|
+
* @param pid - Process to look up
|
|
209
|
+
* @param procRoot - procfs mount, overridable for tests
|
|
210
|
+
* @returns Start tick, or `undefined` when unobtainable
|
|
211
|
+
*/
|
|
212
|
+
export function readProcessStartTick(pid, procRoot = '/proc') {
|
|
213
|
+
try {
|
|
214
|
+
const stat = readFileSync(join(procRoot, String(pid), 'stat'), 'utf-8');
|
|
215
|
+
// `comm` (field 2) is parenthesised and may itself contain spaces or
|
|
216
|
+
// parentheses, so split only what follows the last closing paren:
|
|
217
|
+
// field 3 (state) is then index 0 and field 22 (starttime) index 19.
|
|
218
|
+
const startTick = Number.parseInt(stat
|
|
219
|
+
.slice(stat.lastIndexOf(')') + 1)
|
|
220
|
+
.trim()
|
|
221
|
+
.split(/\s+/)[19] ?? '', 10);
|
|
222
|
+
return Number.isFinite(startTick) ? startTick : undefined;
|
|
223
|
+
}
|
|
224
|
+
catch {
|
|
225
|
+
return undefined;
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
/**
|
|
229
|
+
* Whether the process named by a lock's owner record is the same process
|
|
230
|
+
* that acquired the lock, not merely a live process wearing its PID.
|
|
231
|
+
*
|
|
232
|
+
* `isProcessAlive` answers "does this PID exist". After a holder crashes,
|
|
233
|
+
* the kernel may hand its PID to a long-lived daemon, and a PID-only check
|
|
234
|
+
* then honours the dead lock until the waiter's timeout. Where the record
|
|
235
|
+
* carries the writer's start tick and the candidate's own tick is cheaply
|
|
236
|
+
* obtainable (see {@link readProcessStartTick}), the two must be equal: a
|
|
237
|
+
* different tick is a different process. Records without a start tick, and
|
|
238
|
+
* platforms without one, keep the PID-only answer.
|
|
239
|
+
*
|
|
240
|
+
* @param owner - Owner record fields that identify the holder
|
|
241
|
+
* @param procRoot - procfs mount, overridable for tests
|
|
242
|
+
* @returns True when the original holder is still running (or cannot be proven gone)
|
|
243
|
+
*/
|
|
244
|
+
export function isLockOwnerAlive(owner, procRoot) {
|
|
245
|
+
if (!isProcessAlive(owner.pid))
|
|
246
|
+
return false;
|
|
247
|
+
if (owner.startTick === undefined)
|
|
248
|
+
return true;
|
|
249
|
+
const currentStartTick = readProcessStartTick(owner.pid, procRoot);
|
|
250
|
+
if (currentStartTick === undefined)
|
|
251
|
+
return true;
|
|
252
|
+
if (currentStartTick !== owner.startTick) {
|
|
253
|
+
verbose(`Lock owner PID ${owner.pid} started at tick ${currentStartTick}, but the ` +
|
|
254
|
+
`record was written by a process started at tick ${owner.startTick} — the PID was ` +
|
|
255
|
+
'reused; treating the holder as dead');
|
|
256
|
+
return false;
|
|
257
|
+
}
|
|
258
|
+
return true;
|
|
259
|
+
}
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { LOCK_PID_FILE } from './file-lock-owner.js';
|
|
2
|
+
export { LOCK_PID_FILE };
|
|
1
3
|
/**
|
|
2
4
|
* Snapshot of the current lock holder handed to {@link FileLockOptions.onWaitProgress}.
|
|
3
5
|
* `metadata` carries the pid file's human-diagnostic lines (line 3 onward,
|
|
@@ -12,15 +14,15 @@ export interface LockHolder {
|
|
|
12
14
|
/**
|
|
13
15
|
* Live queue state around a contended lock.
|
|
14
16
|
*
|
|
15
|
-
* The lock itself behaves correctly under several concurrent sessions
|
|
16
|
-
* gap this closes is
|
|
17
|
+
* The lock itself behaves correctly under several concurrent sessions. The
|
|
18
|
+
* gap this closes is visibility. Waiters advertise themselves in a sibling
|
|
17
19
|
* directory so both the wait output and `fireforge status --lock` can say
|
|
18
20
|
* how many are queued and how many are ahead of you.
|
|
19
21
|
*/
|
|
20
22
|
export interface LockQueueState {
|
|
21
23
|
/** Live waiters currently queued for the lock, including this process. */
|
|
22
24
|
depth: number;
|
|
23
|
-
/** Live waiters that started waiting
|
|
25
|
+
/** Live waiters that started waiting before this process. */
|
|
24
26
|
ahead: number;
|
|
25
27
|
}
|
|
26
28
|
export interface FileLockOptions {
|
|
@@ -29,7 +31,7 @@ export interface FileLockOptions {
|
|
|
29
31
|
/**
|
|
30
32
|
* When set, the poll interval doubles after every contended poll (starting
|
|
31
33
|
* from `pollMs`) up to this cap. When absent, polling stays at the fixed
|
|
32
|
-
* `pollMs` interval
|
|
34
|
+
* `pollMs` interval, with zero behavior change for existing callers.
|
|
33
35
|
*/
|
|
34
36
|
pollMaxMs?: number;
|
|
35
37
|
staleMs?: number;
|
|
@@ -58,17 +60,17 @@ export interface FileLockOptions {
|
|
|
58
60
|
queue?: LockQueueState | undefined;
|
|
59
61
|
}) => void;
|
|
60
62
|
/**
|
|
61
|
-
* When set, a wait whose
|
|
63
|
+
* When set, a wait whose queue position is still improving is granted a
|
|
62
64
|
* fresh `timeoutMs` budget on each advance, up to `maxWaitMs` total.
|
|
63
65
|
*
|
|
64
66
|
* A fixed wall-clock budget against a queue whose depth the tool knows is
|
|
65
67
|
* the wrong shape under several concurrent sessions: a wait that expires
|
|
66
68
|
* one position from the head pays the entire wait and gets nothing. The
|
|
67
|
-
*
|
|
68
|
-
*
|
|
69
|
+
* question that matters is whether the queue is moving, not how long the
|
|
70
|
+
* wait has been. A stalled queue still starves on the original budget,
|
|
69
71
|
* which is the case the timeout exists for.
|
|
70
72
|
*
|
|
71
|
-
* Requires the waiter registry (see {@link LockQueueState})
|
|
73
|
+
* Requires the waiter registry (see {@link LockQueueState}). A lock with
|
|
72
74
|
* no readable queue never extends, because nothing observed an advance.
|
|
73
75
|
*/
|
|
74
76
|
extendWhileAdvancing?: {
|
|
@@ -80,7 +82,7 @@ export interface FileLockOptions {
|
|
|
80
82
|
* Separate from {@link onWaitProgress} on purpose: an extension is the one
|
|
81
83
|
* moment the budget the operator asked for stops being the budget in
|
|
82
84
|
* force, and a wait that silently outlives its stated timeout is
|
|
83
|
-
* indistinguishable from a broken one. `budgetMs` is the new
|
|
85
|
+
* indistinguishable from a broken one. `budgetMs` is the new total budget
|
|
84
86
|
* measured from the start of the wait, so it can be compared directly
|
|
85
87
|
* against the requested figure.
|
|
86
88
|
*/
|
|
@@ -90,18 +92,11 @@ export interface FileLockOptions {
|
|
|
90
92
|
}) => void;
|
|
91
93
|
onTimeoutMessage?: string;
|
|
92
94
|
onStaleLockMessage?: (ageMs: number) => string | undefined;
|
|
93
|
-
/** Extra owner-file lines for human diagnostics
|
|
95
|
+
/** Extra owner-file lines for human diagnostics. Lock mechanics ignore them. */
|
|
94
96
|
ownerMetadata?: readonly string[];
|
|
95
97
|
}
|
|
96
98
|
/** Derives the sibling lock-directory path used to guard a file-based resource. */
|
|
97
99
|
export declare function createSiblingLockPath(filePath: string, suffix?: string): string;
|
|
98
|
-
/**
|
|
99
|
-
* Filename of a lock directory's owner record, relative to the lock dir.
|
|
100
|
-
*
|
|
101
|
-
* Exported so external readers (`tree-store.ts`) share the constant instead of
|
|
102
|
-
* re-spelling `'pid'`; the file *format* is documented on {@link readLockOwner}.
|
|
103
|
-
*/
|
|
104
|
-
export declare const LOCK_PID_FILE = "pid";
|
|
105
100
|
/**
|
|
106
101
|
* Reads the live waiter queue around `lockPath`, dropping entries whose
|
|
107
102
|
* process is gone (a killed waiter must not inflate the depth forever).
|
|
@@ -133,11 +128,11 @@ export declare function readLockStatus(lockPath: string): Promise<LockStatusSnap
|
|
|
133
128
|
* Removes a lock directory only if this process still owns it, for callers
|
|
134
129
|
* that hold no acquisition token.
|
|
135
130
|
*
|
|
136
|
-
* The ownership half of {@link releaseLock}, minus the token check
|
|
131
|
+
* The ownership half of {@link releaseLock}, minus the token check: a
|
|
137
132
|
* signal-time sweeper knows which lock paths its own operations opened, but
|
|
138
133
|
* not the per-acquisition UUID those acquisitions minted. The PID check is
|
|
139
134
|
* still the one that matters: it stops the sweeper deleting a lock a
|
|
140
|
-
*
|
|
135
|
+
* different process acquired in the window between our operation dying and
|
|
141
136
|
* the sweep running.
|
|
142
137
|
*
|
|
143
138
|
* Never throws: callers are shutdown paths where a slow or failing I/O must
|