9e019d89d2
* Clean up actions and payloads * Clean up action * Cleanup
163 lines
4.2 KiB
TypeScript
163 lines
4.2 KiB
TypeScript
import { existsSync } from "node:fs";
|
|
import { join } from "node:path";
|
|
import { log } from "../utils/cli.ts";
|
|
import { spawn } from "../utils/subprocess.ts";
|
|
import type { PrepDefinition, PythonPackageManager, PythonPrepResult } from "./types.ts";
|
|
|
|
interface PythonConfig {
|
|
file: string;
|
|
tool: PythonPackageManager;
|
|
installCmd: string[];
|
|
}
|
|
|
|
// python dependency file patterns in priority order
|
|
const PYTHON_CONFIGS: PythonConfig[] = [
|
|
{
|
|
file: "requirements.txt",
|
|
tool: "pip",
|
|
installCmd: ["pip", "install", "-r", "requirements.txt"],
|
|
},
|
|
{
|
|
file: "pyproject.toml",
|
|
tool: "pip",
|
|
installCmd: ["pip", "install", "."],
|
|
},
|
|
{
|
|
file: "Pipfile",
|
|
tool: "pipenv",
|
|
installCmd: ["pipenv", "install"],
|
|
},
|
|
{
|
|
file: "Pipfile.lock",
|
|
tool: "pipenv",
|
|
installCmd: ["pipenv", "sync"],
|
|
},
|
|
{
|
|
file: "poetry.lock",
|
|
tool: "poetry",
|
|
installCmd: ["poetry", "install", "--no-interaction"],
|
|
},
|
|
{
|
|
file: "setup.py",
|
|
tool: "pip",
|
|
installCmd: ["pip", "install", "-e", "."],
|
|
},
|
|
];
|
|
|
|
// tool install commands (via pip)
|
|
const TOOL_INSTALL_COMMANDS: Record<string, string[]> = {
|
|
pipenv: ["pip", "install", "pipenv"],
|
|
poetry: ["pip", "install", "poetry"],
|
|
};
|
|
|
|
async function isCommandAvailable(command: string): Promise<boolean> {
|
|
const result = await spawn({
|
|
cmd: "which",
|
|
args: [command],
|
|
env: { PATH: process.env.PATH || "" },
|
|
});
|
|
return result.exitCode === 0;
|
|
}
|
|
|
|
async function installTool(name: string): Promise<string | null> {
|
|
const installCmd = TOOL_INSTALL_COMMANDS[name];
|
|
if (!installCmd) {
|
|
// tool doesn't need installation (e.g., pip)
|
|
return null;
|
|
}
|
|
|
|
log.info(`» installing ${name}...`);
|
|
const [cmd, ...args] = installCmd;
|
|
const result = await spawn({
|
|
cmd,
|
|
args,
|
|
env: { PATH: process.env.PATH || "", HOME: process.env.HOME || "" },
|
|
onStderr: (chunk) => process.stderr.write(chunk),
|
|
});
|
|
|
|
if (result.exitCode !== 0) {
|
|
return result.stderr || `failed to install ${name}`;
|
|
}
|
|
|
|
log.info(`» installed ${name}`);
|
|
return null;
|
|
}
|
|
|
|
export const installPythonDependencies: PrepDefinition = {
|
|
name: "installPythonDependencies",
|
|
|
|
shouldRun: async () => {
|
|
// check if python is available
|
|
const hasPython = (await isCommandAvailable("python3")) || (await isCommandAvailable("python"));
|
|
if (!hasPython) {
|
|
return false;
|
|
}
|
|
|
|
// check if any python config file exists
|
|
const cwd = process.cwd();
|
|
return PYTHON_CONFIGS.some((config) => existsSync(join(cwd, config.file)));
|
|
},
|
|
|
|
run: async (): Promise<PythonPrepResult> => {
|
|
const cwd = process.cwd();
|
|
|
|
// find the first matching config
|
|
const config = PYTHON_CONFIGS.find((c) => existsSync(join(cwd, c.file)));
|
|
if (!config) {
|
|
return {
|
|
language: "python",
|
|
packageManager: "pip",
|
|
configFile: "unknown",
|
|
dependenciesInstalled: false,
|
|
issues: ["no python config file found"],
|
|
};
|
|
}
|
|
|
|
log.info(`» detected python config: ${config.file} (using ${config.tool})`);
|
|
|
|
// check if the tool is available, install if needed
|
|
const isAvailable = await isCommandAvailable(config.tool);
|
|
if (!isAvailable) {
|
|
log.info(`» ${config.tool} not found, attempting to install...`);
|
|
const installError = await installTool(config.tool);
|
|
if (installError) {
|
|
return {
|
|
language: "python",
|
|
packageManager: config.tool,
|
|
configFile: config.file,
|
|
dependenciesInstalled: false,
|
|
issues: [installError],
|
|
};
|
|
}
|
|
}
|
|
|
|
// run the install command
|
|
const [cmd, ...args] = config.installCmd;
|
|
log.info(`» running: ${cmd} ${args.join(" ")}`);
|
|
const result = await spawn({
|
|
cmd,
|
|
args,
|
|
env: { PATH: process.env.PATH || "", HOME: process.env.HOME || "" },
|
|
onStderr: (chunk) => process.stderr.write(chunk),
|
|
});
|
|
|
|
if (result.exitCode !== 0) {
|
|
return {
|
|
language: "python",
|
|
packageManager: config.tool,
|
|
configFile: config.file,
|
|
dependenciesInstalled: false,
|
|
issues: [result.stderr || `${cmd} exited with code ${result.exitCode}`],
|
|
};
|
|
}
|
|
|
|
return {
|
|
language: "python",
|
|
packageManager: config.tool,
|
|
configFile: config.file,
|
|
dependenciesInstalled: true,
|
|
issues: [],
|
|
};
|
|
},
|
|
};
|