mirror of
https://github.com/morluto/rea
synced 2026-10-27 06:33:32 -04:00
1eca600515
* fix(apktool): resolve Windows PATH launchers before invocation Resolve the default launcher through the selected PATH/PATHEXT before choosing native process creation or the existing conservative cmd.exe wrapper. Reuse the resulting selection and one canonical environment for the version probe and decode. Follow-up to the release #1693 review of #1777. Source inspected and formatted; tests, builds, check reruns and real Windows Apktool execution were skipped at maintainer request. * fix(apktool): bound lookup and retain only selected environment Source inspection and targeted formatting only. Tests, builds, lint, typechecks and provider workloads were not run at the user's explicit request. * fix(apktool): use supported timeout diagnostics Retain lookup phase through AnalysisErrorOptions diagnostics while preserving the operation and timeout identity. Source inspection and targeted formatting only; tests, checks, builds and provider workloads were skipped at the user request. --------- Co-authored-by: morluto <morluto@users.noreply.github.com>
139 lines
4.4 KiB
TypeScript
139 lines
4.4 KiB
TypeScript
import {
|
|
analysisProfileSchema,
|
|
type AnalysisProfileCommitment,
|
|
} from "../../domain/analysisProfile.js";
|
|
import type { BinaryTarget } from "../../domain/binaryTargetTypes.js";
|
|
import {
|
|
AnalysisCancelledError,
|
|
AnalysisUnsupportedTargetError,
|
|
} from "../../domain/analysisErrorCore.js";
|
|
import type { AnalysisError } from "../../domain/analysisErrorBase.js";
|
|
import { jsonObjectSchema, type JsonValue } from "../../domain/jsonValue.js";
|
|
import { err, ok, type Result } from "../../domain/result.js";
|
|
import type { AnalysisProviderCandidate } from "../AnalysisProvider.js";
|
|
import type { AnalysisProviderCandidateStatus } from "./AnalysisProviderRegistry.js";
|
|
import { ABORTED, waitForAbortable } from "../../process/AbortablePromise.js";
|
|
|
|
/** Profile-resolution truth for one discovered provider candidate. */
|
|
export interface AnalysisProviderCandidateEvaluation {
|
|
readonly candidate: AnalysisProviderCandidate;
|
|
readonly status: AnalysisProviderCandidateStatus;
|
|
readonly profile?: AnalysisProfileCommitment;
|
|
readonly profileError?: AnalysisError;
|
|
}
|
|
|
|
/** Resolve and validate one provider profile without starting its client. */
|
|
export const evaluateAnalysisProviderCandidate = async (
|
|
candidate: AnalysisProviderCandidate,
|
|
status: AnalysisProviderCandidateStatus,
|
|
target: BinaryTarget,
|
|
signal: AbortSignal | undefined,
|
|
): Promise<
|
|
Result<AnalysisProviderCandidateEvaluation, AnalysisCancelledError>
|
|
> => {
|
|
if (signalIsAborted(signal))
|
|
return err(new AnalysisCancelledError("open_binary"));
|
|
let resolved: Awaited<ReturnType<typeof candidate.resolveAnalysisProfile>>;
|
|
try {
|
|
const resolution = await waitForAbortable(
|
|
candidate.resolveAnalysisProfile(
|
|
target,
|
|
signal === undefined ? undefined : { signal },
|
|
),
|
|
signal,
|
|
);
|
|
if (resolution === ABORTED)
|
|
return err(new AnalysisCancelledError("open_binary"));
|
|
resolved = resolution;
|
|
} catch (cause: unknown) {
|
|
void cause;
|
|
return ok(
|
|
rejectedProfile(candidate, status, "Provider profile resolution threw"),
|
|
);
|
|
}
|
|
if (signalIsAborted(signal))
|
|
return err(new AnalysisCancelledError("open_binary"));
|
|
if (!resolved.ok && resolved.error instanceof AnalysisCancelledError)
|
|
return err(resolved.error);
|
|
if (!resolved.ok) {
|
|
const error = resolved.error;
|
|
const rejection =
|
|
error instanceof AnalysisUnsupportedTargetError
|
|
? {
|
|
candidate,
|
|
status: {
|
|
...status,
|
|
targetSupport: {
|
|
status: "unsupported" as const,
|
|
code: "target_format_unsupported" as const,
|
|
reason: error.reason,
|
|
diagnostics: { path: error.path, error_tag: error._tag },
|
|
},
|
|
},
|
|
}
|
|
: rejectedProfile(candidate, status, error.message, {
|
|
error_tag: error._tag,
|
|
});
|
|
return ok({ ...rejection, profileError: error });
|
|
}
|
|
try {
|
|
if (resolved.value.profile === null)
|
|
return ok(
|
|
rejectedProfile(
|
|
candidate,
|
|
status,
|
|
"Provider version or analysis profile could not be resolved",
|
|
),
|
|
);
|
|
const profile = analysisProfileSchema.parse(resolved.value.profile);
|
|
const identity = candidate.identity();
|
|
if (
|
|
profile.provider.id !== identity.id ||
|
|
profile.provider.name !== identity.name ||
|
|
(identity.version !== null &&
|
|
profile.provider.version !== identity.version)
|
|
)
|
|
return ok(
|
|
rejectedProfile(
|
|
candidate,
|
|
status,
|
|
"Resolved analysis profile has mismatched provider identity",
|
|
),
|
|
);
|
|
return ok({ candidate, status, profile });
|
|
} catch (cause: unknown) {
|
|
void cause;
|
|
return ok(
|
|
rejectedProfile(
|
|
candidate,
|
|
status,
|
|
"Provider returned an invalid analysis profile",
|
|
),
|
|
);
|
|
}
|
|
};
|
|
|
|
const signalIsAborted = (signal: AbortSignal | undefined): boolean =>
|
|
signal?.aborted === true;
|
|
|
|
const rejectedProfile = (
|
|
candidate: AnalysisProviderCandidate,
|
|
status: AnalysisProviderCandidateStatus,
|
|
reason: string,
|
|
diagnostics: Readonly<Record<string, JsonValue>> = {},
|
|
): AnalysisProviderCandidateEvaluation => ({
|
|
candidate,
|
|
status: {
|
|
...status,
|
|
availability: {
|
|
status: "unavailable",
|
|
code: "version_unresolved",
|
|
reason,
|
|
diagnostics: jsonObjectSchema.parse({
|
|
...status.availability.diagnostics,
|
|
...diagnostics,
|
|
}),
|
|
},
|
|
},
|
|
});
|