"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.PdmProcessor = void 0;
const tslib_1 = require("tslib");
const is_1 = tslib_1.__importDefault(require("@sindresorhus/is"));
const shlex_1 = require("shlex");
const error_messages_1 = require("../../../../constants/error-messages");
const logger_1 = require("../../../../logger");
const exec_1 = require("../../../../util/exec");
const fs_1 = require("../../../../util/fs");
const result_1 = require("../../../../util/result");
const pypi_1 = require("../../../datasource/pypi");
const schema_1 = require("../schema");
const utils_1 = require("../utils");
const pdmUpdateCMD = 'pdm update --no-sync --update-eager';
class PdmProcessor {
    process(project, deps) {
        const pdm = project.tool?.pdm;
        if (is_1.default.nullOrUndefined(pdm)) {
            return deps;
        }
        deps.push(...(0, utils_1.parseDependencyGroupRecord)(utils_1.depTypes.pdmDevDependencies, pdm['dev-dependencies']));
        const pdmSource = pdm.source;
        if (is_1.default.nullOrUndefined(pdmSource)) {
            return deps;
        }
        // add pypi default url, if there is no source declared with the name `pypi`. https://daobook.github.io/pdm/pyproject/tool-pdm/#specify-other-sources-for-finding-packages
        const containsPyPiUrl = pdmSource.some((value) => value.name === 'pypi');
        const registryUrls = [];
        if (!containsPyPiUrl) {
            registryUrls.push(pypi_1.PypiDatasource.defaultURL);
        }
        for (const source of pdmSource) {
            registryUrls.push(source.url);
        }
        for (const dep of deps) {
            dep.registryUrls = [...registryUrls];
        }
        return deps;
    }
    async extractLockedVersions(project, deps, packageFile) {
        if (is_1.default.nullOrUndefined(project.tool?.pdm) &&
            project['build-system']?.['build-backend'] !== 'pdm.backend') {
            return Promise.resolve(deps);
        }
        const lockFileName = (0, fs_1.getSiblingFileName)(packageFile, 'pdm.lock');
        const lockFileContent = await (0, fs_1.readLocalFile)(lockFileName, 'utf8');
        if (lockFileContent) {
            const lockFileMapping = result_1.Result.parse(lockFileContent, schema_1.PdmLockfileSchema.transform(({ lock }) => lock)).unwrapOrElse({});
            for (const dep of deps) {
                const packageName = dep.packageName;
                if (packageName && packageName in lockFileMapping) {
                    dep.lockedVersion = lockFileMapping[packageName];
                }
            }
        }
        return Promise.resolve(deps);
    }
    async updateArtifacts(updateArtifact, project) {
        const { config, updatedDeps, packageFileName } = updateArtifact;
        const isLockFileMaintenance = config.updateType === 'lockFileMaintenance';
        // abort if no lockfile is defined
        const lockFileName = (0, fs_1.getSiblingFileName)(packageFileName, 'pdm.lock');
        try {
            const existingLockFileContent = await (0, fs_1.readLocalFile)(lockFileName, 'utf8');
            if (is_1.default.nullOrUndefined(existingLockFileContent)) {
                logger_1.logger.debug('No pdm.lock found');
                return null;
            }
            const pythonConstraint = {
                toolName: 'python',
                constraint: config.constraints?.python ?? project.project?.['requires-python'],
            };
            const pdmConstraint = {
                toolName: 'pdm',
                constraint: config.constraints?.pdm,
            };
            const execOptions = {
                cwdFile: packageFileName,
                docker: {},
                userConfiguredEnv: config.env,
                toolConstraints: [pythonConstraint, pdmConstraint],
            };
            // on lockFileMaintenance do not specify any packages and update the complete lock file
            // else only update specific packages
            const cmds = [];
            if (isLockFileMaintenance) {
                cmds.push(pdmUpdateCMD);
            }
            else {
                cmds.push(...generateCMDs(updatedDeps));
            }
            await (0, exec_1.exec)(cmds, execOptions);
            // check for changes
            const fileChanges = [];
            const newLockContent = await (0, fs_1.readLocalFile)(lockFileName, 'utf8');
            const isLockFileChanged = existingLockFileContent !== newLockContent;
            if (isLockFileChanged) {
                fileChanges.push({
                    file: {
                        type: 'addition',
                        path: lockFileName,
                        contents: newLockContent,
                    },
                });
            }
            else {
                logger_1.logger.debug('pdm.lock is unchanged');
            }
            return fileChanges.length ? fileChanges : null;
        }
        catch (err) {
            // istanbul ignore if
            if (err.message === error_messages_1.TEMPORARY_ERROR) {
                throw err;
            }
            logger_1.logger.debug({ err }, 'Failed to update PDM lock file');
            return [
                {
                    artifactError: {
                        lockFile: lockFileName,
                        stderr: err.message,
                    },
                },
            ];
        }
    }
}
exports.PdmProcessor = PdmProcessor;
function generateCMDs(updatedDeps) {
    const cmds = [];
    const packagesByCMD = {};
    for (const dep of updatedDeps) {
        switch (dep.depType) {
            case utils_1.depTypes.optionalDependencies: {
                const [group, name] = dep.depName.split('/');
                addPackageToCMDRecord(packagesByCMD, `${pdmUpdateCMD} -G ${(0, shlex_1.quote)(group)}`, name);
                break;
            }
            case utils_1.depTypes.pdmDevDependencies: {
                const [group, name] = dep.depName.split('/');
                addPackageToCMDRecord(packagesByCMD, `${pdmUpdateCMD} -dG ${(0, shlex_1.quote)(group)}`, name);
                break;
            }
            case utils_1.depTypes.buildSystemRequires:
                // build requirements are not locked in the lock files, no need to update.
                // Reference: https://github.com/pdm-project/pdm/discussions/2869
                break;
            default: {
                addPackageToCMDRecord(packagesByCMD, pdmUpdateCMD, dep.packageName);
            }
        }
    }
    for (const commandPrefix in packagesByCMD) {
        const packageList = packagesByCMD[commandPrefix].map(shlex_1.quote).join(' ');
        const cmd = `${commandPrefix} ${packageList}`;
        cmds.push(cmd);
    }
    return cmds;
}
function addPackageToCMDRecord(packagesByCMD, commandPrefix, packageName) {
    if (is_1.default.nullOrUndefined(packagesByCMD[commandPrefix])) {
        packagesByCMD[commandPrefix] = [];
    }
    packagesByCMD[commandPrefix].push(packageName);
}
//# sourceMappingURL=pdm.js.map