@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
|
@@ -5,40 +5,41 @@
|
|
|
5
5
|
*
|
|
6
6
|
* Headless test runs against recent engines can end with an
|
|
7
7
|
* `AttributeError: 'SystemResourceMonitor' object has no attribute
|
|
8
|
-
* 'stop_time'` traceback at harness teardown
|
|
9
|
-
* exactly where a reader looks for the failure summary. Real failure
|
|
10
|
-
* already beat this traceback in
|
|
11
|
-
*
|
|
8
|
+
* 'stop_time'` traceback at harness teardown. That is upstream noise, and
|
|
9
|
+
* it sits exactly where a reader looks for the failure summary. Real failure
|
|
10
|
+
* lines already beat this traceback in classification. This filter closes
|
|
11
|
+
* the presentation gap by collapsing the echoed traceback to one labeled
|
|
12
|
+
* line.
|
|
12
13
|
*
|
|
13
|
-
* Scope is
|
|
14
|
-
* - Only the terminal
|
|
15
|
-
* stay raw
|
|
16
|
-
* traceback for its green-summary override and secondary-noise
|
|
14
|
+
* Scope is narrow on purpose:
|
|
15
|
+
* - Only the terminal echo is filtered. The captured stdout/stderr strings
|
|
16
|
+
* stay raw, because the classifier (`test-harness-crash.ts`) depends on
|
|
17
|
+
* the raw traceback for its green-summary override and secondary-noise
|
|
17
18
|
* detection.
|
|
18
19
|
* - Only the exact documented incident is collapsed, and every condition
|
|
19
20
|
* must hold: an `AttributeError` on `SystemResourceMonitor` naming one
|
|
20
|
-
* of the two known attributes (`stop_time`, `poll_interval`),
|
|
21
|
-
* `mozsystemmonitor/resourcemonitor.py` stack frame,
|
|
21
|
+
* of the two known attributes (`stop_time`, `poll_interval`), and a
|
|
22
|
+
* `mozsystemmonitor/resourcemonitor.py` stack frame, and a
|
|
22
23
|
* previously-seen SUITE_END shutdown marker (shared across the run's
|
|
23
|
-
* stdout/stderr filter instances
|
|
24
|
-
* while the traceback lands on stderr). A novel attribute, a novel
|
|
24
|
+
* stdout/stderr filter instances, where the marker usually lands on
|
|
25
|
+
* stdout while the traceback lands on stderr). A novel attribute, a novel
|
|
25
26
|
* exception type in resourcemonitor.py, or a pre-shutdown occurrence is
|
|
26
27
|
* echoed verbatim, always.
|
|
27
|
-
* - The hold buffer is bounded
|
|
28
|
+
* - The hold buffer is bounded. On overflow the block is flushed verbatim
|
|
28
29
|
* and the filter returns to pass-through, so output is never lost.
|
|
29
30
|
*
|
|
30
|
-
* The
|
|
31
|
-
*
|
|
31
|
+
* The collapse is test-only on purpose, not an oversight. Two reasons,
|
|
32
|
+
* since from outside they read like one:
|
|
32
33
|
* 1. Recognition requires a previously-seen SUITE_END shutdown marker, and
|
|
33
34
|
* `mach build` never prints one. Wiring the option into the build
|
|
34
35
|
* dispatch would therefore be a silent no-op.
|
|
35
36
|
* 2. Relaxing that gate for builds would be wrong on its own terms. The
|
|
36
37
|
* marker is what separates teardown noise from a traceback raised while
|
|
37
|
-
* work was still happening
|
|
38
|
+
* work was still happening. A build has no equivalent boundary, so
|
|
38
39
|
* FireForge cannot tell the known-cosmetic case from a real build-time
|
|
39
40
|
* failure and must not withhold the block.
|
|
40
|
-
* The build path instead
|
|
41
|
-
* verbatim traceback
|
|
41
|
+
* The build path instead recognizes the signature and says so beside the
|
|
42
|
+
* verbatim traceback. See {@link KNOWN_TEARDOWN_NOISE_BUILD_NOTE} and
|
|
42
43
|
* `runProtectedMachBuild`.
|
|
43
44
|
*/
|
|
44
45
|
const TRACEBACK_HEADER_PATTERN = /^Traceback \(most recent call last\)/;
|
|
@@ -47,52 +48,52 @@ const CHAINED_EXCEPTION_CONNECTOR_PATTERN = /^(?:During handling of the above ex
|
|
|
47
48
|
* Closed allowlist of the documented teardown family's attributes:
|
|
48
49
|
* `stop_time` and `poll_interval` (the same mozsystemmonitor init failure
|
|
49
50
|
* `test-harness-crash.ts` already classifies as recognized noise). Any other
|
|
50
|
-
* missing attribute is a
|
|
51
|
+
* missing attribute is a new upstream defect and must print verbatim.
|
|
51
52
|
*/
|
|
52
53
|
const KNOWN_TEARDOWN_ATTRIBUTE_ERROR_PATTERN = /AttributeError: 'SystemResourceMonitor' object has no attribute '(?:stop_time|poll_interval)'/;
|
|
53
54
|
const RESOURCEMONITOR_FRAME_PATTERN = /mozsystemmonitor[/\\]resourcemonitor\.py/;
|
|
54
55
|
/**
|
|
55
56
|
* Shutdown marker: the harness's SUITE_END line. Matches the shape
|
|
56
57
|
* `test-harness-crash.ts` keys its summary parsing on (module-private
|
|
57
|
-
* there
|
|
58
|
+
* there, and duplicated here with this cross-reference rather than
|
|
59
|
+
* exported).
|
|
58
60
|
*/
|
|
59
61
|
const SHUTDOWN_MARKER_PATTERN = /\bSUITE_END\b/;
|
|
60
|
-
/** Whole-block recognition — every signal must hold (see module doc). */
|
|
61
|
-
function isRecognizedTeardownNoise(block) {
|
|
62
|
-
return (KNOWN_TEARDOWN_ATTRIBUTE_ERROR_PATTERN.test(block) && RESOURCEMONITOR_FRAME_PATTERN.test(block));
|
|
63
|
-
}
|
|
64
62
|
/**
|
|
65
|
-
*
|
|
66
|
-
* teardown
|
|
63
|
+
* Whole-block recognition. Every signal must hold (see module doc). True
|
|
64
|
+
* when captured output carries the documented mozsystemmonitor teardown
|
|
65
|
+
* traceback.
|
|
67
66
|
*
|
|
68
|
-
* The echo filter
|
|
67
|
+
* The echo filter below only affects what a human sees. The classifier
|
|
69
68
|
* reads the raw capture, and it needs the same recognition to tell "the
|
|
70
69
|
* suite finished clean and then upstream fell over at shutdown" from "the
|
|
71
|
-
* suite did not finish".
|
|
72
|
-
*
|
|
73
|
-
* `resourcemonitor.py` is
|
|
70
|
+
* suite did not finish". This is the same two-signal test the echo filter
|
|
71
|
+
* applies: a novel attribute or a traceback from anywhere but
|
|
72
|
+
* `resourcemonitor.py` is not this incident and must keep failing the run.
|
|
74
73
|
*
|
|
75
74
|
* The shutdown-marker precondition the echo filter adds is intentionally
|
|
76
|
-
* omitted:
|
|
77
|
-
* the teardown crash prevented the shutdown marker from
|
|
75
|
+
* omitted: at the classification layer the case that matters is exactly
|
|
76
|
+
* the one where the teardown crash prevented the shutdown marker from
|
|
77
|
+
* printing.
|
|
78
78
|
*
|
|
79
|
-
* Pure
|
|
79
|
+
* Pure. Exported for the classifier and for direct unit testing.
|
|
80
80
|
*
|
|
81
81
|
* @param output - Raw captured stdout/stderr
|
|
82
82
|
* @returns True when the recognized teardown traceback is present
|
|
83
83
|
*/
|
|
84
84
|
export function hasKnownTeardownNoise(output) {
|
|
85
|
-
return
|
|
85
|
+
return (KNOWN_TEARDOWN_ATTRIBUTE_ERROR_PATTERN.test(output) &&
|
|
86
|
+
RESOURCEMONITOR_FRAME_PATTERN.test(output));
|
|
86
87
|
}
|
|
87
88
|
/**
|
|
88
|
-
* True when a
|
|
89
|
+
* True when a single line is the documented teardown family's
|
|
89
90
|
* `AttributeError`.
|
|
90
91
|
*
|
|
91
|
-
* The line-level half of {@link hasKnownTeardownNoise}: the traceback
|
|
92
|
+
* The line-level half of {@link hasKnownTeardownNoise}: the traceback frame
|
|
92
93
|
* lives on a neighbouring line, so a per-line test cannot apply the
|
|
93
94
|
* two-signal rule by itself. Callers pair this with
|
|
94
|
-
* `hasKnownTeardownNoise(wholeOutput)` to recover the full recognition
|
|
95
|
-
* "this capture carries the incident, and
|
|
95
|
+
* `hasKnownTeardownNoise(wholeOutput)` to recover the full recognition
|
|
96
|
+
* ("this capture carries the incident, and this line is its header"), which
|
|
96
97
|
* keeps the closed attribute allowlist (`stop_time`/`poll_interval`) doing
|
|
97
98
|
* the same work it does everywhere else. A novel attribute is not this
|
|
98
99
|
* incident and must stay a candidate failure.
|
|
@@ -103,13 +104,13 @@ export function hasKnownTeardownNoise(output) {
|
|
|
103
104
|
export function isKnownTeardownNoiseLine(line) {
|
|
104
105
|
return KNOWN_TEARDOWN_ATTRIBUTE_ERROR_PATTERN.test(line);
|
|
105
106
|
}
|
|
106
|
-
/** Fresh per-run context
|
|
107
|
+
/** Fresh per-run context. Hand the same instance to both stream filters. */
|
|
107
108
|
export function createTeardownNoiseContext() {
|
|
108
109
|
return { shutdownSeen: false };
|
|
109
110
|
}
|
|
110
111
|
/**
|
|
111
|
-
* Build-phase note for the
|
|
112
|
-
* not
|
|
112
|
+
* Build-phase note for the same recognized signature. The build path does
|
|
113
|
+
* not collapse the traceback (see the module doc's "test-only" note). It
|
|
113
114
|
* prints verbatim and this line is added beside it, so one signature reads
|
|
114
115
|
* the same in both phases without a build losing output it may need.
|
|
115
116
|
*/
|
|
@@ -125,7 +126,7 @@ const HOLD_BYTE_LIMIT = 16 * 1024;
|
|
|
125
126
|
/**
|
|
126
127
|
* Creates a stateful filter for one output stream. Complete lines outside a
|
|
127
128
|
* traceback pass straight through (only the trailing partial line is held
|
|
128
|
-
* back)
|
|
129
|
+
* back). A `Traceback (most recent call last)` header switches to hold mode
|
|
129
130
|
* until the block ends, then either the one-line annotation (recognized
|
|
130
131
|
* signature after a seen shutdown marker) or the verbatim block (anything
|
|
131
132
|
* else) is emitted. Pass the run's shared {@link TeardownNoiseContext} so
|
|
@@ -134,18 +135,18 @@ const HOLD_BYTE_LIMIT = 16 * 1024;
|
|
|
134
135
|
export function createKnownTeardownNoiseFilter(context = createTeardownNoiseContext()) {
|
|
135
136
|
/** Partial (no trailing newline yet) input line. */
|
|
136
137
|
let partial = '';
|
|
137
|
-
/** Held traceback lines (each
|
|
138
|
+
/** Held traceback lines (each with its newline) while in hold mode. */
|
|
138
139
|
let held = [];
|
|
139
140
|
let heldBytes = 0;
|
|
140
141
|
/**
|
|
141
142
|
* State machine:
|
|
142
|
-
* 'pass'
|
|
143
|
-
* 'inside'
|
|
144
|
-
* 'closed'
|
|
145
|
-
*
|
|
146
|
-
*
|
|
147
|
-
*
|
|
148
|
-
*
|
|
143
|
+
* 'pass': outside any traceback, so lines echo through.
|
|
144
|
+
* 'inside': between a Traceback header and its closing exception line.
|
|
145
|
+
* 'closed': saw the closing `SomeError: …` line, still holding in
|
|
146
|
+
* case a chained-exception connector continues the block
|
|
147
|
+
* (the real fixture chains two tracebacks, so the whole
|
|
148
|
+
* chain must be evaluated as one block or the second half
|
|
149
|
+
* would print raw after the annotation).
|
|
149
150
|
*/
|
|
150
151
|
let state = 'pass';
|
|
151
152
|
const resetHold = () => {
|
|
@@ -159,7 +160,7 @@ export function createKnownTeardownNoiseFilter(context = createTeardownNoiseCont
|
|
|
159
160
|
const block = resetHold();
|
|
160
161
|
if (block.length === 0)
|
|
161
162
|
return '';
|
|
162
|
-
return context.shutdownSeen &&
|
|
163
|
+
return context.shutdownSeen && hasKnownTeardownNoise(block)
|
|
163
164
|
? KNOWN_TEARDOWN_NOISE_ANNOTATION
|
|
164
165
|
: block;
|
|
165
166
|
};
|
|
@@ -168,7 +169,7 @@ export function createKnownTeardownNoiseFilter(context = createTeardownNoiseCont
|
|
|
168
169
|
heldBytes += line.length;
|
|
169
170
|
if (held.length > HOLD_LINE_LIMIT || heldBytes > HOLD_BYTE_LIMIT) {
|
|
170
171
|
// Pathological block: flush verbatim rather than risk withholding
|
|
171
|
-
// output
|
|
172
|
+
// output. Do not attempt recognition on oversized blocks.
|
|
172
173
|
return { out: resetHold(), overflowed: true };
|
|
173
174
|
}
|
|
174
175
|
return { out: '', overflowed: false };
|
|
@@ -189,7 +190,7 @@ export function createKnownTeardownNoiseFilter(context = createTeardownNoiseCont
|
|
|
189
190
|
/^[ \t]/.test(content) ||
|
|
190
191
|
TRACEBACK_HEADER_PATTERN.test(content);
|
|
191
192
|
const { out, overflowed } = hold(line);
|
|
192
|
-
// The first unindented line is the closing `SomeError: …` line
|
|
193
|
+
// The first unindented line is the closing `SomeError: …` line. Keep
|
|
193
194
|
// holding in case a chained connector extends the block.
|
|
194
195
|
if (!overflowed && !isContinuation) {
|
|
195
196
|
state = 'closed';
|
|
@@ -209,8 +210,8 @@ export function createKnownTeardownNoiseFilter(context = createTeardownNoiseCont
|
|
|
209
210
|
}
|
|
210
211
|
return releaseHeld() + processLineInPass(line);
|
|
211
212
|
};
|
|
212
|
-
// Re-dispatch a line through pass-mode handling after a block release
|
|
213
|
-
//
|
|
213
|
+
// Re-dispatch a line through pass-mode handling after a block release.
|
|
214
|
+
// The line that ended the block may itself start a new traceback.
|
|
214
215
|
const processLineInPass = (line) => {
|
|
215
216
|
const content = line.replace(/\r?\n$/, '');
|
|
216
217
|
if (TRACEBACK_HEADER_PATTERN.test(content)) {
|
|
@@ -240,7 +241,7 @@ export function createKnownTeardownNoiseFilter(context = createTeardownNoiseCont
|
|
|
240
241
|
let out = '';
|
|
241
242
|
if (state !== 'pass') {
|
|
242
243
|
// A stream that closes mid-block: fold the trailing partial line in
|
|
243
|
-
// and evaluate
|
|
244
|
+
// and evaluate. The final exception line is often the last thing
|
|
244
245
|
// printed, without a trailing newline.
|
|
245
246
|
if (partial.length > 0) {
|
|
246
247
|
held.push(partial);
|
|
@@ -10,7 +10,7 @@ export interface MozconfigVariables {
|
|
|
10
10
|
}
|
|
11
11
|
/**
|
|
12
12
|
* Extracts the `--with-branding=<path>` value from a rendered mozconfig
|
|
13
|
-
* body. Returns `undefined` when no directive is present
|
|
13
|
+
* body. Returns `undefined` when no directive is present, and callers treat
|
|
14
14
|
* that as "mozconfig is missing branding", which is itself an actionable
|
|
15
15
|
* configuration error.
|
|
16
16
|
*
|
|
@@ -18,13 +18,13 @@ export interface MozconfigVariables {
|
|
|
18
18
|
*/
|
|
19
19
|
export declare function extractWithBrandingPath(mozconfigContent: string): string | undefined;
|
|
20
20
|
/**
|
|
21
|
-
* Extracts the objdir
|
|
21
|
+
* Extracts the objdir name a mozconfig declares: the single trailing path
|
|
22
22
|
* segment, which is what the `obj-*` scan enumerates.
|
|
23
23
|
*
|
|
24
24
|
* `@TOPSRCDIR@` and a leading `./` are both spellings of "beside the
|
|
25
|
-
* source", which is the only arrangement FireForge's scan can see anyway
|
|
26
|
-
*
|
|
27
|
-
* simply will not match a candidate, which is the correct outcome
|
|
25
|
+
* source", which is the only arrangement FireForge's scan can see anyway.
|
|
26
|
+
* An absolute path outside the engine directory reduces to its basename and
|
|
27
|
+
* simply will not match a candidate, which is the correct outcome. A
|
|
28
28
|
* declaration that names something the scan cannot see must not select
|
|
29
29
|
* anything.
|
|
30
30
|
*
|
|
@@ -33,7 +33,7 @@ export declare function extractWithBrandingPath(mozconfigContent: string): strin
|
|
|
33
33
|
export declare function extractMozObjdirName(mozconfigContent: string): string | undefined;
|
|
34
34
|
/**
|
|
35
35
|
* Preflights the just-written mozconfig against the branding tree FireForge
|
|
36
|
-
* set up. A drift between the two is silent-corruption territory
|
|
36
|
+
* set up. A drift between the two is silent-corruption territory: the
|
|
37
37
|
* build runs, `mach configure` reads the stale directory name out of
|
|
38
38
|
* mozconfig, and then the recursive make backend errors out with a "path
|
|
39
39
|
* does not exist" message that names the branding dir the mozconfig
|
|
@@ -3,6 +3,7 @@ import { join } from 'node:path';
|
|
|
3
3
|
import { MozconfigError } from '../errors/build.js';
|
|
4
4
|
import { pathExists, readText, writeTextIfChanged } from '../utils/fs.js';
|
|
5
5
|
import { verbose } from '../utils/logger.js';
|
|
6
|
+
import { normalizePathSlashes } from '../utils/paths.js';
|
|
6
7
|
import { getPlatform } from '../utils/platform.js';
|
|
7
8
|
import { BrandingMozconfigMismatchError, splitAppId } from './branding.js';
|
|
8
9
|
/**
|
|
@@ -20,17 +21,17 @@ function replaceVariables(content, variables) {
|
|
|
20
21
|
}
|
|
21
22
|
/**
|
|
22
23
|
* Matches an `--with-branding=<path>` directive anywhere in a rendered
|
|
23
|
-
* mozconfig. The directive form is the one mach reads
|
|
24
|
+
* mozconfig. The directive form is the one mach reads, and an optional
|
|
24
25
|
* `ac_add_options` prefix is the on-disk convention. `m` flag anchors the
|
|
25
26
|
* search per-line so a multi-line mozconfig with older directives earlier
|
|
26
|
-
* in the file doesn't confuse the extractor. We pick the
|
|
27
|
+
* in the file doesn't confuse the extractor. We pick the last match
|
|
27
28
|
* because mach itself takes the last-write-wins semantics of shell
|
|
28
29
|
* configuration for overlapping `ac_add_options` calls.
|
|
29
30
|
*/
|
|
30
31
|
const WITH_BRANDING_PATTERN = /^\s*(?:ac_add_options\s+)?--with-branding\s*=\s*(\S+)/gm;
|
|
31
32
|
/**
|
|
32
33
|
* Extracts the `--with-branding=<path>` value from a rendered mozconfig
|
|
33
|
-
* body. Returns `undefined` when no directive is present
|
|
34
|
+
* body. Returns `undefined` when no directive is present, and callers treat
|
|
34
35
|
* that as "mozconfig is missing branding", which is itself an actionable
|
|
35
36
|
* configuration error.
|
|
36
37
|
*
|
|
@@ -50,13 +51,13 @@ export function extractWithBrandingPath(mozconfigContent) {
|
|
|
50
51
|
*/
|
|
51
52
|
const MOZ_OBJDIR_PATTERN = /^\s*(?:mk_add_options\s+|export\s+)?MOZ_OBJDIR\s*=\s*["']?([^"'\s#]+)/gm;
|
|
52
53
|
/**
|
|
53
|
-
* Extracts the objdir
|
|
54
|
+
* Extracts the objdir name a mozconfig declares: the single trailing path
|
|
54
55
|
* segment, which is what the `obj-*` scan enumerates.
|
|
55
56
|
*
|
|
56
57
|
* `@TOPSRCDIR@` and a leading `./` are both spellings of "beside the
|
|
57
|
-
* source", which is the only arrangement FireForge's scan can see anyway
|
|
58
|
-
*
|
|
59
|
-
* simply will not match a candidate, which is the correct outcome
|
|
58
|
+
* source", which is the only arrangement FireForge's scan can see anyway.
|
|
59
|
+
* An absolute path outside the engine directory reduces to its basename and
|
|
60
|
+
* simply will not match a candidate, which is the correct outcome. A
|
|
60
61
|
* declaration that names something the scan cannot see must not select
|
|
61
62
|
* anything.
|
|
62
63
|
*
|
|
@@ -73,7 +74,7 @@ export function extractMozObjdirName(mozconfigContent) {
|
|
|
73
74
|
}
|
|
74
75
|
/**
|
|
75
76
|
* Preflights the just-written mozconfig against the branding tree FireForge
|
|
76
|
-
* set up. A drift between the two is silent-corruption territory
|
|
77
|
+
* set up. A drift between the two is silent-corruption territory: the
|
|
77
78
|
* build runs, `mach configure` reads the stale directory name out of
|
|
78
79
|
* mozconfig, and then the recursive make backend errors out with a "path
|
|
79
80
|
* does not exist" message that names the branding dir the mozconfig
|
|
@@ -93,10 +94,10 @@ export async function assertBrandingMozconfigAgreement(engineDir, mozconfigPath,
|
|
|
93
94
|
if (!found) {
|
|
94
95
|
throw new BrandingMozconfigMismatchError(expected, '(no --with-branding directive)', 'mozconfig-missing-branding');
|
|
95
96
|
}
|
|
96
|
-
// Normalise both sides to forward slashes before compare
|
|
97
|
+
// Normalise both sides to forward slashes before compare. Windows-edited
|
|
97
98
|
// configs can carry backslash path separators that the build would treat
|
|
98
99
|
// as literal characters in a repo-relative path.
|
|
99
|
-
const normalizedFound = found
|
|
100
|
+
const normalizedFound = normalizePathSlashes(found);
|
|
100
101
|
if (normalizedFound !== expected) {
|
|
101
102
|
throw new BrandingMozconfigMismatchError(expected, found, 'name-mismatch');
|
|
102
103
|
}
|
|
@@ -126,9 +127,9 @@ export async function generateMozconfig(configsDir, engineDir, config) {
|
|
|
126
127
|
binaryName: config.binaryName,
|
|
127
128
|
};
|
|
128
129
|
let content = '';
|
|
129
|
-
// Bundle identity: branding configure.sh carries only the
|
|
130
|
-
// (see splitAppId in branding.ts
|
|
131
|
-
// <distribution-id>.<MOZ_MACBUNDLE_ID>)
|
|
130
|
+
// Bundle identity: branding configure.sh carries only the leaf of appId
|
|
131
|
+
// (see splitAppId in branding.ts, and upstream composes the mac bundle id
|
|
132
|
+
// as <distribution-id>.<MOZ_MACBUNDLE_ID>). The prefix travels here so the
|
|
132
133
|
// two halves can never drift apart.
|
|
133
134
|
const { distributionId } = splitAppId(config.appId);
|
|
134
135
|
content +=
|
|
@@ -145,11 +146,11 @@ export async function generateMozconfig(configsDir, engineDir, config) {
|
|
|
145
146
|
}
|
|
146
147
|
const platformContent = await readText(platformPath);
|
|
147
148
|
content += `# Platform configuration (${platform})\n${replaceVariables(platformContent, variables)}`;
|
|
148
|
-
// Write-if-changed: `mozconfig` is a mach
|
|
149
|
-
//
|
|
149
|
+
// Write-if-changed: `mozconfig` is a mach configure input, so its mtime,
|
|
150
|
+
// not its content, is what `config.status` compares against.
|
|
150
151
|
// Rewriting a byte-identical file on every build-capable invocation made
|
|
151
152
|
// mach re-run `configure` plus backend regeneration ("Backend config
|
|
152
|
-
// changed; N files touched") on
|
|
153
|
+
// changed; N files touched") on every run, each run re-arming the next.
|
|
153
154
|
// Only touch the file when the rendered content actually differs.
|
|
154
155
|
const wrote = await writeTextIfChanged(outputPath, content);
|
|
155
156
|
if (!wrote) {
|
|
@@ -6,7 +6,12 @@ import { pathExists, readText } from '../utils/fs.js';
|
|
|
6
6
|
import { verbose } from '../utils/logger.js';
|
|
7
7
|
import { exec, executableExists } from '../utils/process.js';
|
|
8
8
|
/** Cached Python resolution state */
|
|
9
|
-
|
|
9
|
+
/**
|
|
10
|
+
* The resolved interpreter and the requirement range it was resolved for.
|
|
11
|
+
* `undefined` means "not resolved yet". The two always move together, so
|
|
12
|
+
* one nullable record beats two independently-deletable fields.
|
|
13
|
+
*/
|
|
14
|
+
let pythonCache;
|
|
10
15
|
const DEFAULT_MACH_PYTHON_REQUIREMENTS = {
|
|
11
16
|
min: { major: 3, minor: 8 },
|
|
12
17
|
max: { major: 3, minor: 12 },
|
|
@@ -73,10 +78,12 @@ function buildPythonCandidates(requirements) {
|
|
|
73
78
|
}
|
|
74
79
|
/**
|
|
75
80
|
* Resets the resolved Python executable. Primarily useful for testing.
|
|
81
|
+
*
|
|
82
|
+
* @internal Exported only so tests can reach it. Not part of the public
|
|
83
|
+
* surface.
|
|
76
84
|
*/
|
|
77
85
|
export function resetResolvedPython() {
|
|
78
|
-
|
|
79
|
-
delete pythonCache.requirementsKey;
|
|
86
|
+
pythonCache = undefined;
|
|
80
87
|
}
|
|
81
88
|
/**
|
|
82
89
|
* Dynamically resolves the python executable and ensures it is available.
|
|
@@ -86,7 +93,7 @@ export function resetResolvedPython() {
|
|
|
86
93
|
export async function ensurePython(engineDir) {
|
|
87
94
|
const requirements = await readMachPythonRequirements(engineDir);
|
|
88
95
|
const requirementsKey = formatRequirementsKey(requirements);
|
|
89
|
-
if (pythonCache
|
|
96
|
+
if (pythonCache?.requirementsKey === requirementsKey) {
|
|
90
97
|
return;
|
|
91
98
|
}
|
|
92
99
|
const candidates = buildPythonCandidates(requirements);
|
|
@@ -99,8 +106,7 @@ export async function ensurePython(engineDir) {
|
|
|
99
106
|
]);
|
|
100
107
|
const version = parsePythonVersion(stdout);
|
|
101
108
|
if (version && isVersionWithinRequirements(version, requirements)) {
|
|
102
|
-
pythonCache
|
|
103
|
-
pythonCache.requirementsKey = requirementsKey;
|
|
109
|
+
pythonCache = { python: candidate, requirementsKey };
|
|
104
110
|
return;
|
|
105
111
|
}
|
|
106
112
|
}
|
|
@@ -118,7 +124,7 @@ export async function ensurePython(engineDir) {
|
|
|
118
124
|
*/
|
|
119
125
|
export async function getPython(engineDir) {
|
|
120
126
|
await ensurePython(engineDir);
|
|
121
|
-
if (
|
|
127
|
+
if (pythonCache === undefined) {
|
|
122
128
|
throw new PythonNotFoundError();
|
|
123
129
|
}
|
|
124
130
|
return pythonCache.python;
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
*
|
|
13
13
|
* The guard is installed as a `fireforge_mach_guard.pth` + module pair in
|
|
14
14
|
* every discovered mach virtualenv site-packages directory. A PYTHONPATH
|
|
15
|
-
* `sitecustomize.py` is
|
|
15
|
+
* `sitecustomize.py` is not sufficient on its own: mach re-execs itself into
|
|
16
16
|
* its private virtualenv and drops PYTHONPATH, so that route never loads.
|
|
17
17
|
* `.pth` files execute at interpreter startup from the venv's own
|
|
18
18
|
* site-packages, which survives the re-exec. The PYTHONPATH copy is retained
|
|
@@ -21,12 +21,12 @@
|
|
|
21
21
|
*
|
|
22
22
|
* The guard covers the whole crash family:
|
|
23
23
|
* - wraps `psutil.virtual_memory` / `swap_memory` / `cpu_percent` /
|
|
24
|
-
* `cpu_times` / `disk_io_counters` module-wide, so every call site
|
|
24
|
+
* `cpu_times` / `disk_io_counters` module-wide, so every call site,
|
|
25
25
|
* including the direct `psutil.virtual_memory()` in
|
|
26
|
-
* `mozbuild.base._run_make
|
|
26
|
+
* `mozbuild.base._run_make`, degrades to a `UserWarning` and a zeroed
|
|
27
27
|
* reading instead of aborting.
|
|
28
28
|
*
|
|
29
|
-
* The fallback must be per-function
|
|
29
|
+
* The fallback must be per-function arity-correct and reconstructible:
|
|
30
30
|
* mozsystemmonitor captures reading types at `__init__`
|
|
31
31
|
* (`self._swap_type = type(psutil.swap_memory())`) and rebuilds each
|
|
32
32
|
* collector sample via `self._swap_type(*swap_mem)`. An svmem-shaped
|
|
@@ -36,28 +36,28 @@
|
|
|
36
36
|
* sentinel, and mach hangs forever in its atexit `waitpid`. Each wrapped
|
|
37
37
|
* function therefore degrades to a zeroed instance of psutil's own result
|
|
38
38
|
* namedtuple where resolvable, else a module-level guard-owned namedtuple
|
|
39
|
-
* with the exact field order and arity for
|
|
39
|
+
* with the exact field order and arity for that function (module-level so
|
|
40
40
|
* readings pickle by reference across the collector pipe).
|
|
41
41
|
* `_DegradedReading` remains only as a documented last resort and
|
|
42
42
|
* tolerates `type(reading)(*values)` reconstruction. Guard-owned fallback
|
|
43
43
|
* classes never depend on psutil internals resolving, which also makes
|
|
44
44
|
* them safe when two guard copies load (PYTHONPATH `sitecustomize` in the
|
|
45
|
-
* bootstrap phase plus the in-venv `.pth`), each with its own classes
|
|
46
|
-
* - guards `SystemResourceMonitor`
|
|
45
|
+
* bootstrap phase plus the in-venv `.pth`), each with its own classes.
|
|
46
|
+
* - guards `SystemResourceMonitor` construction via an import hook:
|
|
47
47
|
* `poll_interval` is pre-populated before the real `__init__` runs, a
|
|
48
48
|
* failing `__init__` marks the instance degraded instead of raising, and
|
|
49
|
-
* every monitor method no-ops on a degraded instance
|
|
49
|
+
* every monitor method no-ops on a degraded instance, so a
|
|
50
50
|
* partially-constructed monitor can never surface the
|
|
51
51
|
* `AttributeError: poll_interval` variant. Degraded aggregate methods
|
|
52
52
|
* return zeroed shapes (not `None`) where callers subscript the result
|
|
53
53
|
* (`aggregate_io` → zeroed io reading, so mozbuild's `log_resource_usage`
|
|
54
|
-
* does not die on `usage["io"].read_bytes` after a successful compile)
|
|
54
|
+
* does not die on `usage["io"].read_bytes` after a successful compile).
|
|
55
55
|
* - suppresses the mozsystemmonitor collector child on degradation: once
|
|
56
56
|
* any psutil degradation is observed in the process, monitors are kept
|
|
57
57
|
* inert (`start` never spawns the collector), and a degraded transition
|
|
58
58
|
* or raising `stop` best-effort terminates a live collector child and
|
|
59
59
|
* drains the pipe, so a malformed sample stream cannot wedge mach's
|
|
60
|
-
* shutdown even if a future shape mismatch slips through
|
|
60
|
+
* shutdown even if a future shape mismatch slips through.
|
|
61
61
|
* - wraps `mozbuild.controller.building.BuildMonitor.log_resource_usage` to
|
|
62
62
|
* warn-and-continue on any exception, so end-of-build resource reporting
|
|
63
63
|
* can never fail a build whose artifacts are complete.
|
|
@@ -71,7 +71,7 @@
|
|
|
71
71
|
* regression test (mach-resource-shim.python.test.ts), which asserts the
|
|
72
72
|
* degraded readings' runtime behavior rather than string-matching the source.
|
|
73
73
|
*/
|
|
74
|
-
export declare const GUARD_PYTHON_SOURCE = "# Generated by FireForge - do not edit.\n# Degrades the broken host resource monitor family (psutil vs Darwin) from\n# fatal startup errors into non-fatal warnings, so mach builds and tests\n# proceed. Installed into the mach virtualenv site-packages via a .pth file\n# (survives mach's venv re-exec, which drops PYTHONPATH).\nimport builtins\nimport collections\nimport sys\nimport warnings\n\n# Any psutil degradation observed in this process. Once set, monitors are\n# kept inert (start never spawns the collector child) \u2014 on a flapping host a\n# healthy-looking moment must not be trusted to start a sample stream that a\n# later degraded reading could malform.\n_fireforge_host_degraded = [False]\n\n\ndef _fireforge_degraded_notice(exc):\n _fireforge_host_degraded[0] = True\n warnings.warn(\n \"FireForge: host resource monitor degraded (%s); continuing without resource monitoring.\" % exc\n )\n\n\nclass _DegradedReading(object):\n # Last-resort duck type of psutil's namedtuple results (svmem field\n # order): mozsystemmonitor subscripts, iterates, and unpacks readings,\n # so the degraded fallback must survive r[0], list(r), len(r), r._fields\n # and r._asdict(), not just attribute access. The parent also reconstructs\n # readings via type(reading)(*values), so the constructor must tolerate\n # the full positional field list. Normal\n # degraded paths use the per-function namedtuple fallbacks below; this\n # class only backstops a fallback that itself raised.\n _fields = (\"total\", \"available\", \"percent\", \"used\", \"free\", \"active\", \"inactive\", \"wired\")\n total = available = used = free = active = inactive = wired = 0\n percent = 0.0\n\n def __init__(self, *_args, **_kwargs):\n pass\n\n def __getattr__(self, _name):\n return 0\n\n def _values(self):\n return tuple(getattr(self, _field) for _field in self._fields)\n\n def __getitem__(self, index):\n return self._values()[index]\n\n def __iter__(self):\n return iter(self._values())\n\n def __len__(self):\n return len(self._fields)\n\n def _asdict(self):\n return dict(zip(self._fields, self._values()))\n\n\n# Per-function fallback result classes with the exact macOS field\n# orders/arities. Module-level on purpose: readings cross the\n# mozsystemmonitor collector pipe via pickle (by reference), and the parent\n# rebuilds each sample with type(reading)(*values) \u2014 so a swap fallback must\n# be 6-field sswap-shaped in every position. An svmem-shaped fallback there\n# makes the parent reject every sample, fill the pipe, block the collector\n# child in send(), and wedge mach's atexit join forever.\n_FallbackVmem = collections.namedtuple(\n \"_FallbackVmem\",\n (\"total\", \"available\", \"percent\", \"used\", \"free\", \"active\", \"inactive\", \"wired\"),\n)\n_FallbackSwap = collections.namedtuple(\n \"_FallbackSwap\", (\"total\", \"used\", \"free\", \"percent\", \"sin\", \"sout\")\n)\n_FallbackCpuTimes = collections.namedtuple(\"_FallbackCpuTimes\", (\"user\", \"nice\", \"system\", \"idle\"))\n_FallbackDiskIO = collections.namedtuple(\n \"_FallbackDiskIO\",\n (\"read_count\", \"write_count\", \"read_bytes\", \"write_bytes\", \"read_time\", \"write_time\"),\n)\n\n_FALLBACK_CLASSES = {\n \"virtual_memory\": _FallbackVmem,\n \"swap_memory\": _FallbackSwap,\n \"cpu_times\": _FallbackCpuTimes,\n \"disk_io_counters\": _FallbackDiskIO,\n}\n\n# psutil result namedtuple per wrapped function, resolvable via getattr from\n# the platform module / _common without invoking the failing syscall.\n_PSUTIL_RESULT_CLASSES = {\n \"virtual_memory\": \"svmem\",\n \"swap_memory\": \"sswap\",\n \"cpu_times\": \"scputimes\",\n \"disk_io_counters\": \"sdiskio\",\n}\n\n\ndef _zeroed(cls):\n return cls(*([0] * len(cls._fields)))\n\n\ndef _percpu_requested(args, kwargs, positional_index):\n if \"percpu\" in kwargs:\n return bool(kwargs[\"percpu\"])\n return len(args) > positional_index and bool(args[positional_index])\n\n\ndef _degraded_result_factory(psutil, name):\n # cpu_percent returns a plain float (or a per-CPU list) callers do\n # arithmetic on.\n if name == \"cpu_percent\":\n def _cpu_percent_fallback(*args, **kwargs):\n # cpu_percent(interval=None, percpu=False)\n if _percpu_requested(args, kwargs, 1):\n return []\n return 0.0\n\n return _cpu_percent_fallback\n # The guard-owned class is always shape-correct for this function;\n # psutil's own result namedtuple is still preferred when resolvable so\n # type() captures stay identical to real readings on a flapping host.\n _cls = _FALLBACK_CLASSES.get(name, _DegradedReading)\n _cls_name = _PSUTIL_RESULT_CLASSES.get(name)\n if _cls_name is not None:\n for _mod in (getattr(psutil, \"_psplatform\", None), getattr(psutil, \"_common\", None)):\n _real = getattr(_mod, _cls_name, None) if _mod is not None else None\n if _real is not None and getattr(_real, \"_fields\", None):\n _cls = _real\n break\n if name == \"cpu_times\":\n def _cpu_times_fallback(*args, **kwargs):\n # cpu_times(percpu=False); the collector child samples per-CPU.\n if _percpu_requested(args, kwargs, 0):\n return []\n return _zeroed(_cls)\n\n return _cpu_times_fallback\n\n def _reading_fallback(*_args, **_kwargs):\n return _zeroed(_cls)\n\n return _reading_fallback\n\n\ndef _guard_psutil():\n try:\n import psutil\n except Exception:\n return\n\n def _wrap(orig, fallback):\n def wrapper(*args, **kwargs):\n try:\n return orig(*args, **kwargs)\n except Exception as exc: # noqa: BLE001\n _fireforge_degraded_notice(exc)\n try:\n return fallback(*args, **kwargs)\n except Exception: # noqa: BLE001\n return _DegradedReading()\n\n return wrapper\n\n for _name in (\"virtual_memory\", \"swap_memory\", \"cpu_percent\", \"cpu_times\", \"disk_io_counters\"):\n _orig = getattr(psutil, _name, None)\n if _orig is not None and not getattr(_orig, \"_fireforge_guarded\", False):\n try:\n _fallback = _degraded_result_factory(psutil, _name)\n except Exception: # noqa: BLE001\n _fallback = _DegradedReading\n _wrapped = _wrap(_orig, _fallback)\n _wrapped._fireforge_guarded = True\n setattr(psutil, _name, _wrapped)\n\n\n_MONITOR_METHOD_NAMES = (\n \"start\",\n \"stop\",\n \"record_event\",\n \"record_marker\",\n \"begin_phase\",\n \"finish_phase\",\n \"aggregate_cpu_percent\",\n \"aggregate_cpu_times\",\n \"aggregate_io\",\n \"min_memory_available\",\n \"as_dict\",\n)\n\n\ndef _fireforge_stop_collector(monitor):\n # Best-effort: terminate a live collector child and drain the parent end\n # of the pipe, so a child blocked in send() on a full pipe can never\n # keep mach's atexit join (os.waitpid) waiting forever. Attribute names\n # follow upstream resourcemonitor.py (self._process / self._pipe); a\n # miss on a refactored upstream is harmless \u2014 the shape-correct\n # fallbacks above still keep the sample stream well-formed.\n try:\n proc = getattr(monitor, \"_process\", None)\n if proc is not None and getattr(proc, \"is_alive\", lambda: False)():\n proc.terminate()\n proc.join(1)\n except Exception: # noqa: BLE001\n pass\n try:\n pipe = getattr(monitor, \"_pipe\", None)\n if pipe is not None:\n while pipe.poll(0):\n pipe.recv()\n except Exception: # noqa: BLE001\n pass\n\n\ndef _monitor_per_cpu_requested(args, kwargs):\n # aggregate_cpu_percent/aggregate_cpu_times(start=None, end=None,\n # phase=None, per_cpu=True) \u2014 self already stripped from args.\n if \"per_cpu\" in kwargs:\n return bool(kwargs[\"per_cpu\"])\n if len(args) > 3:\n return bool(args[3])\n return True\n\n\ndef _monitor_degraded_result(name, args, kwargs):\n # Degraded aggregate methods return zeroed shapes, not None, where\n # callers subscript the result: mozbuild's log_resource_usage does\n # usage[\"io\"].read_bytes after a successful compile, so None there fails\n # the build with complete artifacts already on disk.\n if name == \"aggregate_io\":\n return _zeroed(_FallbackDiskIO)\n if name == \"aggregate_cpu_percent\":\n return [] if _monitor_per_cpu_requested(args, kwargs) else 0.0\n if name == \"aggregate_cpu_times\":\n return [] if _monitor_per_cpu_requested(args, kwargs) else _zeroed(_FallbackCpuTimes)\n return None\n\n\ndef _patch_monitor_class(cls):\n if cls is None or getattr(cls, \"_fireforge_guarded\", False):\n return\n orig_init = cls.__init__\n\n def guarded_init(self, *args, **kwargs):\n # Pre-populate the attributes a partially-constructed instance is\n # later polled for, so a failing __init__ can never surface\n # AttributeError: poll_interval.\n self.poll_interval = kwargs.get(\"poll_interval\") or 1.0\n self._fireforge_degraded = False\n try:\n orig_init(self, *args, **kwargs)\n except Exception as exc: # noqa: BLE001\n self._fireforge_degraded = True\n _fireforge_degraded_notice(exc)\n if _fireforge_host_degraded[0] and not self._fireforge_degraded:\n # Host already degraded once: keep the monitor inert so the\n # collector child never spawns on a flapping host.\n self._fireforge_degraded = True\n if self._fireforge_degraded:\n _fireforge_stop_collector(self)\n\n cls.__init__ = guarded_init\n\n def _wrap_method(name, orig):\n def wrapper(self, *args, **kwargs):\n if (\n name == \"start\"\n and _fireforge_host_degraded[0]\n and not getattr(self, \"_fireforge_degraded\", False)\n ):\n self._fireforge_degraded = True\n _fireforge_stop_collector(self)\n if getattr(self, \"_fireforge_degraded\", False):\n if name == \"stop\":\n _fireforge_stop_collector(self)\n return _monitor_degraded_result(name, args, kwargs)\n try:\n return orig(self, *args, **kwargs)\n except Exception as exc: # noqa: BLE001\n self._fireforge_degraded = True\n _fireforge_degraded_notice(exc)\n # A raising stop (or any degraded transition) must still\n # take the collector child down, or the parent's atexit\n # join hangs on a child blocked writing to a full pipe.\n _fireforge_stop_collector(self)\n return _monitor_degraded_result(name, args, kwargs)\n\n return wrapper\n\n for _name in _MONITOR_METHOD_NAMES:\n _orig = getattr(cls, _name, None)\n if _orig is not None:\n setattr(cls, _name, _wrap_method(_name, _orig))\n cls._fireforge_guarded = True\n\n\ndef _patch_build_monitor_class(cls):\n # mozbuild's BuildMonitor is not a SystemResourceMonitor; only\n # log_resource_usage needs guarding \u2014 end-of-build resource reporting\n # must never fail a build whose artifacts are complete. No __init__\n # replacement, no degraded-instance gating.\n if cls is None or getattr(cls, \"_fireforge_guarded\", False):\n return\n _orig = getattr(cls, \"log_resource_usage\", None)\n if _orig is not None:\n def _guarded_log_resource_usage(self, *args, **kwargs):\n try:\n return _orig(self, *args, **kwargs)\n except Exception as exc: # noqa: BLE001\n _fireforge_degraded_notice(exc)\n return None\n\n cls.log_resource_usage = _guarded_log_resource_usage\n cls._fireforge_guarded = True\n\n\n_MONITOR_CLASS_PATCHES = (\n (\"mozsystemmonitor.resourcemonitor\", \"SystemResourceMonitor\", _patch_monitor_class),\n (\"mozbuild.resources\", \"SystemResourceMonitor\", _patch_monitor_class),\n (\"mozbuild.controller.building\", \"BuildMonitor\", _patch_build_monitor_class),\n)\n\n\ndef _patch_loaded_monitor_modules():\n for _mod_name, _cls_name, _patcher in _MONITOR_CLASS_PATCHES:\n _mod = sys.modules.get(_mod_name)\n if _mod is not None:\n try:\n _patcher(getattr(_mod, _cls_name, None))\n except Exception: # noqa: BLE001\n pass\n\n\ndef _install_import_hook():\n _orig_import = builtins.__import__\n if getattr(_orig_import, \"_fireforge_guarded\", False):\n return\n\n def _guarding_import(name, *args, **kwargs):\n _module = _orig_import(name, *args, **kwargs)\n try:\n _patch_loaded_monitor_modules()\n except Exception: # noqa: BLE001\n pass\n return _module\n\n _guarding_import._fireforge_guarded = True\n builtins.__import__ = _guarding_import\n\n\ntry:\n _guard_psutil()\n _patch_loaded_monitor_modules()\n _install_import_hook()\nexcept Exception: # noqa: BLE001\n pass\n";
|
|
74
|
+
export declare const GUARD_PYTHON_SOURCE = "# Generated by FireForge - do not edit.\n# Degrades the broken host resource monitor family (psutil vs Darwin) from\n# fatal startup errors into non-fatal warnings, so mach builds and tests\n# proceed. Installed into the mach virtualenv site-packages via a .pth file\n# (survives mach's venv re-exec, which drops PYTHONPATH).\nimport builtins\nimport collections\nimport inspect\nimport sys\nimport warnings\n\n# Any psutil degradation observed in this process. Once set, monitors are\n# kept inert (start never spawns the collector child) \u2014 on a flapping host a\n# healthy-looking moment must not be trusted to start a sample stream that a\n# later degraded reading could malform.\n_fireforge_host_degraded = [False]\n\n\ndef _fireforge_degraded_notice(exc):\n _fireforge_host_degraded[0] = True\n warnings.warn(\n \"FireForge: host resource monitor degraded (%s); continuing without resource monitoring.\" % exc\n )\n\n\nclass _DegradedReading(object):\n # Last-resort duck type of psutil's namedtuple results (svmem field\n # order): mozsystemmonitor subscripts, iterates, and unpacks readings,\n # so the degraded fallback must survive r[0], list(r), len(r), r._fields\n # and r._asdict(), not just attribute access. The parent also reconstructs\n # readings via type(reading)(*values), so the constructor must tolerate\n # the full positional field list. Normal\n # degraded paths use the per-function namedtuple fallbacks below; this\n # class only backstops a fallback that itself raised.\n _fields = (\"total\", \"available\", \"percent\", \"used\", \"free\", \"active\", \"inactive\", \"wired\")\n total = available = used = free = active = inactive = wired = 0\n percent = 0.0\n\n def __init__(self, *_args, **_kwargs):\n pass\n\n def __getattr__(self, _name):\n return 0\n\n def _values(self):\n return tuple(getattr(self, _field) for _field in self._fields)\n\n def __getitem__(self, index):\n return self._values()[index]\n\n def __iter__(self):\n return iter(self._values())\n\n def __len__(self):\n return len(self._fields)\n\n def _asdict(self):\n return dict(zip(self._fields, self._values()))\n\n\n# Per-function fallback result classes with the exact macOS field\n# orders/arities. Module-level on purpose: readings cross the\n# mozsystemmonitor collector pipe via pickle (by reference), and the parent\n# rebuilds each sample with type(reading)(*values) \u2014 so a swap fallback must\n# be 6-field sswap-shaped in every position. An svmem-shaped fallback there\n# makes the parent reject every sample, fill the pipe, block the collector\n# child in send(), and wedge mach's atexit join forever.\n_FallbackVmem = collections.namedtuple(\n \"_FallbackVmem\",\n (\"total\", \"available\", \"percent\", \"used\", \"free\", \"active\", \"inactive\", \"wired\"),\n)\n_FallbackSwap = collections.namedtuple(\n \"_FallbackSwap\", (\"total\", \"used\", \"free\", \"percent\", \"sin\", \"sout\")\n)\n_FallbackCpuTimes = collections.namedtuple(\"_FallbackCpuTimes\", (\"user\", \"nice\", \"system\", \"idle\"))\n_FallbackDiskIO = collections.namedtuple(\n \"_FallbackDiskIO\",\n (\"read_count\", \"write_count\", \"read_bytes\", \"write_bytes\", \"read_time\", \"write_time\"),\n)\n\n_FALLBACK_CLASSES = {\n \"virtual_memory\": _FallbackVmem,\n \"swap_memory\": _FallbackSwap,\n \"cpu_times\": _FallbackCpuTimes,\n \"disk_io_counters\": _FallbackDiskIO,\n}\n\n# psutil result namedtuple per wrapped function, resolvable via getattr from\n# the platform module / _common without invoking the failing syscall.\n_PSUTIL_RESULT_CLASSES = {\n \"virtual_memory\": \"svmem\",\n \"swap_memory\": \"sswap\",\n \"cpu_times\": \"scputimes\",\n \"disk_io_counters\": \"sdiskio\",\n}\n\n\ndef _zeroed(cls):\n return cls(*([0] * len(cls._fields)))\n\n\ndef _percpu_requested(args, kwargs, positional_index):\n if \"percpu\" in kwargs:\n return bool(kwargs[\"percpu\"])\n return len(args) > positional_index and bool(args[positional_index])\n\n\ndef _degraded_result_factory(psutil, name):\n # cpu_percent returns a plain float (or a per-CPU list) callers do\n # arithmetic on.\n if name == \"cpu_percent\":\n def _cpu_percent_fallback(*args, **kwargs):\n # cpu_percent(interval=None, percpu=False)\n if _percpu_requested(args, kwargs, 1):\n return []\n return 0.0\n\n return _cpu_percent_fallback\n # The guard-owned class is always shape-correct for this function;\n # psutil's own result namedtuple is still preferred when resolvable so\n # type() captures stay identical to real readings on a flapping host.\n _cls = _FALLBACK_CLASSES.get(name, _DegradedReading)\n _cls_name = _PSUTIL_RESULT_CLASSES.get(name)\n if _cls_name is not None:\n for _mod in (getattr(psutil, \"_psplatform\", None), getattr(psutil, \"_common\", None)):\n _real = getattr(_mod, _cls_name, None) if _mod is not None else None\n if _real is not None and getattr(_real, \"_fields\", None):\n _cls = _real\n break\n if name == \"cpu_times\":\n def _cpu_times_fallback(*args, **kwargs):\n # cpu_times(percpu=False); the collector child samples per-CPU.\n if _percpu_requested(args, kwargs, 0):\n return []\n return _zeroed(_cls)\n\n return _cpu_times_fallback\n\n def _reading_fallback(*_args, **_kwargs):\n return _zeroed(_cls)\n\n return _reading_fallback\n\n\ndef _guard_psutil():\n try:\n import psutil\n except Exception:\n return\n\n def _wrap(orig, fallback):\n def wrapper(*args, **kwargs):\n try:\n return orig(*args, **kwargs)\n except Exception as exc: # noqa: BLE001\n _fireforge_degraded_notice(exc)\n try:\n return fallback(*args, **kwargs)\n except Exception: # noqa: BLE001\n return _DegradedReading()\n\n return wrapper\n\n for _name in (\"virtual_memory\", \"swap_memory\", \"cpu_percent\", \"cpu_times\", \"disk_io_counters\"):\n _orig = getattr(psutil, _name, None)\n if _orig is not None and not getattr(_orig, \"_fireforge_guarded\", False):\n try:\n _fallback = _degraded_result_factory(psutil, _name)\n except Exception: # noqa: BLE001\n _fallback = _DegradedReading\n _wrapped = _wrap(_orig, _fallback)\n _wrapped._fireforge_guarded = True\n setattr(psutil, _name, _wrapped)\n\n\n_MONITOR_METHOD_NAMES = (\n \"start\",\n \"stop\",\n \"record_event\",\n \"record_marker\",\n \"begin_phase\",\n \"finish_phase\",\n \"aggregate_cpu_percent\",\n \"aggregate_cpu_times\",\n \"aggregate_io\",\n \"min_memory_available\",\n \"as_dict\",\n)\n\n\ndef _fireforge_stop_collector(monitor):\n # Best-effort: terminate a live collector child and drain the parent end\n # of the pipe, so a child blocked in send() on a full pipe can never\n # keep mach's atexit join (os.waitpid) waiting forever. Attribute names\n # follow upstream resourcemonitor.py (self._process / self._pipe); a\n # miss on a refactored upstream is harmless \u2014 the shape-correct\n # fallbacks above still keep the sample stream well-formed.\n try:\n proc = getattr(monitor, \"_process\", None)\n if proc is not None and getattr(proc, \"is_alive\", lambda: False)():\n proc.terminate()\n proc.join(1)\n except Exception: # noqa: BLE001\n pass\n try:\n pipe = getattr(monitor, \"_pipe\", None)\n if pipe is not None:\n while pipe.poll(0):\n pipe.recv()\n except Exception: # noqa: BLE001\n pass\n\n\ndef _monitor_per_cpu_requested(args, kwargs):\n # aggregate_cpu_percent/aggregate_cpu_times(start=None, end=None,\n # phase=None, per_cpu=True) \u2014 self already stripped from args.\n if \"per_cpu\" in kwargs:\n return bool(kwargs[\"per_cpu\"])\n if len(args) > 3:\n return bool(args[3])\n return True\n\n\ndef _monitor_degraded_result(name, args, kwargs):\n # Degraded aggregate methods return zeroed shapes, not None, where\n # callers subscript the result: mozbuild's log_resource_usage does\n # usage[\"io\"].read_bytes after a successful compile, so None there fails\n # the build with complete artifacts already on disk.\n if name == \"aggregate_io\":\n return _zeroed(_FallbackDiskIO)\n if name == \"aggregate_cpu_percent\":\n return [] if _monitor_per_cpu_requested(args, kwargs) else 0.0\n if name == \"aggregate_cpu_times\":\n return [] if _monitor_per_cpu_requested(args, kwargs) else _zeroed(_FallbackCpuTimes)\n return None\n\n\ndef _patch_monitor_class(cls):\n if cls is None or getattr(cls, \"_fireforge_guarded\", False):\n return\n orig_init = cls.__init__\n\n def guarded_init(self, *args, **kwargs):\n # Pre-populate the attributes a partially-constructed instance is\n # later polled for, so a failing __init__ can never surface\n # AttributeError: poll_interval.\n self.poll_interval = kwargs.get(\"poll_interval\") or 1.0\n self._fireforge_degraded = False\n try:\n orig_init(self, *args, **kwargs)\n except Exception as exc: # noqa: BLE001\n self._fireforge_degraded = True\n _fireforge_degraded_notice(exc)\n if _fireforge_host_degraded[0] and not self._fireforge_degraded:\n # Host already degraded once: keep the monitor inert so the\n # collector child never spawns on a flapping host.\n self._fireforge_degraded = True\n if self._fireforge_degraded:\n _fireforge_stop_collector(self)\n\n cls.__init__ = guarded_init\n\n def _wrap_method(name, orig):\n def wrapper(self, *args, **kwargs):\n if (\n name == \"start\"\n and _fireforge_host_degraded[0]\n and not getattr(self, \"_fireforge_degraded\", False)\n ):\n self._fireforge_degraded = True\n _fireforge_stop_collector(self)\n if getattr(self, \"_fireforge_degraded\", False):\n if name == \"stop\":\n _fireforge_stop_collector(self)\n return _monitor_degraded_result(name, args, kwargs)\n try:\n return orig(self, *args, **kwargs)\n except Exception as exc: # noqa: BLE001\n self._fireforge_degraded = True\n _fireforge_degraded_notice(exc)\n # A raising stop (or any degraded transition) must still\n # take the collector child down, or the parent's atexit\n # join hangs on a child blocked writing to a full pipe.\n _fireforge_stop_collector(self)\n return _monitor_degraded_result(name, args, kwargs)\n\n return wrapper\n\n def _wrap_unbound(name, func):\n # Upstream declares record_event/record_marker as @staticmethods (and\n # may declare others as @classmethods). Those take no receiver, so\n # they cannot use the per-instance degraded flag and must not have one\n # threaded in \u2014 see the descriptor dispatch below.\n def wrapper(*args, **kwargs):\n if _fireforge_host_degraded[0]:\n return _monitor_degraded_result(name, args, kwargs)\n try:\n return func(*args, **kwargs)\n except Exception as exc: # noqa: BLE001\n _fireforge_degraded_notice(exc)\n return _monitor_degraded_result(name, args, kwargs)\n\n return wrapper\n\n for _name in _MONITOR_METHOD_NAMES:\n # getattr_static returns the raw class attribute, so a staticmethod\n # is still a staticmethod object here. Plain getattr would hand back\n # the underlying function, and re-setting THAT on the class rebinds\n # it as an instance method: the receiver is then passed through as an\n # extra leading positional and every call raises\n # \"takes N positional arguments but N+1 were given\". Re-apply the\n # descriptor the attribute actually had.\n try:\n _raw = inspect.getattr_static(cls, _name)\n except AttributeError:\n continue\n if isinstance(_raw, staticmethod):\n setattr(cls, _name, staticmethod(_wrap_unbound(_name, _raw.__func__)))\n continue\n if isinstance(_raw, classmethod):\n setattr(cls, _name, classmethod(_wrap_unbound(_name, _raw.__func__)))\n continue\n _orig = getattr(cls, _name, None)\n if _orig is not None:\n setattr(cls, _name, _wrap_method(_name, _orig))\n cls._fireforge_guarded = True\n\n\ndef _patch_build_monitor_class(cls):\n # mozbuild's BuildMonitor is not a SystemResourceMonitor; only\n # log_resource_usage needs guarding \u2014 end-of-build resource reporting\n # must never fail a build whose artifacts are complete. No __init__\n # replacement, no degraded-instance gating.\n if cls is None or getattr(cls, \"_fireforge_guarded\", False):\n return\n _orig = getattr(cls, \"log_resource_usage\", None)\n if _orig is not None:\n def _guarded_log_resource_usage(self, *args, **kwargs):\n try:\n return _orig(self, *args, **kwargs)\n except Exception as exc: # noqa: BLE001\n _fireforge_degraded_notice(exc)\n return None\n\n cls.log_resource_usage = _guarded_log_resource_usage\n cls._fireforge_guarded = True\n\n\n_MONITOR_CLASS_PATCHES = (\n (\"mozsystemmonitor.resourcemonitor\", \"SystemResourceMonitor\", _patch_monitor_class),\n (\"mozbuild.resources\", \"SystemResourceMonitor\", _patch_monitor_class),\n (\"mozbuild.controller.building\", \"BuildMonitor\", _patch_build_monitor_class),\n)\n\n\ndef _patch_loaded_monitor_modules():\n for _mod_name, _cls_name, _patcher in _MONITOR_CLASS_PATCHES:\n _mod = sys.modules.get(_mod_name)\n if _mod is not None:\n try:\n _patcher(getattr(_mod, _cls_name, None))\n except Exception: # noqa: BLE001\n pass\n\n\ndef _install_import_hook():\n _orig_import = builtins.__import__\n if getattr(_orig_import, \"_fireforge_guarded\", False):\n return\n\n def _guarding_import(name, *args, **kwargs):\n _module = _orig_import(name, *args, **kwargs)\n try:\n _patch_loaded_monitor_modules()\n except Exception: # noqa: BLE001\n pass\n return _module\n\n _guarding_import._fireforge_guarded = True\n builtins.__import__ = _guarding_import\n\n\ntry:\n _guard_psutil()\n _patch_loaded_monitor_modules()\n _install_import_hook()\nexcept Exception: # noqa: BLE001\n pass\n";
|
|
75
75
|
/** Result of installing the mach resource guard before a dispatch. */
|
|
76
76
|
export interface MachResourceGuardInstallation {
|
|
77
77
|
/**
|
|
@@ -83,12 +83,24 @@ export interface MachResourceGuardInstallation {
|
|
|
83
83
|
/** site-packages directories the in-venv guard was written into. */
|
|
84
84
|
sitePackagesDirs: string[];
|
|
85
85
|
}
|
|
86
|
+
/**
|
|
87
|
+
* Refuses a shim directory that is not a private directory of the current
|
|
88
|
+
* user. `lstat`, not `stat`: a symlink planted at the path would otherwise
|
|
89
|
+
* be followed and the check would describe its target. On Windows only the
|
|
90
|
+
* "is a real directory" half applies. There is no POSIX owner or mode bit
|
|
91
|
+
* to read, and the per-user name is the isolation.
|
|
92
|
+
*
|
|
93
|
+
* @param dir - Shim directory that {@link ensureSitecustomizeFallback} created
|
|
94
|
+
* @throws BuildError when the directory is a symlink/file, owned by another
|
|
95
|
+
* uid, or group/world-writable
|
|
96
|
+
*/
|
|
97
|
+
export declare function assertPrivateShimDir(dir: string): Promise<void>;
|
|
86
98
|
/**
|
|
87
99
|
* Installs the resource-monitor degrade guard for a mach dispatch:
|
|
88
100
|
* `fireforge_mach_guard.pth` + `fireforge_mach_guard.py` into every
|
|
89
101
|
* discovered mach virtualenv site-packages (survives mach's venv re-exec),
|
|
90
102
|
* plus the PYTHONPATH sitecustomize fallback for the pre-venv bootstrap
|
|
91
|
-
* phase. Idempotent and re-run before
|
|
103
|
+
* phase. Idempotent and re-run before every protected dispatch (including
|
|
92
104
|
* each retry) so a venv created by a crashed first attempt is guarded on
|
|
93
105
|
* the next one instead of re-dying on the same wedged state.
|
|
94
106
|
*/
|