@hominis/fireforge 0.35.0 → 0.37.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +42 -0
- package/README.md +34 -9
- package/dist/bin/fireforge.js +21 -6
- package/dist/src/cli.js +22 -5
- package/dist/src/commands/bootstrap-checks.js +0 -1
- package/dist/src/commands/bootstrap.d.ts +2 -1
- package/dist/src/commands/bootstrap.js +16 -7
- package/dist/src/commands/build.js +5 -4
- package/dist/src/commands/config.js +30 -10
- package/dist/src/commands/discard.js +18 -3
- package/dist/src/commands/doctor/post-rebase-audit.js +0 -1
- package/dist/src/commands/doctor-check-core.js +0 -1
- package/dist/src/commands/doctor-external-toolchains.d.ts +3 -0
- package/dist/src/commands/doctor-external-toolchains.js +54 -0
- package/dist/src/commands/doctor-furnace-jar.js +0 -1
- package/dist/src/commands/doctor-furnace-manifest-sync.js +0 -1
- package/dist/src/commands/doctor-furnace.js +2 -2
- package/dist/src/commands/doctor-orphaned-harness.d.ts +52 -0
- package/dist/src/commands/doctor-orphaned-harness.js +132 -0
- package/dist/src/commands/doctor-working-tree.js +0 -1
- package/dist/src/commands/doctor.js +6 -1
- package/dist/src/commands/download.js +28 -13
- package/dist/src/commands/export-all.js +5 -3
- package/dist/src/commands/export-flow.js +12 -7
- package/dist/src/commands/export-placement-gate.js +0 -1
- package/dist/src/commands/export-placement-policy.js +0 -1
- package/dist/src/commands/export-shared.d.ts +5 -1
- package/dist/src/commands/export-shared.js +18 -6
- package/dist/src/commands/export.js +22 -10
- package/dist/src/commands/furnace/apply.js +22 -6
- package/dist/src/commands/furnace/chrome-doc-remove.js +0 -1
- package/dist/src/commands/furnace/chrome-doc-templates.js +0 -1
- package/dist/src/commands/furnace/chrome-doc-tests.js +0 -1
- package/dist/src/commands/furnace/chrome-doc.js +0 -1
- package/dist/src/commands/furnace/create-browser-test.js +0 -1
- package/dist/src/commands/furnace/create-dry-run.js +0 -1
- package/dist/src/commands/furnace/create-features.js +0 -1
- package/dist/src/commands/furnace/create-mochikit.js +0 -1
- package/dist/src/commands/furnace/create-readback.js +0 -1
- package/dist/src/commands/furnace/create-templates.js +0 -1
- package/dist/src/commands/furnace/create-validation.js +0 -1
- package/dist/src/commands/furnace/create-xpcshell.js +0 -1
- package/dist/src/commands/furnace/create.js +0 -1
- package/dist/src/commands/furnace/deploy.js +7 -83
- package/dist/src/commands/furnace/diff.js +0 -1
- package/dist/src/commands/furnace/index.js +59 -25
- package/dist/src/commands/furnace/init.js +0 -1
- package/dist/src/commands/furnace/list.js +0 -1
- package/dist/src/commands/furnace/override.js +0 -1
- package/dist/src/commands/furnace/preview.js +3 -3
- package/dist/src/commands/furnace/refresh.js +0 -1
- package/dist/src/commands/furnace/remove-state.d.ts +15 -0
- package/dist/src/commands/furnace/remove-state.js +47 -1
- package/dist/src/commands/furnace/remove.js +3 -9
- package/dist/src/commands/furnace/rename-browser-test.js +1 -5
- package/dist/src/commands/furnace/rename-helpers.d.ts +6 -0
- package/dist/src/commands/furnace/rename-helpers.js +30 -1
- package/dist/src/commands/furnace/rename-xpcshell.js +7 -6
- package/dist/src/commands/furnace/rename.js +15 -36
- package/dist/src/commands/furnace/scan.js +0 -1
- package/dist/src/commands/furnace/status.js +0 -1
- package/dist/src/commands/furnace/sync.js +76 -4
- package/dist/src/commands/furnace/validate.js +0 -1
- package/dist/src/commands/furnace/validation-output.js +0 -1
- package/dist/src/commands/import.js +35 -9
- package/dist/src/commands/lint-per-patch.js +19 -7
- package/dist/src/commands/lint.js +13 -3
- package/dist/src/commands/manifest.js +1 -2
- package/dist/src/commands/package.js +2 -1
- package/dist/src/commands/patch/compact.js +1 -1
- package/dist/src/commands/patch/delete.js +1 -1
- package/dist/src/commands/patch/index.js +1 -1
- package/dist/src/commands/patch/lint-ignore.js +21 -6
- package/dist/src/commands/patch/move-files.js +1 -1
- package/dist/src/commands/patch/patch-context.js +0 -1
- package/dist/src/commands/patch/rename.js +4 -4
- package/dist/src/commands/patch/reorder.js +3 -4
- package/dist/src/commands/patch/split-plan.js +2 -1
- package/dist/src/commands/patch/split.js +4 -4
- package/dist/src/commands/patch/staged-dependency.d.ts +1 -1
- package/dist/src/commands/patch/staged-dependency.js +114 -52
- package/dist/src/commands/patch/tier.js +18 -5
- package/dist/src/commands/re-export-bulk-scan.js +0 -1
- package/dist/src/commands/re-export-files.js +5 -1
- package/dist/src/commands/re-export-options.js +0 -1
- package/dist/src/commands/re-export-scan.js +0 -1
- package/dist/src/commands/re-export.js +14 -4
- package/dist/src/commands/rebase/abort.js +2 -9
- package/dist/src/commands/rebase/confirm.js +0 -1
- package/dist/src/commands/rebase/conflict-summary.js +0 -1
- package/dist/src/commands/rebase/continue.js +0 -1
- package/dist/src/commands/rebase/index.d.ts +1 -1
- package/dist/src/commands/rebase/index.js +10 -15
- package/dist/src/commands/rebase/patch-loop.js +38 -7
- package/dist/src/commands/rebase/summary.js +2 -3
- package/dist/src/commands/rebase.js +0 -1
- package/dist/src/commands/register.js +1 -1
- package/dist/src/commands/reset.js +16 -9
- package/dist/src/commands/resolve.js +2 -2
- package/dist/src/commands/run.js +4 -4
- package/dist/src/commands/setup-support.js +0 -1
- package/dist/src/commands/setup.js +1 -2
- package/dist/src/commands/source.js +1 -2
- package/dist/src/commands/status-output.js +1 -12
- package/dist/src/commands/status.js +147 -133
- package/dist/src/commands/test-appdir.js +0 -1
- package/dist/src/commands/test-diagnose.js +38 -3
- package/dist/src/commands/test-modes.d.ts +15 -0
- package/dist/src/commands/test-modes.js +61 -0
- package/dist/src/commands/test-register.d.ts +4 -0
- package/dist/src/commands/test-register.js +64 -0
- package/dist/src/commands/test-run.d.ts +23 -7
- package/dist/src/commands/test-run.js +15 -14
- package/dist/src/commands/test.d.ts +0 -4
- package/dist/src/commands/test.js +147 -96
- package/dist/src/commands/token-coverage.js +0 -1
- package/dist/src/commands/token.js +1 -2
- package/dist/src/commands/typecheck.js +1 -1
- package/dist/src/commands/verify.js +3 -9
- package/dist/src/commands/watch.js +5 -1
- package/dist/src/commands/wire.js +1 -1
- package/dist/src/core/ast-utils.js +0 -1
- package/dist/src/core/brand-validation.js +0 -1
- package/dist/src/core/branding.js +0 -1
- package/dist/src/core/browser-wire.js +0 -1
- package/dist/src/core/build-audit-platform.js +0 -1
- package/dist/src/core/build-audit-registration.js +0 -1
- package/dist/src/core/build-audit-resolve.js +0 -1
- package/dist/src/core/build-audit-transforms.js +0 -1
- package/dist/src/core/build-audit.js +0 -1
- package/dist/src/core/build-baseline-types.d.ts +24 -0
- package/dist/src/core/build-baseline-types.js +0 -1
- package/dist/src/core/build-baseline.d.ts +5 -2
- package/dist/src/core/build-baseline.js +5 -2
- package/dist/src/core/build-prepare.js +2 -2
- package/dist/src/core/config-mutate.js +0 -1
- package/dist/src/core/config-paths.d.ts +2 -2
- package/dist/src/core/config-paths.js +6 -1
- package/dist/src/core/config-state.js +0 -1
- package/dist/src/core/config-validate-patch-policy.js +0 -1
- package/dist/src/core/config-validate-test-toolchains.d.ts +8 -0
- package/dist/src/core/config-validate-test-toolchains.js +105 -0
- package/dist/src/core/config-validate.js +3 -1
- package/dist/src/core/config.js +0 -1
- package/dist/src/core/destructive.js +0 -1
- package/dist/src/core/diff-hunks.js +13 -7
- package/dist/src/core/engine-changes.js +0 -1
- package/dist/src/core/engine-session-lock.d.ts +12 -0
- package/dist/src/core/engine-session-lock.js +45 -0
- package/dist/src/core/file-lock.d.ts +8 -0
- package/dist/src/core/file-lock.js +157 -48
- package/dist/src/core/firefox-archive.d.ts +4 -0
- package/dist/src/core/firefox-archive.js +6 -1
- package/dist/src/core/firefox-cache.js +60 -4
- package/dist/src/core/firefox-download.js +0 -1
- package/dist/src/core/firefox-extract.js +75 -16
- package/dist/src/core/firefox-ignorefile.js +0 -1
- package/dist/src/core/firefox.d.ts +12 -0
- package/dist/src/core/firefox.js +64 -2
- package/dist/src/core/furnace-apply-dry-run.js +0 -1
- package/dist/src/core/furnace-apply-ftl.d.ts +7 -3
- package/dist/src/core/furnace-apply-ftl.js +10 -5
- package/dist/src/core/furnace-apply-helpers.js +0 -1
- package/dist/src/core/furnace-apply-output.js +2 -2
- package/dist/src/core/furnace-apply.d.ts +7 -1
- package/dist/src/core/furnace-apply.js +47 -13
- package/dist/src/core/furnace-checksum-utils.js +0 -1
- package/dist/src/core/furnace-config-array-utils.js +0 -1
- package/dist/src/core/furnace-config-custom.js +10 -1
- package/dist/src/core/furnace-config-order.js +0 -1
- package/dist/src/core/furnace-config-tokens.js +0 -1
- package/dist/src/core/furnace-config-validate.js +0 -1
- package/dist/src/core/furnace-config.d.ts +11 -0
- package/dist/src/core/furnace-config.js +37 -1
- package/dist/src/core/furnace-constants.js +0 -1
- package/dist/src/core/furnace-css-fragments.js +0 -1
- package/dist/src/core/furnace-graph-utils.js +0 -1
- package/dist/src/core/furnace-jsconfig.d.ts +2 -3
- package/dist/src/core/furnace-jsconfig.js +25 -18
- package/dist/src/core/furnace-marker.js +0 -1
- package/dist/src/core/furnace-operation.js +0 -1
- package/dist/src/core/furnace-refresh.js +0 -1
- package/dist/src/core/furnace-registration-ast.d.ts +14 -0
- package/dist/src/core/furnace-registration-ast.js +1 -2
- package/dist/src/core/furnace-registration-remove.js +0 -1
- package/dist/src/core/furnace-registration-validate.js +1 -5
- package/dist/src/core/furnace-registration.js +0 -1
- package/dist/src/core/furnace-rollback.js +0 -1
- package/dist/src/core/furnace-scanner.js +0 -1
- package/dist/src/core/furnace-stale-export.d.ts +59 -0
- package/dist/src/core/furnace-stale-export.js +123 -0
- package/dist/src/core/furnace-staleness.js +0 -1
- package/dist/src/core/furnace-state-persist.d.ts +72 -0
- package/dist/src/core/furnace-state-persist.js +118 -0
- package/dist/src/core/furnace-step-errors.d.ts +23 -0
- package/dist/src/core/furnace-step-errors.js +25 -0
- package/dist/src/core/furnace-stories.js +0 -1
- package/dist/src/core/furnace-validate-accessibility.js +0 -1
- package/dist/src/core/furnace-validate-checks.js +0 -1
- package/dist/src/core/furnace-validate-compatibility.js +9 -3
- package/dist/src/core/furnace-validate-helpers.js +0 -1
- package/dist/src/core/furnace-validate-registration.js +7 -7
- package/dist/src/core/furnace-validate-structure.d.ts +8 -0
- package/dist/src/core/furnace-validate-structure.js +14 -4
- package/dist/src/core/furnace-validate.js +0 -1
- package/dist/src/core/furnace-version-drift.d.ts +6 -3
- package/dist/src/core/furnace-version-drift.js +6 -4
- package/dist/src/core/git-base.js +0 -1
- package/dist/src/core/git-diff.js +0 -1
- package/dist/src/core/git-file-ops.js +0 -1
- package/dist/src/core/git-status.d.ts +13 -0
- package/dist/src/core/git-status.js +32 -2
- package/dist/src/core/git.d.ts +10 -1
- package/dist/src/core/git.js +63 -6
- package/dist/src/core/license-headers.js +0 -1
- package/dist/src/core/lint-cache.js +0 -1
- package/dist/src/core/lint-projection.js +0 -1
- package/dist/src/core/mach-build-artifacts.js +0 -1
- package/dist/src/core/mach-error-hints.js +0 -1
- package/dist/src/core/mach-known-noise-filter.d.ts +60 -0
- package/dist/src/core/mach-known-noise-filter.js +193 -0
- package/dist/src/core/mach-mozconfig.js +0 -1
- package/dist/src/core/mach-python.js +0 -1
- package/dist/src/core/mach-resource-shim.js +0 -1
- package/dist/src/core/mach.d.ts +8 -0
- package/dist/src/core/mach.js +36 -4
- package/dist/src/core/manifest-helpers.js +0 -1
- package/dist/src/core/manifest-register.js +0 -1
- package/dist/src/core/manifest-rules.js +0 -1
- package/dist/src/core/manifest-tokenizers.js +0 -1
- package/dist/src/core/marionette-port.d.ts +8 -0
- package/dist/src/core/marionette-port.js +34 -3
- package/dist/src/core/marionette-preflight.js +0 -1
- package/dist/src/core/markdown-table.js +0 -1
- package/dist/src/core/ownership-table.js +2 -9
- package/dist/src/core/parser-fallback.js +0 -1
- package/dist/src/core/patch-apply-fuzz.d.ts +27 -9
- package/dist/src/core/patch-apply-fuzz.js +71 -34
- package/dist/src/core/patch-apply.d.ts +30 -0
- package/dist/src/core/patch-apply.js +101 -18
- package/dist/src/core/patch-artifact-normalize.d.ts +18 -5
- package/dist/src/core/patch-artifact-normalize.js +19 -15
- package/dist/src/core/patch-export-coverage.js +0 -1
- package/dist/src/core/patch-export-metadata.js +0 -1
- package/dist/src/core/patch-export-update.js +2 -3
- package/dist/src/core/patch-export.d.ts +2 -6
- package/dist/src/core/patch-export.js +24 -48
- package/dist/src/core/patch-files.js +0 -1
- package/dist/src/core/patch-identifier-suggest.js +0 -1
- package/dist/src/core/patch-lint-checkjs.js +0 -1
- package/dist/src/core/patch-lint-chrome-jsdoc.js +0 -1
- package/dist/src/core/patch-lint-cross.js +80 -3
- package/dist/src/core/patch-lint-css.js +0 -1
- package/dist/src/core/patch-lint-diff-tag.js +0 -1
- package/dist/src/core/patch-lint-diff.d.ts +2 -1
- package/dist/src/core/patch-lint-diff.js +17 -32
- package/dist/src/core/patch-lint-imports.js +0 -1
- package/dist/src/core/patch-lint-jsdoc.js +0 -1
- package/dist/src/core/patch-lint-observer.js +0 -1
- package/dist/src/core/patch-lint-ownership.js +0 -1
- package/dist/src/core/patch-lint-reexports.js +0 -1
- package/dist/src/core/patch-lint.d.ts +37 -2
- package/dist/src/core/patch-lint.js +47 -34
- package/dist/src/core/patch-lock.js +0 -1
- package/dist/src/core/patch-manifest-consistency.js +9 -1
- package/dist/src/core/patch-manifest-io.d.ts +19 -2
- package/dist/src/core/patch-manifest-io.js +57 -21
- package/dist/src/core/patch-manifest-query.js +18 -10
- package/dist/src/core/patch-manifest-resolve.js +0 -1
- package/dist/src/core/patch-manifest-validate.js +24 -1
- package/dist/src/core/patch-manifest.d.ts +1 -1
- package/dist/src/core/patch-manifest.js +1 -2
- package/dist/src/core/patch-parse.d.ts +59 -0
- package/dist/src/core/patch-parse.js +209 -92
- package/dist/src/core/patch-policy.js +0 -1
- package/dist/src/core/patch-registration-refs.js +16 -26
- package/dist/src/core/patch-source-metadata.js +0 -1
- package/dist/src/core/patch-transform.d.ts +4 -0
- package/dist/src/core/patch-transform.js +30 -38
- package/dist/src/core/rebase-session.js +0 -1
- package/dist/src/core/register-browser-content.js +0 -1
- package/dist/src/core/register-module.js +0 -1
- package/dist/src/core/register-result.js +0 -1
- package/dist/src/core/register-scaffold.js +0 -1
- package/dist/src/core/register-shared-css.js +0 -1
- package/dist/src/core/register-test-manifest.js +0 -1
- package/dist/src/core/register-xpcshell-test.js +0 -1
- package/dist/src/core/shared-ftl.js +0 -1
- package/dist/src/core/signal-critical.js +0 -1
- package/dist/src/core/smoke-patterns.js +0 -1
- package/dist/src/core/state-file.js +0 -1
- package/dist/src/core/status-classify.d.ts +16 -0
- package/dist/src/core/status-classify.js +24 -16
- package/dist/src/core/test-harness-crash.d.ts +80 -7
- package/dist/src/core/test-harness-crash.js +251 -15
- package/dist/src/core/test-harness-output.js +0 -1
- package/dist/src/core/test-path-scope.d.ts +21 -13
- package/dist/src/core/test-path-scope.js +43 -28
- package/dist/src/core/test-stale-check.d.ts +29 -1
- package/dist/src/core/test-stale-check.js +59 -1
- package/dist/src/core/test-stale-symlink.js +0 -1
- package/dist/src/core/test-xpcshell-retry.js +0 -1
- package/dist/src/core/token-coverage.js +0 -1
- package/dist/src/core/token-dark-mode.js +0 -1
- package/dist/src/core/token-docs.js +0 -1
- package/dist/src/core/token-manager.js +0 -1
- package/dist/src/core/token-scaffold.js +0 -1
- package/dist/src/core/token-variant.js +0 -1
- package/dist/src/core/toolchain-preflight.d.ts +31 -10
- package/dist/src/core/toolchain-preflight.js +97 -36
- package/dist/src/core/typecheck-shim.js +13 -1
- package/dist/src/core/typecheck.js +0 -1
- package/dist/src/core/wire-destroy.js +0 -1
- package/dist/src/core/wire-dom-fragment.js +0 -1
- package/dist/src/core/wire-init.js +0 -1
- package/dist/src/core/wire-subscript.js +0 -1
- package/dist/src/core/wire-targets.js +0 -1
- package/dist/src/core/wire-utils.js +0 -1
- package/dist/src/core/xpcshell-appdir.js +1 -4
- package/dist/src/errors/base.d.ts +29 -0
- package/dist/src/errors/base.js +35 -1
- package/dist/src/errors/build.js +0 -1
- package/dist/src/errors/codes.d.ts +6 -0
- package/dist/src/errors/codes.js +6 -1
- package/dist/src/errors/config.js +0 -1
- package/dist/src/errors/download.js +0 -1
- package/dist/src/errors/furnace.d.ts +11 -1
- package/dist/src/errors/furnace.js +6 -5
- package/dist/src/errors/git.js +0 -1
- package/dist/src/errors/patch.d.ts +17 -0
- package/dist/src/errors/patch.js +29 -1
- package/dist/src/errors/rebase.js +0 -1
- package/dist/src/errors/run.js +1 -1
- package/dist/src/index.js +0 -1
- package/dist/src/types/cli.js +0 -1
- package/dist/src/types/commands/index.d.ts +1 -1
- package/dist/src/types/commands/index.js +0 -1
- package/dist/src/types/commands/options.d.ts +40 -9
- package/dist/src/types/commands/options.js +0 -1
- package/dist/src/types/commands/patches.d.ts +37 -0
- package/dist/src/types/commands/patches.js +0 -1
- package/dist/src/types/commands/project.d.ts +11 -2
- package/dist/src/types/commands/project.js +0 -1
- package/dist/src/types/config.d.ts +32 -0
- package/dist/src/types/config.js +0 -1
- package/dist/src/types/furnace.d.ts +23 -0
- package/dist/src/types/furnace.js +0 -1
- package/dist/src/types/index.js +0 -1
- package/dist/src/types/typecheck.js +0 -1
- package/dist/src/utils/elapsed.js +0 -1
- package/dist/src/utils/errors.js +0 -1
- package/dist/src/utils/fs.js +37 -5
- package/dist/src/utils/logger.d.ts +7 -0
- package/dist/src/utils/logger.js +85 -3
- package/dist/src/utils/options.d.ts +15 -0
- package/dist/src/utils/options.js +25 -1
- package/dist/src/utils/package-root.js +11 -4
- package/dist/src/utils/parse.js +0 -1
- package/dist/src/utils/paths.js +0 -1
- package/dist/src/utils/platform.js +0 -1
- package/dist/src/utils/process-group.d.ts +33 -0
- package/dist/src/utils/process-group.js +161 -0
- package/dist/src/utils/process.d.ts +48 -4
- package/dist/src/utils/process.js +258 -59
- package/dist/src/utils/regex.d.ts +13 -3
- package/dist/src/utils/regex.js +53 -4
- package/dist/src/utils/validation.d.ts +0 -12
- package/dist/src/utils/validation.js +13 -26
- package/package.json +9 -8
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
// SPDX-License-Identifier: EUPL-1.2
|
|
2
|
+
import { warn } from '../utils/logger.js';
|
|
1
3
|
import { ensureGit, git } from './git-base.js';
|
|
2
4
|
/**
|
|
3
5
|
* Parses NUL-delimited porcelain status output.
|
|
@@ -43,22 +45,51 @@ export async function getWorkingTreeStatus(repoDir) {
|
|
|
43
45
|
await ensureGit();
|
|
44
46
|
return parsePorcelainStatus(await git(['status', '--porcelain=v1', '-z'], repoDir));
|
|
45
47
|
}
|
|
48
|
+
/** Default per-directory cap for untracked-directory expansion. */
|
|
49
|
+
const DEFAULT_MAX_UNTRACKED_FILES_PER_DIR = 5000;
|
|
50
|
+
/**
|
|
51
|
+
* Resolves the per-directory expansion cap, honoring the same
|
|
52
|
+
* FIREFORGE_MAX_UNTRACKED_FILES override the status command documents.
|
|
53
|
+
*/
|
|
54
|
+
export function resolveMaxUntrackedFilesPerDir() {
|
|
55
|
+
const raw = process.env['FIREFORGE_MAX_UNTRACKED_FILES'];
|
|
56
|
+
if (raw === undefined || raw.length === 0)
|
|
57
|
+
return DEFAULT_MAX_UNTRACKED_FILES_PER_DIR;
|
|
58
|
+
const parsed = Number.parseInt(raw, 10);
|
|
59
|
+
if (!Number.isFinite(parsed) || parsed <= 0) {
|
|
60
|
+
warn(`Ignoring FIREFORGE_MAX_UNTRACKED_FILES="${raw}" — expected a positive integer. Falling back to ${String(DEFAULT_MAX_UNTRACKED_FILES_PER_DIR)}.`);
|
|
61
|
+
return DEFAULT_MAX_UNTRACKED_FILES_PER_DIR;
|
|
62
|
+
}
|
|
63
|
+
return parsed;
|
|
64
|
+
}
|
|
46
65
|
/**
|
|
47
66
|
* Expands collapsed untracked directory entries into individual file entries.
|
|
48
67
|
* Git status may report "?? dir/" instead of listing each file underneath.
|
|
68
|
+
*
|
|
69
|
+
* Expansion is capped per directory (FIREFORGE_MAX_UNTRACKED_FILES, default
|
|
70
|
+
* 5000) with a warning on overflow. The cap used to exist only in the
|
|
71
|
+
* status command's private expander; this shared one — used by reset,
|
|
72
|
+
* discard, verify, lint, export-all — was unbounded, so e.g. `reset
|
|
73
|
+
* --dry-run` after an interrupted download (unborn HEAD, the entire ~300k
|
|
74
|
+
* file tree untracked) enumerated and printed every file.
|
|
75
|
+
*
|
|
49
76
|
* @param repoDir - Repository directory
|
|
50
77
|
* @param entries - Parsed status entries
|
|
51
78
|
* @returns Status entries with untracked directories expanded to individual files
|
|
52
79
|
*/
|
|
53
80
|
export async function expandUntrackedDirectoryEntries(repoDir, entries) {
|
|
54
81
|
const expanded = [];
|
|
82
|
+
const maxPerDir = resolveMaxUntrackedFilesPerDir();
|
|
55
83
|
for (const entry of entries) {
|
|
56
84
|
if (!entry.isUntracked || !entry.file.endsWith('/')) {
|
|
57
85
|
expanded.push(entry);
|
|
58
86
|
continue;
|
|
59
87
|
}
|
|
60
88
|
const individualFiles = await getUntrackedFilesInDir(repoDir, entry.file);
|
|
61
|
-
|
|
89
|
+
if (individualFiles.length > maxPerDir) {
|
|
90
|
+
warn(`Untracked directory ${entry.file} contains ${String(individualFiles.length)} files — only the first ${String(maxPerDir)} are listed. Add a .gitignore entry or clean the directory.`);
|
|
91
|
+
}
|
|
92
|
+
for (const file of individualFiles.slice(0, maxPerDir)) {
|
|
62
93
|
expanded.push({
|
|
63
94
|
status: '??',
|
|
64
95
|
indexStatus: '?',
|
|
@@ -125,4 +156,3 @@ export async function getDirtyFiles(repoDir, files) {
|
|
|
125
156
|
const untracked = untrackedOutput.split('\n').filter((line) => line.trim().length > 0);
|
|
126
157
|
return [...new Set([...tracked, ...untracked])].sort();
|
|
127
158
|
}
|
|
128
|
-
//# sourceMappingURL=git-status.js.map
|
package/dist/src/core/git.d.ts
CHANGED
|
@@ -53,12 +53,21 @@ export declare function applyPatch(patchPath: string, repoDir: string, options?:
|
|
|
53
53
|
* Applies a patch idempotently using reverse-forward pattern.
|
|
54
54
|
* First tries to reverse the patch (in case it's already applied),
|
|
55
55
|
* then applies it forward.
|
|
56
|
+
*
|
|
56
57
|
* @param patchPath - Path to the patch file
|
|
57
58
|
* @param repoDir - Repository directory
|
|
58
|
-
* @param options -
|
|
59
|
+
* @param options.reject - Fall back to `git apply --reject`
|
|
60
|
+
* @param options.protectedFiles - Files that must NOT be reset to HEAD by
|
|
61
|
+
* the recovery step. Callers applying a patch QUEUE pass the files
|
|
62
|
+
* already touched by previously applied patches in the same run: two
|
|
63
|
+
* overlapping patches (an `--allow-overlap` queue) share files, and the
|
|
64
|
+
* blanket `checkout HEAD` used to wipe the earlier patch's changes from
|
|
65
|
+
* the shared file before applying the later one — leaving the engine in
|
|
66
|
+
* a hybrid state the summary never described.
|
|
59
67
|
*/
|
|
60
68
|
export declare function applyPatchIdempotent(patchPath: string, repoDir: string, options?: {
|
|
61
69
|
reject?: boolean;
|
|
70
|
+
protectedFiles?: ReadonlySet<string>;
|
|
62
71
|
}): Promise<void>;
|
|
63
72
|
/**
|
|
64
73
|
* Reverses a previously applied patch.
|
package/dist/src/core/git.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
// SPDX-License-Identifier: EUPL-1.2
|
|
2
2
|
import { readdir, stat } from 'node:fs/promises';
|
|
3
3
|
import { join } from 'node:path';
|
|
4
|
+
import { ExecTimeoutError } from '../errors/base.js';
|
|
4
5
|
import { GitError, GitIndexingTimeoutError, GitIndexLockError, PatchApplyError, } from '../errors/git.js';
|
|
5
6
|
import { elapsedSince } from '../utils/elapsed.js';
|
|
6
7
|
import { toError } from '../utils/errors.js';
|
|
@@ -8,7 +9,7 @@ import { pathExists, pathExistsStrict, removeFile } from '../utils/fs.js';
|
|
|
8
9
|
import { verbose } from '../utils/logger.js';
|
|
9
10
|
import { exec } from '../utils/process.js';
|
|
10
11
|
import { ensureFirefoxIgnorefileCompatibility } from './firefox-ignorefile.js';
|
|
11
|
-
import { configureGitPerformance, ensureGit, git, GIT_ADD_CHUNK_TIMEOUT_ENV_VAR, GIT_ADD_CHUNK_TIMEOUT_MS, GIT_ADD_TIMEOUT_MS, } from './git-base.js';
|
|
12
|
+
import { chunkPathspecs, configureGitPerformance, ensureGit, git, GIT_ADD_CHUNK_TIMEOUT_ENV_VAR, GIT_ADD_CHUNK_TIMEOUT_MS, GIT_ADD_TIMEOUT_MS, } from './git-base.js';
|
|
12
13
|
import { getWorkingTreeStatus } from './git-status.js';
|
|
13
14
|
// ── Functions that remain in this file ──
|
|
14
15
|
/**
|
|
@@ -47,6 +48,11 @@ const GIT_ADD_ENV = { GIT_INDEX_THREADS: '0' };
|
|
|
47
48
|
* detection here needs to recognise that shape too.
|
|
48
49
|
*/
|
|
49
50
|
function isTimeoutError(error) {
|
|
51
|
+
// `exec` now rejects with a typed ExecTimeoutError when its `timeout`
|
|
52
|
+
// option fires (the raw AbortError check below is kept for defence in
|
|
53
|
+
// depth against other abort paths).
|
|
54
|
+
if (error instanceof ExecTimeoutError)
|
|
55
|
+
return true;
|
|
50
56
|
if (error instanceof Error && error.name === 'AbortError')
|
|
51
57
|
return true;
|
|
52
58
|
if (!(error instanceof GitError))
|
|
@@ -410,9 +416,17 @@ export async function applyPatch(patchPath, repoDir, options = {}) {
|
|
|
410
416
|
* Applies a patch idempotently using reverse-forward pattern.
|
|
411
417
|
* First tries to reverse the patch (in case it's already applied),
|
|
412
418
|
* then applies it forward.
|
|
419
|
+
*
|
|
413
420
|
* @param patchPath - Path to the patch file
|
|
414
421
|
* @param repoDir - Repository directory
|
|
415
|
-
* @param options -
|
|
422
|
+
* @param options.reject - Fall back to `git apply --reject`
|
|
423
|
+
* @param options.protectedFiles - Files that must NOT be reset to HEAD by
|
|
424
|
+
* the recovery step. Callers applying a patch QUEUE pass the files
|
|
425
|
+
* already touched by previously applied patches in the same run: two
|
|
426
|
+
* overlapping patches (an `--allow-overlap` queue) share files, and the
|
|
427
|
+
* blanket `checkout HEAD` used to wipe the earlier patch's changes from
|
|
428
|
+
* the shared file before applying the later one — leaving the engine in
|
|
429
|
+
* a hybrid state the summary never described.
|
|
416
430
|
*/
|
|
417
431
|
export async function applyPatchIdempotent(patchPath, repoDir, options = {}) {
|
|
418
432
|
await ensureGit();
|
|
@@ -428,15 +442,59 @@ export async function applyPatchIdempotent(patchPath, repoDir, options = {}) {
|
|
|
428
442
|
const touchedFiles = listResult.stdout
|
|
429
443
|
.split('\n')
|
|
430
444
|
.map((line) => line.split('\t')[2])
|
|
431
|
-
.filter((f) => !!f)
|
|
445
|
+
.filter((f) => !!f)
|
|
446
|
+
.filter((f) => !(options.protectedFiles?.has(f) ?? false));
|
|
432
447
|
if (touchedFiles.length > 0) {
|
|
433
|
-
|
|
434
|
-
await exec('git', ['checkout', 'HEAD', '--', ...touchedFiles], { cwd: repoDir });
|
|
448
|
+
await restoreFilesToHead(repoDir, patchPath, touchedFiles);
|
|
435
449
|
}
|
|
436
450
|
}
|
|
437
451
|
// Apply forward
|
|
438
452
|
await applyPatch(patchPath, repoDir, options);
|
|
439
453
|
}
|
|
454
|
+
/**
|
|
455
|
+
* Restores `files` to their HEAD state, deleting files the patch would
|
|
456
|
+
* CREATE (present on disk from a partial apply but absent in HEAD — for
|
|
457
|
+
* those, `git checkout HEAD --` fails, and the historical code ignored
|
|
458
|
+
* that failure entirely, leaving stray files that made the subsequent
|
|
459
|
+
* forward apply die with "already exists" and no hint why).
|
|
460
|
+
*
|
|
461
|
+
* Every git invocation is chunked via {@link chunkPathspecs} so a very
|
|
462
|
+
* large patch cannot hit `E2BIG`, and every exit code is checked — a
|
|
463
|
+
* silent failed restore is precisely the confusing state this recovery
|
|
464
|
+
* step exists to prevent.
|
|
465
|
+
*/
|
|
466
|
+
async function restoreFilesToHead(repoDir, patchPath, files) {
|
|
467
|
+
// Partition into tracked-in-HEAD (restore via checkout) and absent-in-HEAD
|
|
468
|
+
// (patch-created leftovers: delete from the worktree).
|
|
469
|
+
const trackedInHead = new Set();
|
|
470
|
+
for (const chunk of chunkPathspecs(files)) {
|
|
471
|
+
const lsTree = await exec('git', ['ls-tree', '-r', '--name-only', 'HEAD', '--', ...chunk], {
|
|
472
|
+
cwd: repoDir,
|
|
473
|
+
});
|
|
474
|
+
if (lsTree.exitCode !== 0) {
|
|
475
|
+
throw new PatchApplyError(patchPath, new Error(`git ls-tree failed while preparing recovery: ${lsTree.stderr.trim()}`));
|
|
476
|
+
}
|
|
477
|
+
for (const line of lsTree.stdout.split('\n')) {
|
|
478
|
+
if (line.length > 0)
|
|
479
|
+
trackedInHead.add(line);
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
const toCheckout = files.filter((f) => trackedInHead.has(f));
|
|
483
|
+
const toDelete = files.filter((f) => !trackedInHead.has(f));
|
|
484
|
+
for (const chunk of chunkPathspecs(toCheckout)) {
|
|
485
|
+
const checkout = await exec('git', ['checkout', 'HEAD', '--', ...chunk], { cwd: repoDir });
|
|
486
|
+
if (checkout.exitCode !== 0) {
|
|
487
|
+
throw new PatchApplyError(patchPath, new Error(`Could not restore patch-touched files to HEAD before applying: ${checkout.stderr.trim()}`));
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
for (const file of toDelete) {
|
|
491
|
+
const target = join(repoDir, file);
|
|
492
|
+
if (await pathExists(target)) {
|
|
493
|
+
await removeFile(target);
|
|
494
|
+
verbose(`Removed stray patch-created file before apply: ${file}`);
|
|
495
|
+
}
|
|
496
|
+
}
|
|
497
|
+
}
|
|
440
498
|
/**
|
|
441
499
|
* Reverses a previously applied patch.
|
|
442
500
|
* @param patchPath - Path to the patch file
|
|
@@ -524,4 +582,3 @@ export async function getStatusWithCodes(repoDir) {
|
|
|
524
582
|
file: entry.file,
|
|
525
583
|
}));
|
|
526
584
|
}
|
|
527
|
-
//# sourceMappingURL=git.js.map
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Terminal-echo filter for the KNOWN upstream mozsystemmonitor teardown
|
|
3
|
+
* traceback (0.37.0 item 8).
|
|
4
|
+
*
|
|
5
|
+
* Every headless test run against the 153-beta engine ends with an
|
|
6
|
+
* `AttributeError: 'SystemResourceMonitor' object has no attribute
|
|
7
|
+
* 'stop_time'` traceback at harness teardown — upstream noise that sits
|
|
8
|
+
* exactly where a reader looks for the failure summary. 0.36.0 already made
|
|
9
|
+
* real failure lines beat this traceback in CLASSIFICATION; this filter
|
|
10
|
+
* closes the PRESENTATION gap by collapsing the echoed traceback to one
|
|
11
|
+
* labeled line.
|
|
12
|
+
*
|
|
13
|
+
* Scope is deliberately narrow:
|
|
14
|
+
* - Only the terminal ECHO is filtered. The captured stdout/stderr strings
|
|
15
|
+
* stay raw — the classifier (`test-harness-crash.ts`) depends on the
|
|
16
|
+
* raw traceback for its green-summary override and secondary-noise
|
|
17
|
+
* detection.
|
|
18
|
+
* - Only the exact documented incident is collapsed, and every condition
|
|
19
|
+
* must hold: an `AttributeError` on `SystemResourceMonitor` naming one
|
|
20
|
+
* of the two known attributes (`stop_time`, `poll_interval` — the
|
|
21
|
+
* 0.34.0 guard family), AND a `mozsystemmonitor/resourcemonitor.py`
|
|
22
|
+
* stack frame, AND a previously-seen SUITE_END shutdown marker (shared
|
|
23
|
+
* across the run's stdout/stderr filter instances — the marker usually
|
|
24
|
+
* lands on stdout while the traceback lands on stderr). A novel
|
|
25
|
+
* attribute, a novel exception type in resourcemonitor.py, or a
|
|
26
|
+
* pre-shutdown occurrence is echoed verbatim, always.
|
|
27
|
+
* - The hold buffer is bounded; on overflow the block is flushed verbatim
|
|
28
|
+
* and the filter returns to pass-through, so output is never lost.
|
|
29
|
+
*/
|
|
30
|
+
/**
|
|
31
|
+
* Shared across the stdout and stderr filter instances of ONE mach run:
|
|
32
|
+
* SUITE_END typically arrives on stdout while the teardown traceback lands
|
|
33
|
+
* on stderr, so the shutdown-seen flag must be visible to both. The two
|
|
34
|
+
* pipes are independent, so a traceback can theoretically beat the marker
|
|
35
|
+
* through — the block then prints verbatim, the correct failure direction.
|
|
36
|
+
*/
|
|
37
|
+
export interface TeardownNoiseContext {
|
|
38
|
+
shutdownSeen: boolean;
|
|
39
|
+
}
|
|
40
|
+
/** Fresh per-run context — hand the same instance to both stream filters. */
|
|
41
|
+
export declare function createTeardownNoiseContext(): TeardownNoiseContext;
|
|
42
|
+
/** One line replaces the whole recognized traceback block in the echo. */
|
|
43
|
+
export declare const KNOWN_TEARDOWN_NOISE_ANNOTATION: string;
|
|
44
|
+
/** Chunk-safe, line-buffered echo filter. See module doc. */
|
|
45
|
+
export interface KnownTeardownNoiseFilter {
|
|
46
|
+
/** Feed a raw chunk; returns the text to echo now (possibly empty). */
|
|
47
|
+
transform(chunk: string): string;
|
|
48
|
+
/** Flush any buffered residue verbatim (call after the stream closes). */
|
|
49
|
+
flush(): string;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Creates a stateful filter for one output stream. Complete lines outside a
|
|
53
|
+
* traceback pass straight through (only the trailing partial line is held
|
|
54
|
+
* back); a `Traceback (most recent call last)` header switches to hold mode
|
|
55
|
+
* until the block ends, then either the one-line annotation (recognized
|
|
56
|
+
* signature after a seen shutdown marker) or the verbatim block (anything
|
|
57
|
+
* else) is emitted. Pass the run's shared {@link TeardownNoiseContext} so
|
|
58
|
+
* both stream filters see the same shutdown flag.
|
|
59
|
+
*/
|
|
60
|
+
export declare function createKnownTeardownNoiseFilter(context?: TeardownNoiseContext): KnownTeardownNoiseFilter;
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
// SPDX-License-Identifier: EUPL-1.2
|
|
2
|
+
/**
|
|
3
|
+
* Terminal-echo filter for the KNOWN upstream mozsystemmonitor teardown
|
|
4
|
+
* traceback (0.37.0 item 8).
|
|
5
|
+
*
|
|
6
|
+
* Every headless test run against the 153-beta engine ends with an
|
|
7
|
+
* `AttributeError: 'SystemResourceMonitor' object has no attribute
|
|
8
|
+
* 'stop_time'` traceback at harness teardown — upstream noise that sits
|
|
9
|
+
* exactly where a reader looks for the failure summary. 0.36.0 already made
|
|
10
|
+
* real failure lines beat this traceback in CLASSIFICATION; this filter
|
|
11
|
+
* closes the PRESENTATION gap by collapsing the echoed traceback to one
|
|
12
|
+
* labeled line.
|
|
13
|
+
*
|
|
14
|
+
* Scope is deliberately narrow:
|
|
15
|
+
* - Only the terminal ECHO is filtered. The captured stdout/stderr strings
|
|
16
|
+
* stay raw — the classifier (`test-harness-crash.ts`) depends on the
|
|
17
|
+
* raw traceback for its green-summary override and secondary-noise
|
|
18
|
+
* detection.
|
|
19
|
+
* - Only the exact documented incident is collapsed, and every condition
|
|
20
|
+
* must hold: an `AttributeError` on `SystemResourceMonitor` naming one
|
|
21
|
+
* of the two known attributes (`stop_time`, `poll_interval` — the
|
|
22
|
+
* 0.34.0 guard family), AND a `mozsystemmonitor/resourcemonitor.py`
|
|
23
|
+
* stack frame, AND a previously-seen SUITE_END shutdown marker (shared
|
|
24
|
+
* across the run's stdout/stderr filter instances — the marker usually
|
|
25
|
+
* lands on stdout while the traceback lands on stderr). A novel
|
|
26
|
+
* attribute, a novel exception type in resourcemonitor.py, or a
|
|
27
|
+
* pre-shutdown occurrence is echoed verbatim, always.
|
|
28
|
+
* - The hold buffer is bounded; on overflow the block is flushed verbatim
|
|
29
|
+
* and the filter returns to pass-through, so output is never lost.
|
|
30
|
+
*/
|
|
31
|
+
const TRACEBACK_HEADER_PATTERN = /^Traceback \(most recent call last\)/;
|
|
32
|
+
const CHAINED_EXCEPTION_CONNECTOR_PATTERN = /^(?:During handling of the above exception, another exception occurred:|The above exception was the direct cause of the following exception:)\s*$/;
|
|
33
|
+
/**
|
|
34
|
+
* Closed allowlist of the documented teardown family's attributes:
|
|
35
|
+
* `stop_time` (the 0.37.0 item-8 incident) and `poll_interval` (the same
|
|
36
|
+
* mozsystemmonitor init failure the 0.34.0 resource-guard family covers —
|
|
37
|
+
* `test-harness-crash.ts` already classifies it as recognized noise). Any
|
|
38
|
+
* other missing attribute is a NEW upstream defect and must print verbatim.
|
|
39
|
+
*/
|
|
40
|
+
const KNOWN_TEARDOWN_ATTRIBUTE_ERROR_PATTERN = /AttributeError: 'SystemResourceMonitor' object has no attribute '(?:stop_time|poll_interval)'/;
|
|
41
|
+
const RESOURCEMONITOR_FRAME_PATTERN = /mozsystemmonitor[/\\]resourcemonitor\.py/;
|
|
42
|
+
/**
|
|
43
|
+
* Shutdown marker: the harness's SUITE_END line. Matches the shape
|
|
44
|
+
* `test-harness-crash.ts` keys its summary parsing on (module-private
|
|
45
|
+
* there; duplicated here with this cross-reference rather than exported).
|
|
46
|
+
*/
|
|
47
|
+
const SHUTDOWN_MARKER_PATTERN = /\bSUITE_END\b/;
|
|
48
|
+
/** Whole-block recognition — every signal must hold (see module doc). */
|
|
49
|
+
function isRecognizedTeardownNoise(block) {
|
|
50
|
+
return (KNOWN_TEARDOWN_ATTRIBUTE_ERROR_PATTERN.test(block) && RESOURCEMONITOR_FRAME_PATTERN.test(block));
|
|
51
|
+
}
|
|
52
|
+
/** Fresh per-run context — hand the same instance to both stream filters. */
|
|
53
|
+
export function createTeardownNoiseContext() {
|
|
54
|
+
return { shutdownSeen: false };
|
|
55
|
+
}
|
|
56
|
+
/** One line replaces the whole recognized traceback block in the echo. */
|
|
57
|
+
export const KNOWN_TEARDOWN_NOISE_ANNOTATION = '[FireForge] Known upstream mozsystemmonitor teardown noise (SystemResourceMonitor ' +
|
|
58
|
+
'AttributeError at harness shutdown) — not a test failure. See FireForge docs.\n';
|
|
59
|
+
/** Bounds on the held traceback block before flushing verbatim. */
|
|
60
|
+
const HOLD_LINE_LIMIT = 100;
|
|
61
|
+
const HOLD_BYTE_LIMIT = 16 * 1024;
|
|
62
|
+
/**
|
|
63
|
+
* Creates a stateful filter for one output stream. Complete lines outside a
|
|
64
|
+
* traceback pass straight through (only the trailing partial line is held
|
|
65
|
+
* back); a `Traceback (most recent call last)` header switches to hold mode
|
|
66
|
+
* until the block ends, then either the one-line annotation (recognized
|
|
67
|
+
* signature after a seen shutdown marker) or the verbatim block (anything
|
|
68
|
+
* else) is emitted. Pass the run's shared {@link TeardownNoiseContext} so
|
|
69
|
+
* both stream filters see the same shutdown flag.
|
|
70
|
+
*/
|
|
71
|
+
export function createKnownTeardownNoiseFilter(context = createTeardownNoiseContext()) {
|
|
72
|
+
/** Partial (no trailing newline yet) input line. */
|
|
73
|
+
let partial = '';
|
|
74
|
+
/** Held traceback lines (each WITH its newline) while in hold mode. */
|
|
75
|
+
let held = [];
|
|
76
|
+
let heldBytes = 0;
|
|
77
|
+
/**
|
|
78
|
+
* State machine:
|
|
79
|
+
* 'pass' — outside any traceback; lines echo through.
|
|
80
|
+
* 'inside' — between a Traceback header and its closing exception line.
|
|
81
|
+
* 'closed' — saw the closing `SomeError: …` line; still holding in
|
|
82
|
+
* case a chained-exception connector continues the block
|
|
83
|
+
* (the real fixture chains two tracebacks — the whole
|
|
84
|
+
* chain must be evaluated as ONE block or the second half
|
|
85
|
+
* would print raw after the annotation).
|
|
86
|
+
*/
|
|
87
|
+
let state = 'pass';
|
|
88
|
+
const resetHold = () => {
|
|
89
|
+
const block = held.join('');
|
|
90
|
+
held = [];
|
|
91
|
+
heldBytes = 0;
|
|
92
|
+
state = 'pass';
|
|
93
|
+
return block;
|
|
94
|
+
};
|
|
95
|
+
const releaseHeld = () => {
|
|
96
|
+
const block = resetHold();
|
|
97
|
+
if (block.length === 0)
|
|
98
|
+
return '';
|
|
99
|
+
return context.shutdownSeen && isRecognizedTeardownNoise(block)
|
|
100
|
+
? KNOWN_TEARDOWN_NOISE_ANNOTATION
|
|
101
|
+
: block;
|
|
102
|
+
};
|
|
103
|
+
const hold = (line) => {
|
|
104
|
+
held.push(line);
|
|
105
|
+
heldBytes += line.length;
|
|
106
|
+
if (held.length > HOLD_LINE_LIMIT || heldBytes > HOLD_BYTE_LIMIT) {
|
|
107
|
+
// Pathological block: flush verbatim rather than risk withholding
|
|
108
|
+
// output; do not attempt recognition on oversized blocks.
|
|
109
|
+
return { out: resetHold(), overflowed: true };
|
|
110
|
+
}
|
|
111
|
+
return { out: '', overflowed: false };
|
|
112
|
+
};
|
|
113
|
+
const processLine = (line) => {
|
|
114
|
+
const content = line.replace(/\r?\n$/, '');
|
|
115
|
+
if (state === 'pass') {
|
|
116
|
+
if (TRACEBACK_HEADER_PATTERN.test(content)) {
|
|
117
|
+
state = 'inside';
|
|
118
|
+
return hold(line).out;
|
|
119
|
+
}
|
|
120
|
+
if (SHUTDOWN_MARKER_PATTERN.test(content))
|
|
121
|
+
context.shutdownSeen = true;
|
|
122
|
+
return line;
|
|
123
|
+
}
|
|
124
|
+
if (state === 'inside') {
|
|
125
|
+
const isContinuation = content.trim().length === 0 ||
|
|
126
|
+
/^[ \t]/.test(content) ||
|
|
127
|
+
TRACEBACK_HEADER_PATTERN.test(content);
|
|
128
|
+
const { out, overflowed } = hold(line);
|
|
129
|
+
// The first unindented line is the closing `SomeError: …` line; keep
|
|
130
|
+
// holding in case a chained connector extends the block.
|
|
131
|
+
if (!overflowed && !isContinuation) {
|
|
132
|
+
state = 'closed';
|
|
133
|
+
}
|
|
134
|
+
return out;
|
|
135
|
+
}
|
|
136
|
+
// state === 'closed': only a blank line, a chained-exception connector,
|
|
137
|
+
// or another Traceback header continues the block.
|
|
138
|
+
if (content.trim().length === 0 || CHAINED_EXCEPTION_CONNECTOR_PATTERN.test(content)) {
|
|
139
|
+
return hold(line).out;
|
|
140
|
+
}
|
|
141
|
+
if (TRACEBACK_HEADER_PATTERN.test(content)) {
|
|
142
|
+
const { out, overflowed } = hold(line);
|
|
143
|
+
if (!overflowed)
|
|
144
|
+
state = 'inside';
|
|
145
|
+
return out;
|
|
146
|
+
}
|
|
147
|
+
return releaseHeld() + processLineInPass(line);
|
|
148
|
+
};
|
|
149
|
+
// Re-dispatch a line through pass-mode handling after a block release —
|
|
150
|
+
// the line that ended the block may itself start a new traceback.
|
|
151
|
+
const processLineInPass = (line) => {
|
|
152
|
+
const content = line.replace(/\r?\n$/, '');
|
|
153
|
+
if (TRACEBACK_HEADER_PATTERN.test(content)) {
|
|
154
|
+
state = 'inside';
|
|
155
|
+
return hold(line).out;
|
|
156
|
+
}
|
|
157
|
+
if (SHUTDOWN_MARKER_PATTERN.test(content))
|
|
158
|
+
context.shutdownSeen = true;
|
|
159
|
+
return line;
|
|
160
|
+
};
|
|
161
|
+
return {
|
|
162
|
+
transform(chunk) {
|
|
163
|
+
let out = '';
|
|
164
|
+
let buffer = partial + chunk;
|
|
165
|
+
partial = '';
|
|
166
|
+
let newlineIndex = buffer.indexOf('\n');
|
|
167
|
+
while (newlineIndex !== -1) {
|
|
168
|
+
const line = buffer.slice(0, newlineIndex + 1);
|
|
169
|
+
buffer = buffer.slice(newlineIndex + 1);
|
|
170
|
+
out += processLine(line);
|
|
171
|
+
newlineIndex = buffer.indexOf('\n');
|
|
172
|
+
}
|
|
173
|
+
partial = buffer;
|
|
174
|
+
return out;
|
|
175
|
+
},
|
|
176
|
+
flush() {
|
|
177
|
+
let out = '';
|
|
178
|
+
if (state !== 'pass') {
|
|
179
|
+
// A stream that closes mid-block: fold the trailing partial line in
|
|
180
|
+
// and evaluate — the final exception line is often the last thing
|
|
181
|
+
// printed, without a trailing newline.
|
|
182
|
+
if (partial.length > 0) {
|
|
183
|
+
held.push(partial);
|
|
184
|
+
partial = '';
|
|
185
|
+
}
|
|
186
|
+
out += releaseHeld();
|
|
187
|
+
}
|
|
188
|
+
out += partial;
|
|
189
|
+
partial = '';
|
|
190
|
+
return out;
|
|
191
|
+
},
|
|
192
|
+
};
|
|
193
|
+
}
|
|
@@ -113,4 +113,3 @@ export async function generateMozconfig(configsDir, engineDir, config) {
|
|
|
113
113
|
// the single source of truth for both the render and the sanity-check.
|
|
114
114
|
await assertBrandingMozconfigAgreement(engineDir, outputPath, config);
|
|
115
115
|
}
|
|
116
|
-
//# sourceMappingURL=mach-mozconfig.js.map
|
package/dist/src/core/mach.d.ts
CHANGED
|
@@ -17,6 +17,14 @@ export interface MachOptions {
|
|
|
17
17
|
env?: Record<string, string>;
|
|
18
18
|
/** Whether to inherit stdio (show output directly) */
|
|
19
19
|
inherit?: boolean;
|
|
20
|
+
/**
|
|
21
|
+
* Collapse the KNOWN mozsystemmonitor teardown traceback to one labeled
|
|
22
|
+
* line in the terminal ECHO (capture-only option). The captured
|
|
23
|
+
* stdout/stderr stay raw — the harness classifier depends on the raw
|
|
24
|
+
* traceback. Unrecognized tracebacks always echo verbatim. Opted into by
|
|
25
|
+
* the test dispatchers only.
|
|
26
|
+
*/
|
|
27
|
+
annotateKnownTeardownNoise?: boolean;
|
|
20
28
|
}
|
|
21
29
|
/**
|
|
22
30
|
* Result of running a mach command while capturing streamed output.
|
package/dist/src/core/mach.js
CHANGED
|
@@ -7,6 +7,7 @@ import { exec, execInherit, execInheritCapture, execSmokeRun, execStream, } from
|
|
|
7
7
|
import { createSiblingLockPath, withFileLock } from './file-lock.js';
|
|
8
8
|
import { ensureFirefoxIgnorefileCompatibility } from './firefox-ignorefile.js';
|
|
9
9
|
import { explainMachError } from './mach-error-hints.js';
|
|
10
|
+
import { createKnownTeardownNoiseFilter, createTeardownNoiseContext, } from './mach-known-noise-filter.js';
|
|
10
11
|
import { getPython } from './mach-python.js';
|
|
11
12
|
import { installMachResourceGuard } from './mach-resource-shim.js';
|
|
12
13
|
import { detectHarnessCrashSignature } from './test-harness-crash.js';
|
|
@@ -42,7 +43,12 @@ export async function runMach(args, engineDir, options = {}) {
|
|
|
42
43
|
...(options.env ? { env: options.env } : {}),
|
|
43
44
|
};
|
|
44
45
|
if (options.inherit) {
|
|
45
|
-
|
|
46
|
+
// Group-reap every long-lived inherited mach dispatch (bootstrap, run,
|
|
47
|
+
// watch): a mach dying at startup must not strand multiprocessing
|
|
48
|
+
// workers. Short-lived metadata queries below stay on plain exec() —
|
|
49
|
+
// adding groups there would touch every non-mach exec consumer's path
|
|
50
|
+
// for no reaping benefit.
|
|
51
|
+
return execInherit(python, [machPath, ...args], { ...execOptions, processGroup: true });
|
|
46
52
|
}
|
|
47
53
|
const result = await exec(python, [machPath, ...args], execOptions);
|
|
48
54
|
return result.exitCode;
|
|
@@ -67,24 +73,47 @@ export async function runMachCapture(args, engineDir, options = {}) {
|
|
|
67
73
|
const machPath = join(engineDir, 'mach');
|
|
68
74
|
let stdout = '';
|
|
69
75
|
let stderr = '';
|
|
76
|
+
// Echo-path filters only: the captured strings above accumulate RAW so the
|
|
77
|
+
// classifier still sees the full teardown traceback. When the option is
|
|
78
|
+
// off, the filters are absent and echo is a straight write (unchanged).
|
|
79
|
+
// One shutdown context per run, shared by both stream filters: the
|
|
80
|
+
// SUITE_END marker usually arrives on stdout while the teardown traceback
|
|
81
|
+
// lands on stderr, so the shutdown-seen flag must span the pair.
|
|
82
|
+
const noiseContext = options.annotateKnownTeardownNoise === true ? createTeardownNoiseContext() : undefined;
|
|
83
|
+
const stdoutFilter = noiseContext && createKnownTeardownNoiseFilter(noiseContext);
|
|
84
|
+
const stderrFilter = noiseContext && createKnownTeardownNoiseFilter(noiseContext);
|
|
70
85
|
const exitCode = await execStream(python, [machPath, ...args], {
|
|
71
86
|
cwd: engineDir,
|
|
72
87
|
...(options.env ? { env: options.env } : {}),
|
|
88
|
+
// Every capture dispatch (test suites, protected builds, package,
|
|
89
|
+
// storybook) runs as a process-group leader and is group-reaped on
|
|
90
|
+
// exit/abort — see ExecOptions.processGroup (0.37.0 item 9a).
|
|
91
|
+
processGroup: true,
|
|
73
92
|
onStdout: (data) => {
|
|
74
93
|
stdout += data;
|
|
75
94
|
if (stdout.length > CAPTURE_TAIL_LIMIT) {
|
|
76
95
|
stdout = stdout.slice(-CAPTURE_TAIL_LIMIT);
|
|
77
96
|
}
|
|
78
|
-
process.stdout.write(data);
|
|
97
|
+
process.stdout.write(stdoutFilter ? stdoutFilter.transform(data) : data);
|
|
79
98
|
},
|
|
80
99
|
onStderr: (data) => {
|
|
81
100
|
stderr += data;
|
|
82
101
|
if (stderr.length > CAPTURE_TAIL_LIMIT) {
|
|
83
102
|
stderr = stderr.slice(-CAPTURE_TAIL_LIMIT);
|
|
84
103
|
}
|
|
85
|
-
process.stderr.write(data);
|
|
104
|
+
process.stderr.write(stderrFilter ? stderrFilter.transform(data) : data);
|
|
86
105
|
},
|
|
87
106
|
});
|
|
107
|
+
if (stdoutFilter) {
|
|
108
|
+
const residue = stdoutFilter.flush();
|
|
109
|
+
if (residue.length > 0)
|
|
110
|
+
process.stdout.write(residue);
|
|
111
|
+
}
|
|
112
|
+
if (stderrFilter) {
|
|
113
|
+
const residue = stderrFilter.flush();
|
|
114
|
+
if (residue.length > 0)
|
|
115
|
+
process.stderr.write(residue);
|
|
116
|
+
}
|
|
88
117
|
return { stdout, stderr, exitCode };
|
|
89
118
|
}
|
|
90
119
|
/**
|
|
@@ -99,6 +128,7 @@ export async function runMachInheritCapture(args, engineDir, options = {}) {
|
|
|
99
128
|
return execInheritCapture(python, [machPath, ...args], {
|
|
100
129
|
cwd: engineDir,
|
|
101
130
|
...(options.env ? { env: options.env } : {}),
|
|
131
|
+
processGroup: true,
|
|
102
132
|
});
|
|
103
133
|
}
|
|
104
134
|
/**
|
|
@@ -363,6 +393,7 @@ export async function testWithOutput(engineDir, testPaths = [], args = [], env)
|
|
|
363
393
|
const guard = await installMachResourceGuard(engineDir);
|
|
364
394
|
return runMachCapture(['test', ...testPaths, ...args], engineDir, {
|
|
365
395
|
env: { ...guard.env, ...env },
|
|
396
|
+
annotateKnownTeardownNoise: true,
|
|
366
397
|
});
|
|
367
398
|
}
|
|
368
399
|
/**
|
|
@@ -379,6 +410,7 @@ export async function xpcshellTestWithOutput(engineDir, testPaths = [], args = [
|
|
|
379
410
|
const guard = await installMachResourceGuard(engineDir);
|
|
380
411
|
return runMachCapture(['xpcshell-test', ...testPaths, ...args], engineDir, {
|
|
381
412
|
env: { ...guard.env, ...env },
|
|
413
|
+
annotateKnownTeardownNoise: true,
|
|
382
414
|
});
|
|
383
415
|
}
|
|
384
416
|
/**
|
|
@@ -390,6 +422,6 @@ export async function mochitestWithOutput(engineDir, testPaths = [], args = [],
|
|
|
390
422
|
const guard = await installMachResourceGuard(engineDir);
|
|
391
423
|
return runMachCapture(['mochitest', ...testPaths, ...args], engineDir, {
|
|
392
424
|
env: { ...guard.env, ...env },
|
|
425
|
+
annotateKnownTeardownNoise: true,
|
|
393
426
|
});
|
|
394
427
|
}
|
|
395
|
-
//# sourceMappingURL=mach.js.map
|