Skip to content

Commit

Permalink
trying to remove packaging files from pygen
Browse files Browse the repository at this point in the history
  • Loading branch information
iscai-msft committed May 16, 2024
1 parent c033992 commit ead7533
Show file tree
Hide file tree
Showing 6 changed files with 211 additions and 82 deletions.
3 changes: 1 addition & 2 deletions packages/autorest.python/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,7 @@
},
"homepage": "https://github.com/Azure/autorest.python/blob/main/README.md",
"dependencies": {
"@autorest/system-requirements": "~1.0.2",
"@azure-tools/python-client-generator-core": "workspace:^"
"@autorest/system-requirements": "~1.0.2"
},
"devDependencies": {
"@microsoft.azure/autorest.testserver": "^3.3.46",
Expand Down
43 changes: 0 additions & 43 deletions packages/pygen/package.json

This file was deleted.

175 changes: 173 additions & 2 deletions packages/pygen/run-python3.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,9 @@
// Invoke it like so: "node run-python3.js script.py"

const cp = require("child_process");
const extension = require("@autorest/system-requirements");

async function runPython3(scriptName, ...args) {
const command = await extension.patchPythonPath(["python", scriptName, ...args], { version: ">=3.8", environmentVariable: "AUTOREST_PYTHON_EXE" });
const command = await patchPythonPath(["python", scriptName, ...args], { version: ">=3.8", environmentVariable: "AUTOREST_PYTHON_EXE" });
cp.execSync(command.join(" "), {
stdio: [0, 1, 2]
});
Expand All @@ -20,3 +19,175 @@ runPython3(...process.argv.slice(2)).catch(err => {
console.error(err.toString());
process.exit(1);
});

/*
* Copied from @autorest/system-requirements
*/

const PythonRequirement = "python";
const PRINT_PYTHON_VERSION_SCRIPT = "import sys; print('.'.join(map(str, sys.version_info[:3])))";
const semver_1 = require("semver");

const execute = (command, cmdlineargs, options = {}) => {
return new Promise((resolve, reject) => {
const cp = (0, child_process_1.spawn)(command, cmdlineargs, { ...options, stdio: "pipe", shell: true });
if (options.onCreate) {
options.onCreate(cp);
}
options.onStdOutData ? cp.stdout.on("data", options.onStdOutData) : cp;
options.onStdErrData ? cp.stderr.on("data", options.onStdErrData) : cp;
let err = "";
let out = "";
let all = "";
cp.stderr.on("data", (chunk) => {
err += chunk;
all += chunk;
});
cp.stdout.on("data", (chunk) => {
out += chunk;
all += chunk;
});
cp.on("error", (err) => {
reject(err);
});
cp.on("close", (code, signal) => resolve({
stdout: out,
stderr: err,
log: all,
error: code ? new Error("Process Failed.") : null,
code,
}));
});
};

const versionIsSatisfied = (version, requirement) => {
const cleanedVersion = semver_1.default.coerce(version);
if (!cleanedVersion) {
throw new Error(`Invalid version ${version}.`);
}
return semver_1.default.satisfies(cleanedVersion, requirement, true);
};

/**
* Validate the provided system requirement resolution is satisfying the version requirement if applicable.
* @param resolution Command resolution.
* @param actualVersion Version for that resolution.
* @param requirement Requirement.
* @returns the resolution if it is valid or an @see SystemRequirementError if not.
*/
const validateVersionRequirement = (resolution, actualVersion, requirement) => {
if (!requirement.version) {
return resolution; // No version requirement.
}
try {
if ((0, versionIsSatisfied)(actualVersion, requirement.version)) {
return resolution;
}
return {
...resolution,
error: true,
message: `'${resolution.command}' version is '${actualVersion}' but doesn't satisfy requirement '${requirement.version}'. Please update.`,
actualVersion: actualVersion,
neededVersion: requirement.version,
};
}
catch (_a) {
return {
...resolution,
error: true,
message: `Couldn't parse the version ${actualVersion}. This is not a valid semver version.`,
actualVersion: actualVersion,
neededVersion: requirement.version,
};
}
};

const tryPython = async (requirement, command, additionalArgs = []) => {
const resolution = {
name: PythonRequirement,
command,
additionalArgs: additionalArgs.length > 0 ? additionalArgs : undefined,
};
try {
const result = await (0, execute)(command, [...additionalArgs, "-c", `"${PRINT_PYTHON_VERSION_SCRIPT}"`]);
return (0, validateVersionRequirement)(resolution, result.stdout.trim(), requirement);
}
catch (e) {
return {
error: true,
...resolution,
message: `'${command}' command line is not found in the path. Make sure to have it installed.`,
};
}
};

/**
* Returns the path to the executable as asked in the requirement.
* @param requirement System requirement definition.
* @returns If the requirement provide an environment variable for the path returns the value of that environment variable. undefined otherwise.
*/
const getExecutablePath = (requirement) => requirement.environmentVariable && process.env[requirement.environmentVariable];

const createPythonErrorMessage = (requirement, errors) => {
var _a;
const versionReq = (_a = requirement.version) !== null && _a !== void 0 ? _a : "*";
const lines = [
`Couldn't find a valid python interpreter satisfying the requirement (version: ${versionReq}). Tried:`,
...errors.map((x) => ` - ${x.command} (${x.message})`),
];
return {
error: true,
name: "python",
command: "python",
message: lines.join("\n"),
};
};

const resolvePythonRequirement = async (requirement) => {
var _a;
// Hardcoding AUTOREST_PYTHON_EXE is for backward compatibility
const path = (_a = (0, getExecutablePath)(requirement)) !== null && _a !== void 0 ? _a : process.env["AUTOREST_PYTHON_EXE"];
if (path) {
return await tryPython(requirement, path);
}
const errors = [];
// On windows try `py` executable with `-3` flag.
if (process.platform === "win32") {
const pyResult = await tryPython(requirement, "py", ["-3"]);
if ("error" in pyResult) {
errors.push(pyResult);
}
else {
return pyResult;
}
}
const python3Result = await tryPython(requirement, "python3");
if ("error" in python3Result) {
errors.push(python3Result);
}
else {
return python3Result;
}
const pythonResult = await tryPython(requirement, "python");
if ("error" in pythonResult) {
errors.push(pythonResult);
}
else {
return pythonResult;
}
return createPythonErrorMessage(requirement, errors);
};

/**
* @param command list of the command and arguments. First item in array must be a python exe @see KnownPythonExe. (e.g. ["python", "mypythonfile.py"]
* @param requirement
*/
const patchPythonPath = async (command, requirement) => {
var _a;
const [_, ...args] = command;
const resolution = await (0, resolvePythonRequirement)(requirement);
if ("error" in resolution) {
throw new Error(`Failed to find compatible python version. ${resolution.message}`);
}
return [resolution.command, ...((_a = resolution.additionalArgs) !== null && _a !== void 0 ? _a : []), ...args];
};
3 changes: 2 additions & 1 deletion packages/typespec-python/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,8 @@
"js-yaml": "~4.1.0",
"@typespec/openapi3": "~0.56.0",
"@autorest/system-requirements": "~1.0.2",
"fs-extra": "11.2.0"
"fs-extra": "11.2.0",
"semver": "7.6.2"
},
"devDependencies": {
"@azure-tools/typespec-azure-resource-manager": "~0.42.0",
Expand Down
7 changes: 6 additions & 1 deletion packages/typespec-python/scripts/post-build.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,10 @@ const __dirname = dirname(fileURLToPath(import.meta.url))
const sourceDir = join(__dirname, "..", "..", 'pygen');
const destDir = join(__dirname, "..", 'dist', "src", "pygen");

// Define the filter function. Don't want to copy node_modules
const filterFunc = (src) => {
return src.indexOf('node_modules') === -1;
};

// Copy the source directory to the destination directory
fs.copySync(sourceDir, destDir);
fs.copySync(sourceDir, destDir, { filter: filterFunc });
Loading

0 comments on commit ead7533

Please sign in to comment.