renovate
Version:
Automated dependency updates. Flexible so you don't need to be.
174 lines • 8.2 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.LOCKFIlE_HEADER_TEXT = exports.VERSIONS_LOCK = exports.VERSIONS_PROPS = void 0;
exports.usesGcv = usesGcv;
exports.isGcvPropsFile = isGcvPropsFile;
exports.isGcvLockFile = isGcvLockFile;
exports.parseGcv = parseGcv;
exports.parseLockFile = parseLockFile;
exports.parsePropsFile = parsePropsFile;
const tslib_1 = require("tslib");
const logger_1 = require("../../../../logger");
const fs = tslib_1.__importStar(require("../../../../util/fs"));
const regex_1 = require("../../../../util/regex");
const string_1 = require("../../../../util/string");
const utils_1 = require("../utils");
exports.VERSIONS_PROPS = 'versions.props';
exports.VERSIONS_LOCK = 'versions.lock';
exports.LOCKFIlE_HEADER_TEXT = (0, regex_1.regEx)(/^# Run \.\/gradlew (?:--write-locks|writeVersionsLock|writeVersionsLocks) to regenerate this file/);
/**
* Determines if Palantir gradle-consistent-versions is in use, https://github.com/palantir/gradle-consistent-versions.
* Both `versions.props` and `versions.lock` must exist and the special header line of lock file must match
*
* @param versionsPropsFilename is the full file name path of `versions.props`
* @param fileContents map with file contents of all files
*/
function usesGcv(versionsPropsFilename, fileContents) {
const versionsLockFile = fs.getSiblingFileName(versionsPropsFilename, exports.VERSIONS_LOCK);
return !!fileContents[versionsLockFile]?.match(exports.LOCKFIlE_HEADER_TEXT);
}
/**
* Confirms whether the provided file name is the props file
*/
function isGcvPropsFile(fileName) {
return fileName === exports.VERSIONS_PROPS || fileName.endsWith(`/${exports.VERSIONS_PROPS}`);
}
/**
* Confirms whether the provided file name is the lock file
*/
function isGcvLockFile(fileName) {
return fileName === exports.VERSIONS_LOCK || fileName.endsWith(`/${exports.VERSIONS_LOCK}`);
}
/**
* Parses Gradle-Consistent-Versions files to figure out what dependencies, versions
* and groups they contain. The parsing goes like this:
* - Parse `versions.props` into deps (or groups) and versions, remembering file offsets
* - Parse `versions.lock` into deps and lock-versions
* - For each exact dep in props file, lookup the lock-version from lock file
* - For each group/regex dep in props file, lookup the set of exact deps and versions in lock file
*
* @param propsFileName name and path of the props file
* @param fileContents text content of all files
*/
function parseGcv(propsFileName, fileContents) {
const propsFileContent = (0, string_1.coerceString)(fileContents[propsFileName]);
const lockFileName = fs.getSiblingFileName(propsFileName, exports.VERSIONS_LOCK);
const lockFileContent = (0, string_1.coerceString)(fileContents[lockFileName]);
const lockFileMap = parseLockFile(lockFileContent);
const [propsFileExactMap, propsFileRegexMap] = parsePropsFile(propsFileContent);
const extractedDeps = [];
// For each exact dep in props file
for (const [propDep, versionAndPosition] of propsFileExactMap) {
if (lockFileMap.has(propDep)) {
const newDep = {
managerData: {
packageFile: propsFileName,
fileReplacePosition: versionAndPosition.filePos,
},
depName: propDep,
currentValue: versionAndPosition.version,
lockedVersion: lockFileMap.get(propDep)?.version,
depType: lockFileMap.get(propDep)?.depType,
};
extractedDeps.push(newDep);
// Remove from the lockfile map so the same exact lib will not be included in globbing
lockFileMap.delete(propDep);
}
}
// For each regular expression dep in props file (starting with the longest glob string)...
for (const [propDepGlob, propVerAndPos] of propsFileRegexMap) {
const globRegex = globToRegex(propDepGlob);
for (const [exactDep, lockVersionAndDepType] of lockFileMap) {
if (globRegex.test(exactDep)) {
const newDep = {
managerData: {
packageFile: propsFileName,
fileReplacePosition: propVerAndPos.filePos,
},
depName: exactDep,
currentValue: propVerAndPos.version,
lockedVersion: lockVersionAndDepType.version,
depType: lockVersionAndDepType.depType,
sharedVariableName: propDepGlob,
};
extractedDeps.push(newDep);
// Remove from the lockfile map so the same lib will not be included in more generic globs later
lockFileMap.delete(exactDep);
}
}
}
return extractedDeps;
}
// Translate glob syntax to a regex that does the same. Note that we cannot use replaceAll as it does not exist in Node14
// Loosely borrowed mapping to regex from https://github.com/palantir/gradle-consistent-versions/blob/develop/src/main/java/com/palantir/gradle/versions/FuzzyPatternResolver.java
function globToRegex(depName) {
return (0, regex_1.regEx)(depName
.replace(/\*/g, '_WC_CHAR_')
.replace(/[/\-\\^$*+?.()|[\]{}]/g, '\\$&')
.replace(/_WC_CHAR_/g, '.*?'));
}
/**
* Parses `versions.lock`
*/
function parseLockFile(input) {
const lockLineRegex = (0, regex_1.regEx)(`^(?<depName>[^:]+:[^:]+):(?<lockVersion>[^ ]+) \\(\\d+ constraints: [0-9a-f]+\\)$`);
const depVerMap = new Map();
let isTestDepType = false;
for (const line of input.split(regex_1.newlineRegex)) {
const lineMatch = lockLineRegex.exec(line);
if (lineMatch?.groups) {
const { depName, lockVersion } = lineMatch.groups;
if ((0, utils_1.isDependencyString)(`${depName}:${lockVersion}`)) {
depVerMap.set(depName, {
version: lockVersion,
depType: isTestDepType ? 'test' : 'dependencies',
});
}
}
else if (line === '[Test dependencies]') {
isTestDepType = true; // We know that all lines below this header are test dependencies
}
}
logger_1.logger.trace(`Found ${depVerMap.size} locked dependencies in ${exports.VERSIONS_LOCK}.`);
return depVerMap;
}
/**
* Parses `versions.props`, this is CR/LF safe
* @param input the entire property file from file system
* @return two maps, first being exact matches, second regex matches
*/
function parsePropsFile(input) {
const propsLineRegex = (0, regex_1.regEx)(`^(?<depName>[^:]+:[^=]+?) *= *(?<propsVersion>.*)$`);
const depVerExactMap = new Map();
const depVerRegexMap = new Map();
let startOfLineIdx = 0;
const isCrLf = input.indexOf('\r\n') > 0;
const validGlob = /^[a-zA-Z][-_a-zA-Z0-9.:*]+$/;
for (const line of input.split(regex_1.newlineRegex)) {
const lineMatch = propsLineRegex.exec(line);
if (lineMatch?.groups) {
const { depName, propsVersion } = lineMatch.groups;
if (validGlob.test(depName) &&
(0, utils_1.versionLikeSubstring)(propsVersion) !== null) {
const startPosInLine = line.lastIndexOf(propsVersion);
const propVersionPos = startOfLineIdx + startPosInLine;
if (depName.includes('*')) {
depVerRegexMap.set(depName, {
version: propsVersion,
filePos: propVersionPos,
});
}
else {
depVerExactMap.set(depName, {
version: propsVersion,
filePos: propVersionPos,
});
}
}
}
startOfLineIdx += line.length + (isCrLf ? 2 : 1);
}
logger_1.logger.trace(`Found ${depVerExactMap.size} dependencies and ${depVerRegexMap.size} wildcard dependencies in ${exports.VERSIONS_PROPS}.`);
return [depVerExactMap, new Map([...depVerRegexMap].sort().reverse())];
}
//# sourceMappingURL=consistent-versions-plugin.js.map