python.ts
This commit is contained in:
@@ -1,14 +1,16 @@
|
||||
#!/usr/bin/env runts -- --allow-env --allow-run
|
||||
|
||||
import {
|
||||
execCommand,
|
||||
execCommandShell,
|
||||
existsPath,
|
||||
joinPath,
|
||||
log,
|
||||
readFileToString,
|
||||
resolveFilename,
|
||||
} from "https://global.hatter.ink/script/get/@12/deno-commons-mod.ts";
|
||||
} from "https://global.hatter.ink/script/get/@16/deno-commons-mod.ts";
|
||||
import { parseArgs } from "jsr:@std/cli/parse-args";
|
||||
import { spawn } from "node:child_process";
|
||||
import { writeStringToFile } from "../libraries/deno-commons-mod.ts";
|
||||
|
||||
const PYTHON_CONFIG_FILE = "~/.config/python-config.json";
|
||||
const PYTHON_VENV_DEFAULT_BASE_DIR = "~/.venv/";
|
||||
@@ -42,6 +44,14 @@ async function loadPythonConfig(): Promise<PythonConfig> {
|
||||
return JSON.parse(pythonConfigJson) as PythonConfig;
|
||||
}
|
||||
|
||||
async function savePythonConfig(pythonConfig: PythonConfig): Promise<void> {
|
||||
const pythonConfigFile = resolveFilename(PYTHON_CONFIG_FILE);
|
||||
await writeStringToFile(
|
||||
pythonConfigFile,
|
||||
JSON.stringify(pythonConfig, null, 2),
|
||||
);
|
||||
}
|
||||
|
||||
async function findVirtualEnv(pythonVenvVersion: string): Promise<PythonVenv> {
|
||||
const pythonConfig = await loadPythonConfig();
|
||||
if (!pythonConfig.profiles) {
|
||||
@@ -86,28 +96,14 @@ async function newVirtualEnv(pythonVersion: string | null, pythonVenv: string) {
|
||||
}
|
||||
|
||||
// python3 -m venv myenv
|
||||
const python3Cmd = await getPythonFromPath(pythonVersionProfile.path);
|
||||
const python3Cmd = pythonVersionProfile.path;
|
||||
log.success(`Found Python: ${python3Cmd}`);
|
||||
const pythonVenvArgs = ["-m", "vent", pythonVenvDir];
|
||||
const pythonVenvArgs = ["-m", "venv", pythonVenvDir];
|
||||
|
||||
log.info(
|
||||
`Create Python venv, python: ${python3Cmd}, args: ${pythonVenvArgs}`,
|
||||
);
|
||||
spawn(python3Cmd, pythonVenvArgs, {
|
||||
shell: true,
|
||||
stdio: ["inherit", "inherit", "inherit"],
|
||||
});
|
||||
}
|
||||
|
||||
async function getPythonFromPath(path: string): Promise<string> {
|
||||
if (await isFile(path)) {
|
||||
return path;
|
||||
}
|
||||
const python3Cmd = joinPath(pythonVersionProfile.path, "bin", "python3");
|
||||
if (await isFile(python3Cmd)) {
|
||||
return python3Cmd;
|
||||
}
|
||||
throw new Error(`Python path not found, path: ${path}`);
|
||||
await execCommandShell(python3Cmd, pythonVenvArgs);
|
||||
}
|
||||
|
||||
async function isFile(path: string): Promise<boolean> {
|
||||
@@ -116,7 +112,17 @@ async function isFile(path: string): Promise<boolean> {
|
||||
}
|
||||
|
||||
function handleHelp(_args: string[]) {
|
||||
console.log("Help message");
|
||||
const help = [];
|
||||
help.push(
|
||||
`python.ts - Python version and virtual environment management tool
|
||||
|
||||
python.ts python - management python version [alias: py]
|
||||
python.ts add-python - add python version [alias: py]
|
||||
python.ts venv - management python virtual environment`,
|
||||
);
|
||||
// source <(cat ~/.venv-python-3.13.5/bin/activate)
|
||||
// source <(python.ts venv test1)
|
||||
console.log(help.join("\n"));
|
||||
}
|
||||
|
||||
async function handlePython(args: string[]) {
|
||||
@@ -168,6 +174,77 @@ async function handlePython(args: string[]) {
|
||||
// TODO
|
||||
}
|
||||
|
||||
async function getPythonVersion(pythonBinPath: string): Promise<string> {
|
||||
const pythonVersion = await execCommand(pythonBinPath, ["--version"]);
|
||||
const pythonVersionLower = pythonVersion.assertSuccess()
|
||||
.getStdoutAsStringThenTrim().toLowerCase();
|
||||
if (!pythonVersionLower.startsWith("python ")) {
|
||||
throw new Error(`Invalid Python version: ${pythonVersionLower}`);
|
||||
}
|
||||
return pythonVersionLower.substring("python ".length).trim();
|
||||
}
|
||||
|
||||
async function handleAddPython(args: string[]) {
|
||||
const flags = parseArgs(Deno.args, {
|
||||
boolean: ["help"],
|
||||
string: ["path"],
|
||||
});
|
||||
if (flags.help) {
|
||||
console.log("Help massage for python add-python");
|
||||
return;
|
||||
}
|
||||
if (!flags.path) {
|
||||
throw new Error("Path is empty");
|
||||
}
|
||||
const path = flags.path as string;
|
||||
let pythonPath = path;
|
||||
if (!path.includes("/")) {
|
||||
const whichPath = await execCommand("which", [path]);
|
||||
pythonPath = whichPath.assertSuccess().getStdoutAsStringThenTrim();
|
||||
}
|
||||
log.info(`Python path: ${pythonPath}`);
|
||||
const isPythonPathFile = await isFile(pythonPath);
|
||||
let pythonBinPath = "";
|
||||
if (!isPythonPathFile) {
|
||||
const pythonPath1 = joinPath(pythonPath, "bin", "python3");
|
||||
if (await isFile(pythonPath1)) {
|
||||
pythonBinPath = pythonPath1;
|
||||
} else {
|
||||
const pythonPath2 = joinPath(pythonPath, "bin", "python");
|
||||
if (await isFile(pythonPath2)) {
|
||||
pythonBinPath = pythonPath2;
|
||||
} else {
|
||||
throw new Error(
|
||||
`Python bin path not found, python path: ${pythonPath}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
pythonBinPath = pythonPath;
|
||||
}
|
||||
const pythonVersion = await getPythonVersion(pythonBinPath);
|
||||
log.info(`Python version: ${pythonVersion}`);
|
||||
|
||||
const pythonConfig = await loadPythonConfig();
|
||||
|
||||
if (!pythonConfig.versions) {
|
||||
pythonConfig.versions = {};
|
||||
}
|
||||
if (pythonConfig.versions[pythonVersion]) {
|
||||
throw new Error(`Python version ${pythonVersion} exists`);
|
||||
}
|
||||
const pyVersion: PythonVersion = {
|
||||
version: pythonVersion,
|
||||
path: pythonBinPath,
|
||||
comment: `Python v${pythonVersion}`,
|
||||
};
|
||||
log.info("Found Python version", pyVersion);
|
||||
pythonConfig.versions[pythonVersion] = pyVersion;
|
||||
|
||||
log.info("Save to Python config");
|
||||
await savePythonConfig(pythonConfig);
|
||||
}
|
||||
|
||||
async function handleVenv(args: string[]) {
|
||||
const flags = parseArgs(Deno.args, {
|
||||
boolean: ["help"],
|
||||
@@ -194,7 +271,7 @@ async function main() {
|
||||
const [subcommand, ...remainingArgs] = args._;
|
||||
|
||||
if (!subcommand) {
|
||||
log.warn("Subcommand not found");
|
||||
log.warn("Subcommand not found, `python.ts help` for help message");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -206,6 +283,10 @@ async function main() {
|
||||
case "python":
|
||||
await handlePython(remainingArgs);
|
||||
break;
|
||||
case "add-py":
|
||||
case "add-python":
|
||||
await handleAddPython(remainingArgs);
|
||||
break;
|
||||
case "venv":
|
||||
await handleVenv(remainingArgs);
|
||||
break;
|
||||
|
||||
Reference in New Issue
Block a user