feat: Cargo manager use toml parser (#3505)

This commit is contained in:
Nikita Chashchinskii 2019-04-09 11:25:13 +03:00 committed by Rhys Arkins
parent ec16c8b2b8
commit 9476c80f3d
11 changed files with 753 additions and 307 deletions

View file

@ -1,165 +1,105 @@
const toml = require('toml');
const semver = require('../../versioning/cargo');
module.exports = {
extractPackageFile,
getDep,
getInlineTableDep,
getTableDep,
};
/* Quote from TOML spec. */
/*
Inline tables are intended to appear on a single line. No newlines are
allowed between the curly braces unless they are valid within a value.
Even so, it is strongly discouraged to break an inline table onto
multiples lines. If you find yourself gripped with this desire, it
means you should be using standard tables.
*/
// TODO: Find and fix all corner cases
function extractPackageFile(content, fileName) {
logger.trace(`cargo.extractPackageFile(${fileName})`);
let deps = [];
let lineNumber = 0;
const lines = content.split('\n');
for (const line of lines) {
if (line.trim()[0] !== '#') {
const match = line.match('dependencies[.]');
if (match) {
const dep = getTableDep(match, lines, lineNumber);
if (dep) {
deps.push(dep);
}
} else if (line.match('dependencies')) {
const sectionDeps = getDeps(lines, lineNumber);
deps = [].concat(deps, sectionDeps);
}
lineNumber += 1;
}
}
if (!deps.length) {
let parsedContent;
try {
parsedContent = toml.parse(content);
} catch (err) {
logger.debug({ err }, 'Error parsing Cargo.toml file');
return null;
}
for (let i = 0; i < deps.length; i += 1) {
const dep = deps[i];
deps[i].purl = 'pkg:cargo/' + deps[i].depName;
deps[i].datasource = 'cargo';
if (dep && !dep.skipReason && dep.currentValue) {
if (!semver.isValid(dep.currentValue)) {
deps[i].skipReason = 'unknown-version';
}
}
/*
There are the following sections in Cargo.toml:
[dependencies]
[dev-dependencies]
[build-dependencies]
[target.*.dependencies]
*/
const targetSection = parsedContent.target;
// An array of all dependencies in the target section
let targetDeps = [];
if (targetSection) {
const targets = Object.keys(targetSection);
targets.forEach(target => {
const targetContent = parsedContent.target[target];
// Dependencies for `${target}`
const deps = [
...extractFromSection(targetContent, 'dependencies', target),
...extractFromSection(targetContent, 'dev-dependencies', target),
...extractFromSection(targetContent, 'build-dependencies', target),
];
targetDeps = targetDeps.concat(deps);
});
}
const deps = [
...extractFromSection(parsedContent, 'dependencies'),
...extractFromSection(parsedContent, 'dev-dependencies'),
...extractFromSection(parsedContent, 'build-dependencies'),
...targetDeps,
];
if (!deps.length) {
return null;
}
return { deps };
}
// Get dependencies in a [dependencies], or [dev-dependencies],
// or [build-dependencies], etc section
function getDeps(lines, lineNumber) {
function extractFromSection(parsedContent, section, target) {
const deps = [];
for (
let i = 1;
lineNumber + i < lines.length && lines[lineNumber + i].trim()[0] !== '[';
i += 1
) {
let dep = null;
const l = lines[lineNumber + i];
// Ignore comments
if (l.trim()[0] !== '#') {
if (l.match('{*}')) {
dep = getInlineTableDep(l);
const sectionContent = parsedContent[section];
if (!sectionContent) {
return [];
}
Object.keys(sectionContent).forEach(depName => {
let skipReason;
let currentValue = sectionContent[depName];
let nestedVersion = false;
if (typeof currentValue !== 'string') {
const version = sectionContent[depName].version;
const path = sectionContent[depName].path;
const git = sectionContent[depName].git;
if (version) {
currentValue = version;
nestedVersion = true;
if (path) {
skipReason = 'path-dependency';
}
if (git) {
skipReason = 'git-dependency';
}
} else if (path) {
currentValue = '';
skipReason = 'path-dependency';
} else if (git) {
currentValue = '';
skipReason = 'git-dependency';
} else {
dep = getDep(l);
}
if (dep) {
dep.lineNumber = lineNumber + i;
deps.push(dep);
currentValue = '';
skipReason = 'invalid-dependency-specification';
}
}
}
const dep = {
depName,
depType: section,
currentValue,
nestedVersion,
datasource: 'cargo',
purl: 'pkg:cargo/' + depName,
};
if (skipReason) {
dep.skipReason = skipReason;
} else if (!semver.isValid(dep.currentValue)) {
dep.skipReason = 'unknown-version';
}
if (target) {
dep.target = target;
}
deps.push(dep);
});
return deps;
}
// Get a normal dependency name and version
// Example: foo = '1.2.3'
function getDep(line) {
const entry = line.split('=');
const remaining = entry.slice(1).join('=');
const dep = {};
const depName = entry[0].trim();
if (depName) {
const currentValue = remaining
.trim()
.replace(/['"]+/g, '')
.trim();
dep.currentValue = currentValue;
dep.depName = depName;
dep.depType = 'normal';
return dep;
}
return null;
}
// Get dependency name and version from an inline table
// Example: pcap-sys = { version = "0.1", path = "pcap-sys" }
function getInlineTableDep(line) {
const dep = {};
let content = line.split('=');
dep.depName = content[0].trim();
content = content.slice(1);
content = content.join('=');
content = content.trim().replace(/[{}]+/g, '');
const fields = content.split(',');
for (let i = 0; i < fields.length; i += 1) {
const field = fields[i].split('=');
const remaining = field.slice(1).join('=');
const name = field[0].trim();
const value = remaining.trim();
if (name === 'path') {
dep.skipReason = 'path-dependency';
}
if (name === 'version') {
dep.currentValue = value.replace(/['"]+/g, '').trim();
dep.depType = 'inlineTable';
}
}
if (dep.currentValue || dep.skipReason) {
return dep;
}
return null;
}
// Get dependency name and version from a standard TOML table
function getTableDep(match, lines, lineNumber) {
const dep = {};
let input = match.input;
if (input.trim()[0] === '#') {
return null;
}
input = input.replace(/[[\]]+/g, '');
input = input.split('.');
dep.depName = input[input.length - 1];
// Record the line number of [*dependencies.<depName>] expression
dep.lineNumber = lineNumber;
let name = '';
for (let i = 1; lineNumber + i < lines.length; i += 1) {
const field = lines[lineNumber + i].split('=');
const remaining = field.slice(1).join('=');
name = field[0].trim();
if (name === 'path') {
dep.skipReason = 'path-dependency';
}
if (name === 'version') {
dep.currentValue = remaining
.trim()
.replace(/['"]+/g, '')
.trim();
dep.depType = 'standardTable';
dep.versionLineNumber = lineNumber + i;
}
}
if (dep.currentValue || dep.skipReason) {
return dep;
}
return null;
}

View file

@ -1,39 +1,125 @@
const { getDep, getInlineTableDep, getTableDep } = require('./extract');
const _ = require('lodash');
const toml = require('toml');
module.exports = {
updateDependency,
};
function updateDependency(currentFileContent, upgrade) {
logger.trace({ config: upgrade }, 'cargo.updateDependency()');
const { depName, depType, lineNumber, newValue } = upgrade;
const lines = currentFileContent.split('\n');
let dep;
let currentValue;
let versionLineNumber = lineNumber;
const line = lines[lineNumber];
if (depType === 'normal') {
dep = getDep(line);
} else if (depType === 'inlineTable') {
dep = getInlineTableDep(line);
} else if (depType === 'standardTable' && line) {
const match = line.match('dependencies[.]');
// Might need handling comments in getTableDep
dep = getTableDep(match, lines, lineNumber);
if (dep) {
versionLineNumber = dep.versionLineNumber;
}
// Return true if the match string is found at index in content
function matchAt(content, index, match) {
return content.substring(index, index + match.length) === match;
}
// Replace oldString with newString at location index of content
function replaceAt(content, index, oldString, newString) {
logger.debug(`Replacing ${oldString} with ${newString} at index ${index}`);
return (
content.substr(0, index) +
newString +
content.substr(index + oldString.length)
);
}
function updateDependency(fileContent, upgrade) {
logger.trace({ config: upgrade }, 'poetry.updateDependency()');
if (!upgrade) {
return fileContent;
}
if (dep && !dep.skipReason) {
currentValue = dep.currentValue;
if (dep.depName.match(depName)) {
lines[versionLineNumber] = lines[versionLineNumber].replace(
currentValue,
newValue
const { target, depType, depName, newValue, nestedVersion } = upgrade;
let parsedContent;
try {
parsedContent = toml.parse(fileContent);
} catch (err) {
logger.debug({ err }, 'Error parsing Cargo.toml file');
return fileContent;
}
let section;
if (target) {
section = parsedContent.target[target];
if (section) {
section = section[depType];
}
} else {
section = parsedContent[depType];
}
if (!section) {
if (target) {
logger.info(
{ config: upgrade },
`Error: Section [target.${target}.${depType}] doesn't exist in Cargo.toml file, update failed`
);
} else {
logger.debug(dep, upgrade, 'Invalid upgrade.lineNumber');
logger.info(
{ config: upgrade },
`Error: Section [${depType}] doesn't exist in Cargo.toml file, update failed`
);
}
return fileContent;
}
let oldVersion;
const oldDep = section[depName];
if (!oldDep) {
logger.info(
{ config: upgrade },
`Could not get version of dependency ${depName}, update failed (most likely name is invalid)`
);
return fileContent;
}
oldVersion = section[depName];
// if (typeof oldVersion !== 'string') {
// if (oldVersion.version) {
// oldVersion = oldVersion.version;
// } else {
// oldVersion = null;
// }
// }
if (nestedVersion) {
oldVersion = oldVersion.version;
}
if (!oldVersion) {
logger.info(
{ config: upgrade },
`Could not get version of dependency ${depName}, update failed (most likely name is invalid)`
);
return fileContent;
}
if (oldVersion === newValue) {
logger.info('Version is already updated');
return fileContent;
}
if (nestedVersion) {
section[depName].version = newValue;
} else {
section[depName] = newValue;
}
if (target) {
parsedContent.target[target][depType] = section;
} else {
parsedContent[depType] = section;
}
const searchString = `"${oldVersion}"`;
const newString = `"${newValue}"`;
let newFileContent = fileContent;
let searchIndex = fileContent.indexOf(`${depName}`) + depName.length;
for (; searchIndex < fileContent.length; searchIndex += 1) {
// First check if we have a hit for the old version
if (matchAt(fileContent, searchIndex, searchString)) {
logger.trace(`Found match at index ${searchIndex}`);
// Now test if the result matches
const testContent = replaceAt(
fileContent,
searchIndex,
searchString,
newString
);
// Compare the parsed toml structure of old and new
if (_.isEqual(parsedContent, toml.parse(testContent))) {
newFileContent = testContent;
break;
} else {
logger.debug('Mismatched replace at searchIndex ' + searchIndex);
}
}
}
return lines.join('\n');
return newFileContent;
}

View file

@ -6,24 +6,24 @@ Array [
"currentValue": "=0.2.43",
"datasource": "cargo",
"depName": "libc",
"depType": "normal",
"lineNumber": 16,
"depType": "dependencies",
"nestedVersion": false,
"purl": "pkg:cargo/libc",
},
Object {
"currentValue": "1.0.4",
"datasource": "cargo",
"depName": "bitflags",
"depType": "normal",
"lineNumber": 17,
"depType": "dependencies",
"nestedVersion": false,
"purl": "pkg:cargo/bitflags",
},
Object {
"currentValue": "=0.1",
"datasource": "cargo",
"depName": "pcap-sys",
"depType": "inlineTable",
"lineNumber": 18,
"depType": "dependencies",
"nestedVersion": true,
"purl": "pkg:cargo/pcap-sys",
"skipReason": "path-dependency",
},
@ -31,27 +31,105 @@ Array [
"currentValue": "0.21.0",
"datasource": "cargo",
"depName": "pnet",
"depType": "inlineTable",
"lineNumber": 19,
"depType": "dependencies",
"nestedVersion": true,
"purl": "pkg:cargo/pnet",
},
Object {
"currentValue": "0.4.2",
"currentValue": "0.1.0",
"datasource": "cargo",
"depName": "winapi",
"depType": "standardTable",
"lineNumber": 21,
"purl": "pkg:cargo/winapi",
"versionLineNumber": 26,
"depName": "git_dep_with_version",
"depType": "dependencies",
"nestedVersion": true,
"purl": "pkg:cargo/git_dep_with_version",
"skipReason": "git-dependency",
},
Object {
"currentValue": "",
"datasource": "cargo",
"depName": "git_dep",
"depType": "dependencies",
"nestedVersion": false,
"purl": "pkg:cargo/git_dep",
"skipReason": "git-dependency",
},
Object {
"currentValue": "0.0.0",
"datasource": "cargo",
"depName": "same_version_1__",
"depType": "dependencies",
"nestedVersion": false,
"purl": "pkg:cargo/same_version_1__",
},
Object {
"currentValue": "0.0.0",
"datasource": "cargo",
"depName": "same_version_1_",
"depType": "dependencies",
"nestedVersion": false,
"purl": "pkg:cargo/same_version_1_",
},
Object {
"currentValue": "0.0.0",
"datasource": "cargo",
"depName": "same_version_1",
"depType": "dependencies",
"nestedVersion": false,
"purl": "pkg:cargo/same_version_1",
},
Object {
"currentValue": "0.4.2",
"datasource": "cargo",
"depName": "dep1",
"depType": "standardTable",
"lineNumber": 25,
"depType": "dependencies",
"nestedVersion": true,
"purl": "pkg:cargo/dep1",
"versionLineNumber": 26,
},
Object {
"currentValue": "=0.3.6",
"datasource": "cargo",
"depName": "winapi",
"depType": "dependencies",
"nestedVersion": true,
"purl": "pkg:cargo/winapi",
"target": "cfg(windows)",
},
Object {
"currentValue": "0.2.37",
"datasource": "cargo",
"depName": "wasm-bindgen",
"depType": "dependencies",
"nestedVersion": false,
"purl": "pkg:cargo/wasm-bindgen",
"target": "cfg(target_arch = \\"wasm32\\")",
},
Object {
"currentValue": "0.3.14",
"datasource": "cargo",
"depName": "js-sys",
"depType": "dependencies",
"nestedVersion": false,
"purl": "pkg:cargo/js-sys",
"target": "cfg(target_arch = \\"wasm32\\")",
},
Object {
"currentValue": "",
"datasource": "cargo",
"depName": "js_relative_import",
"depType": "dependencies",
"nestedVersion": false,
"purl": "pkg:cargo/js_relative_import",
"skipReason": "path-dependency",
"target": "cfg(target_arch = \\"wasm32\\")",
},
Object {
"currentValue": "0.3.14",
"datasource": "cargo",
"depName": "web-sys",
"depType": "dependencies",
"nestedVersion": true,
"purl": "pkg:cargo/web-sys",
"target": "cfg(target_arch = \\"wasm32\\")",
},
]
`;
@ -62,8 +140,8 @@ Array [
"currentValue": "0.2.0",
"datasource": "cargo",
"depName": "amethyst_animation",
"depType": "inlineTable",
"lineNumber": 53,
"depType": "dependencies",
"nestedVersion": true,
"purl": "pkg:cargo/amethyst_animation",
"skipReason": "path-dependency",
},
@ -71,8 +149,8 @@ Array [
"currentValue": "0.3.0",
"datasource": "cargo",
"depName": "amethyst_assets",
"depType": "inlineTable",
"lineNumber": 54,
"depType": "dependencies",
"nestedVersion": true,
"purl": "pkg:cargo/amethyst_assets",
"skipReason": "path-dependency",
},
@ -80,8 +158,8 @@ Array [
"currentValue": "0.2.0",
"datasource": "cargo",
"depName": "amethyst_audio",
"depType": "inlineTable",
"lineNumber": 55,
"depType": "dependencies",
"nestedVersion": true,
"purl": "pkg:cargo/amethyst_audio",
"skipReason": "path-dependency",
},
@ -89,8 +167,8 @@ Array [
"currentValue": "0.6.0",
"datasource": "cargo",
"depName": "amethyst_config",
"depType": "inlineTable",
"lineNumber": 56,
"depType": "dependencies",
"nestedVersion": true,
"purl": "pkg:cargo/amethyst_config",
"skipReason": "path-dependency",
},
@ -98,8 +176,8 @@ Array [
"currentValue": "0.2.0",
"datasource": "cargo",
"depName": "amethyst_core",
"depType": "inlineTable",
"lineNumber": 57,
"depType": "dependencies",
"nestedVersion": true,
"purl": "pkg:cargo/amethyst_core",
"skipReason": "path-dependency",
},
@ -107,8 +185,8 @@ Array [
"currentValue": "0.1.0",
"datasource": "cargo",
"depName": "amethyst_controls",
"depType": "inlineTable",
"lineNumber": 58,
"depType": "dependencies",
"nestedVersion": true,
"purl": "pkg:cargo/amethyst_controls",
"skipReason": "path-dependency",
},
@ -116,8 +194,8 @@ Array [
"currentValue": "0.1.0",
"datasource": "cargo",
"depName": "amethyst_locale",
"depType": "inlineTable",
"lineNumber": 59,
"depType": "dependencies",
"nestedVersion": true,
"purl": "pkg:cargo/amethyst_locale",
"skipReason": "path-dependency",
},
@ -125,8 +203,8 @@ Array [
"currentValue": "0.7",
"datasource": "cargo",
"depName": "amethyst_renderer",
"depType": "inlineTable",
"lineNumber": 60,
"depType": "dependencies",
"nestedVersion": true,
"purl": "pkg:cargo/amethyst_renderer",
"skipReason": "path-dependency",
},
@ -134,8 +212,8 @@ Array [
"currentValue": "0.3",
"datasource": "cargo",
"depName": "amethyst_input",
"depType": "inlineTable",
"lineNumber": 61,
"depType": "dependencies",
"nestedVersion": true,
"purl": "pkg:cargo/amethyst_input",
"skipReason": "path-dependency",
},
@ -143,8 +221,8 @@ Array [
"currentValue": "0.2",
"datasource": "cargo",
"depName": "amethyst_ui",
"depType": "inlineTable",
"lineNumber": 62,
"depType": "dependencies",
"nestedVersion": true,
"purl": "pkg:cargo/amethyst_ui",
"skipReason": "path-dependency",
},
@ -152,8 +230,8 @@ Array [
"currentValue": "0.2",
"datasource": "cargo",
"depName": "amethyst_utils",
"depType": "inlineTable",
"lineNumber": 63,
"depType": "dependencies",
"nestedVersion": true,
"purl": "pkg:cargo/amethyst_utils",
"skipReason": "path-dependency",
},
@ -161,64 +239,64 @@ Array [
"currentValue": "1.0",
"datasource": "cargo",
"depName": "derivative",
"depType": "normal",
"lineNumber": 64,
"depType": "dependencies",
"nestedVersion": false,
"purl": "pkg:cargo/derivative",
},
Object {
"currentValue": "0.5",
"datasource": "cargo",
"depName": "fern",
"depType": "inlineTable",
"lineNumber": 65,
"depType": "dependencies",
"nestedVersion": true,
"purl": "pkg:cargo/fern",
},
Object {
"currentValue": "0.4",
"datasource": "cargo",
"depName": "log",
"depType": "normal",
"lineNumber": 66,
"depType": "dependencies",
"nestedVersion": false,
"purl": "pkg:cargo/log",
},
Object {
"currentValue": "1.0.1",
"datasource": "cargo",
"depName": "rayon",
"depType": "normal",
"lineNumber": 67,
"depType": "dependencies",
"nestedVersion": false,
"purl": "pkg:cargo/rayon",
},
Object {
"currentValue": "0.1",
"datasource": "cargo",
"depName": "rustc_version_runtime",
"depType": "normal",
"lineNumber": 68,
"depType": "dependencies",
"nestedVersion": false,
"purl": "pkg:cargo/rustc_version_runtime",
},
Object {
"currentValue": "0.15",
"datasource": "cargo",
"depName": "winit",
"depType": "normal",
"lineNumber": 69,
"depType": "dependencies",
"nestedVersion": false,
"purl": "pkg:cargo/winit",
},
Object {
"currentValue": "0.1",
"datasource": "cargo",
"depName": "thread_profiler",
"depType": "inlineTable",
"lineNumber": 71,
"depType": "dependencies",
"nestedVersion": true,
"purl": "pkg:cargo/thread_profiler",
},
Object {
"currentValue": "0.2",
"datasource": "cargo",
"depName": "amethyst_gltf",
"depType": "inlineTable",
"lineNumber": 74,
"depType": "dev-dependencies",
"nestedVersion": true,
"purl": "pkg:cargo/amethyst_gltf",
"skipReason": "path-dependency",
},
@ -226,61 +304,103 @@ Array [
"currentValue": "0.5.10",
"datasource": "cargo",
"depName": "env_logger",
"depType": "normal",
"lineNumber": 75,
"depType": "dev-dependencies",
"nestedVersion": false,
"purl": "pkg:cargo/env_logger",
},
Object {
"currentValue": "0.6",
"datasource": "cargo",
"depName": "genmesh",
"depType": "normal",
"lineNumber": 76,
"depType": "dev-dependencies",
"nestedVersion": false,
"purl": "pkg:cargo/genmesh",
},
Object {
"currentValue": "0.2",
"datasource": "cargo",
"depName": "ron",
"depType": "normal",
"lineNumber": 77,
"depType": "dev-dependencies",
"nestedVersion": false,
"purl": "pkg:cargo/ron",
},
Object {
"currentValue": "1.0",
"datasource": "cargo",
"depName": "serde",
"depType": "normal",
"lineNumber": 78,
"depType": "dev-dependencies",
"nestedVersion": false,
"purl": "pkg:cargo/serde",
},
Object {
"currentValue": "1.0",
"datasource": "cargo",
"depName": "serde_derive",
"depType": "normal",
"lineNumber": 79,
"depType": "dev-dependencies",
"nestedVersion": false,
"purl": "pkg:cargo/serde_derive",
},
Object {
"currentValue": "0.1",
"datasource": "cargo",
"depName": "vergen",
"depType": "normal",
"lineNumber": 82,
"depType": "build-dependencies",
"nestedVersion": false,
"purl": "pkg:cargo/vergen",
},
]
`;
exports[`lib/manager/cargo/extract extractPackageFile() extracts platform specific dependencies 1`] = `
Array [
Object {
"currentValue": "0.2.37",
"datasource": "cargo",
"depName": "wasm-bindgen",
"depType": "dependencies",
"nestedVersion": false,
"purl": "pkg:cargo/wasm-bindgen",
"target": "cfg(target_arch = \\"wasm32\\")",
},
Object {
"currentValue": "0.3.14",
"datasource": "cargo",
"depName": "js-sys",
"depType": "dependencies",
"nestedVersion": false,
"purl": "pkg:cargo/js-sys",
"target": "cfg(target_arch = \\"wasm32\\")",
},
Object {
"currentValue": "",
"datasource": "cargo",
"depName": "js_relative_import",
"depType": "dependencies",
"nestedVersion": false,
"purl": "pkg:cargo/js_relative_import",
"skipReason": "path-dependency",
"target": "cfg(target_arch = \\"wasm32\\")",
},
Object {
"currentValue": "0.3.14",
"datasource": "cargo",
"depName": "web-sys",
"depType": "dependencies",
"nestedVersion": true,
"purl": "pkg:cargo/web-sys",
"target": "cfg(target_arch = \\"wasm32\\")",
},
]
`;
exports[`lib/manager/cargo/extract extractPackageFile() handles inline tables 1`] = `
Array [
Object {
"currentValue": "0.1",
"datasource": "cargo",
"depName": "pcap-sys",
"depType": "inlineTable",
"lineNumber": 5,
"depType": "dependencies",
"nestedVersion": true,
"purl": "pkg:cargo/pcap-sys",
"skipReason": "path-dependency",
},
@ -288,16 +408,16 @@ Array [
"currentValue": "0.21.0",
"datasource": "cargo",
"depName": "pnet",
"depType": "inlineTable",
"lineNumber": 6,
"depType": "dependencies",
"nestedVersion": true,
"purl": "pkg:cargo/pnet",
},
Object {
"currentValue": "1.2",
"datasource": "cargo",
"depName": "dep1",
"depType": "inlineTable",
"lineNumber": 7,
"depType": "dependencies",
"nestedVersion": true,
"purl": "pkg:cargo/dep1",
"skipReason": "path-dependency",
},
@ -305,8 +425,8 @@ Array [
"currentValue": "3.4",
"datasource": "cargo",
"depName": "dep2",
"depType": "inlineTable",
"lineNumber": 8,
"depType": "dependencies",
"nestedVersion": true,
"purl": "pkg:cargo/dep2",
"skipReason": "path-dependency",
},
@ -314,8 +434,8 @@ Array [
"currentValue": "~12.3.1",
"datasource": "cargo",
"depName": "dep3",
"depType": "inlineTable",
"lineNumber": 9,
"depType": "dependencies",
"nestedVersion": true,
"purl": "pkg:cargo/dep3",
"skipReason": "path-dependency",
},
@ -323,8 +443,8 @@ Array [
"currentValue": "INVALID 3.3.1 VERSION",
"datasource": "cargo",
"depName": "dep4",
"depType": "inlineTable",
"lineNumber": 10,
"depType": "dependencies",
"nestedVersion": true,
"purl": "pkg:cargo/dep4",
"skipReason": "unknown-version",
},
@ -332,61 +452,77 @@ Array [
"currentValue": "3.2.1",
"datasource": "cargo",
"depName": "dep5",
"depType": "inlineTable",
"lineNumber": 11,
"depType": "dependencies",
"nestedVersion": true,
"purl": "pkg:cargo/dep5",
},
Object {
"currentValue": "",
"datasource": "cargo",
"depName": "dep6",
"depType": "dependencies",
"nestedVersion": false,
"purl": "pkg:cargo/dep6",
"skipReason": "invalid-dependency-specification",
},
]
`;
exports[`lib/manager/cargo/extract extractPackageFile() handles standard tables 1`] = `
Array [
Object {
"currentValue": "INVALID 1.3.1 VERSION",
"currentValue": "1.2",
"datasource": "cargo",
"depName": "dep1",
"depType": "standardTable",
"lineNumber": 4,
"depType": "dependencies",
"nestedVersion": true,
"purl": "pkg:cargo/dep1",
"skipReason": "path-dependency",
"versionLineNumber": 24,
},
Object {
"currentValue": "INVALID 1.3.1 VERSION",
"currentValue": "3.4",
"datasource": "cargo",
"depName": "dep2",
"depType": "standardTable",
"lineNumber": 13,
"depType": "dependencies",
"nestedVersion": true,
"purl": "pkg:cargo/dep2",
"skipReason": "path-dependency",
"versionLineNumber": 24,
},
Object {
"currentValue": "INVALID 1.3.1 VERSION",
"currentValue": "~12.3.1",
"datasource": "cargo",
"depName": "dep3",
"depType": "standardTable",
"lineNumber": 18,
"depType": "dependencies",
"nestedVersion": true,
"purl": "pkg:cargo/dep3",
"skipReason": "path-dependency",
"versionLineNumber": 24,
},
Object {
"currentValue": "INVALID 1.3.1 VERSION",
"datasource": "cargo",
"depName": "dep4",
"depType": "standardTable",
"lineNumber": 23,
"depType": "dependencies",
"nestedVersion": true,
"purl": "pkg:cargo/dep4",
"skipReason": "path-dependency",
"versionLineNumber": 24,
},
Object {
"currentValue": "",
"datasource": "cargo",
"depName": "dep5",
"lineNumber": 28,
"depType": "dependencies",
"nestedVersion": false,
"purl": "pkg:cargo/dep5",
"skipReason": "path-dependency",
},
Object {
"currentValue": "",
"datasource": "cargo",
"depName": "dep7",
"depType": "dependencies",
"nestedVersion": false,
"purl": "pkg:cargo/dep7",
"skipReason": "invalid-dependency-specification",
},
]
`;

View file

@ -1,6 +1,6 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`lib/manager/cargo/update updateDependency() updates inline table dependency 1`] = `
exports[`lib/manager/cargo/update updateDependency() updates nested version dependency 1`] = `
"[package]
name = \\"rustcap\\"
version = \\"0.1.2\\"
@ -19,13 +19,33 @@ members = [\\"pcap-sys\\"]
[dependencies]
libc = \\"=0.2.43\\"
bitflags = \\"1.0.4\\"
pcap-sys = { version = \\"=0.1\\", path = \\"pcap-sys\\" }
pcap-sys = { version = \\"0.2.0\\", path = \\"pcap-sys\\" }
pnet = { version = \\"0.21.0\\", optional = true, default-features = false}
git_dep_with_version = { version = \\"0.1.0\\", git = \\"https://github.com/foo/bar\\" }
git_dep = { git = \\"https://github.com/foo/bar\\" }
same_version_1__ = \\"0.0.0\\"
same_version_1_ = \\"0.0.0\\"
same_version_1 = \\"0.0.0\\"
[target.'cfg(windows)'.dependencies.winapi]
version = \\"=0.3.6\\"
features = [\\"ws2def\\", \\"ws2ipdef\\"]
[target.'cfg(target_arch = \\"wasm32\\")'.dependencies]
wasm-bindgen = \\"0.2.37\\"
js-sys = \\"0.3.14\\"
js_relative_import = { path = \\"../../common/js_relative_import\\" }
[target.'cfg(target_arch = \\"wasm32\\")'.dependencies.web-sys]
version = \\"0.3.14\\"
features = [
\\"AudioBuffer\\",
\\"AudioBufferSourceNode\\",
\\"AudioContext\\",
\\"AudioDestinationNode\\",
\\"AudioNode\\",
]
[dependencies.dep1]
version = \\"0.4.2\\"
@ -61,11 +81,31 @@ libc = \\"0.3.0\\"
bitflags = \\"1.0.4\\"
pcap-sys = { version = \\"=0.1\\", path = \\"pcap-sys\\" }
pnet = { version = \\"0.21.0\\", optional = true, default-features = false}
git_dep_with_version = { version = \\"0.1.0\\", git = \\"https://github.com/foo/bar\\" }
git_dep = { git = \\"https://github.com/foo/bar\\" }
same_version_1__ = \\"0.0.0\\"
same_version_1_ = \\"0.0.0\\"
same_version_1 = \\"0.0.0\\"
[target.'cfg(windows)'.dependencies.winapi]
version = \\"=0.3.6\\"
features = [\\"ws2def\\", \\"ws2ipdef\\"]
[target.'cfg(target_arch = \\"wasm32\\")'.dependencies]
wasm-bindgen = \\"0.2.37\\"
js-sys = \\"0.3.14\\"
js_relative_import = { path = \\"../../common/js_relative_import\\" }
[target.'cfg(target_arch = \\"wasm32\\")'.dependencies.web-sys]
version = \\"0.3.14\\"
features = [
\\"AudioBuffer\\",
\\"AudioBufferSourceNode\\",
\\"AudioContext\\",
\\"AudioDestinationNode\\",
\\"AudioNode\\",
]
[dependencies.dep1]
version = \\"0.4.2\\"
@ -80,7 +120,7 @@ libpnet = [\\"pnet\\"]
# features = [\\"ws2def\\", \\"ws2ipdef\\"]"
`;
exports[`lib/manager/cargo/update updateDependency() updates standard table dependency 1`] = `
exports[`lib/manager/cargo/update updateDependency() updates normal dependency with mismatch on first try 1`] = `
"[package]
name = \\"rustcap\\"
version = \\"0.1.2\\"
@ -101,13 +141,93 @@ libc = \\"=0.2.43\\"
bitflags = \\"1.0.4\\"
pcap-sys = { version = \\"=0.1\\", path = \\"pcap-sys\\" }
pnet = { version = \\"0.21.0\\", optional = true, default-features = false}
git_dep_with_version = { version = \\"0.1.0\\", git = \\"https://github.com/foo/bar\\" }
git_dep = { git = \\"https://github.com/foo/bar\\" }
same_version_1__ = \\"0.0.0\\"
same_version_1_ = \\"0.0.0\\"
same_version_1 = \\"1.2.3\\"
[target.'cfg(windows)'.dependencies.winapi]
version = \\"=0.3.6\\"
features = [\\"ws2def\\", \\"ws2ipdef\\"]
[target.'cfg(target_arch = \\"wasm32\\")'.dependencies]
wasm-bindgen = \\"0.2.37\\"
js-sys = \\"0.3.14\\"
js_relative_import = { path = \\"../../common/js_relative_import\\" }
[target.'cfg(target_arch = \\"wasm32\\")'.dependencies.web-sys]
version = \\"0.3.14\\"
features = [
\\"AudioBuffer\\",
\\"AudioBufferSourceNode\\",
\\"AudioContext\\",
\\"AudioDestinationNode\\",
\\"AudioNode\\",
]
[dependencies.dep1]
version = \\"0.4.0\\"
version = \\"0.4.2\\"
[features]
libpnet = [\\"pnet\\"]
[dev-dependencies]
# libc = \\"0.1.1\\"
# pnet = { version = \\"0.19.0\\", optional = true, default-features = false}
# [target.'cfg(windows)'.dependencies.winapi]
# version = \\"0.3.0\\"
# features = [\\"ws2def\\", \\"ws2ipdef\\"]"
`;
exports[`lib/manager/cargo/update updateDependency() updates platform specific dependency 1`] = `
"[package]
name = \\"rustcap\\"
version = \\"0.1.2\\"
description = \\"Wrapper for libpcap\\"
homepage = \\"https://github.com/jmmk/rustcap\\"
repository = \\"https://github.com/jmmk/rustcap\\"
authors = [\\"Michael McLellan <jmikem825@gmail.com>\\"]
keywords = [\\"pcap\\", \\"libpcap\\"]
license = \\"MIT\\"
readme = \\"README.md\\"
documentation = \\"https://docs.rs/rustcap\\"
[workspace]
members = [\\"pcap-sys\\"]
[dependencies]
libc = \\"=0.2.43\\"
bitflags = \\"1.0.4\\"
pcap-sys = { version = \\"=0.1\\", path = \\"pcap-sys\\" }
pnet = { version = \\"0.21.0\\", optional = true, default-features = false}
git_dep_with_version = { version = \\"0.1.0\\", git = \\"https://github.com/foo/bar\\" }
git_dep = { git = \\"https://github.com/foo/bar\\" }
same_version_1__ = \\"0.0.0\\"
same_version_1_ = \\"0.0.0\\"
same_version_1 = \\"0.0.0\\"
[target.'cfg(windows)'.dependencies.winapi]
version = \\"0.4.0\\"
features = [\\"ws2def\\", \\"ws2ipdef\\"]
[target.'cfg(target_arch = \\"wasm32\\")'.dependencies]
wasm-bindgen = \\"0.2.37\\"
js-sys = \\"0.3.14\\"
js_relative_import = { path = \\"../../common/js_relative_import\\" }
[target.'cfg(target_arch = \\"wasm32\\")'.dependencies.web-sys]
version = \\"0.3.14\\"
features = [
\\"AudioBuffer\\",
\\"AudioBufferSourceNode\\",
\\"AudioContext\\",
\\"AudioDestinationNode\\",
\\"AudioNode\\",
]
[dependencies.dep1]
version = \\"0.4.2\\"
[features]
libpnet = [\\"pnet\\"]

View file

@ -18,11 +18,31 @@ libc = "=0.2.43"
bitflags = "1.0.4"
pcap-sys = { version = "=0.1", path = "pcap-sys" }
pnet = { version = "0.21.0", optional = true, default-features = false}
git_dep_with_version = { version = "0.1.0", git = "https://github.com/foo/bar" }
git_dep = { git = "https://github.com/foo/bar" }
same_version_1__ = "0.0.0"
same_version_1_ = "0.0.0"
same_version_1 = "0.0.0"
[target.'cfg(windows)'.dependencies.winapi]
version = "=0.3.6"
features = ["ws2def", "ws2ipdef"]
[target.'cfg(target_arch = "wasm32")'.dependencies]
wasm-bindgen = "0.2.37"
js-sys = "0.3.14"
js_relative_import = { path = "../../common/js_relative_import" }
[target.'cfg(target_arch = "wasm32")'.dependencies.web-sys]
version = "0.3.14"
features = [
"AudioBuffer",
"AudioBufferSourceNode",
"AudioContext",
"AudioDestinationNode",
"AudioNode",
]
[dependencies.dep1]
version = "0.4.2"

View file

@ -0,0 +1,19 @@
[package]
name = "platform-specific-dep-example"
version = "0.1.2"
# --- Web dependencies
[target.'cfg(target_arch = "wasm32")'.dependencies]
wasm-bindgen = "0.2.37"
js-sys = "0.3.14"
js_relative_import = { path = "../../common/js_relative_import" }
[target.'cfg(target_arch = "wasm32")'.dependencies.web-sys]
version = "0.3.14"
features = [
"AudioBuffer",
"AudioBufferSourceNode",
"AudioContext",
"AudioDestinationNode",
"AudioNode",
]

View file

@ -2,19 +2,23 @@ const fs = require('fs');
const { extractPackageFile } = require('../../../lib/manager/cargo/extract');
const cargo1toml = fs.readFileSync(
'test/datasource/cargo/_fixtures/Cargo.1.toml',
'test/manager/cargo/_fixtures/Cargo.1.toml',
'utf8'
);
const cargo2toml = fs.readFileSync(
'test/datasource/cargo/_fixtures/Cargo.2.toml',
'test/manager/cargo/_fixtures/Cargo.2.toml',
'utf8'
);
const cargo3toml = fs.readFileSync(
'test/datasource/cargo/_fixtures/Cargo.3.toml',
'test/manager/cargo/_fixtures/Cargo.3.toml',
'utf8'
);
const cargo4toml = fs.readFileSync(
'test/datasource/cargo/_fixtures/Cargo.4.toml',
'test/manager/cargo/_fixtures/Cargo.4.toml',
'utf8'
);
const cargo5toml = fs.readFileSync(
'test/manager/cargo/_fixtures/Cargo.5.toml',
'utf8'
);
@ -24,13 +28,25 @@ describe('lib/manager/cargo/extract', () => {
beforeEach(() => {
config = {};
});
it('returns null for invalid toml', () => {
expect(extractPackageFile('invalid toml', config)).toBeNull();
});
it('returns null for empty', () => {
expect(extractPackageFile('nothing here', config)).toBeNull();
const cargotoml = '[dependencies]\n';
expect(extractPackageFile(cargotoml, config)).toBeNull();
});
it('returns null for empty', () => {
const cargotoml = '[dev-dependencies]\n';
expect(extractPackageFile(cargotoml, config)).toBeNull();
});
it('returns null for empty', () => {
const cargotoml = '[target."foo".dependencies]\n';
expect(extractPackageFile(cargotoml, config)).toBeNull();
});
it('extracts multiple dependencies', () => {
const res = extractPackageFile(cargo1toml, config);
expect(res.deps).toMatchSnapshot();
expect(res.deps).toHaveLength(6);
expect(res.deps).toHaveLength(15);
});
it('extracts multiple dependencies', () => {
const res = extractPackageFile(cargo2toml, config);
@ -40,12 +56,17 @@ describe('lib/manager/cargo/extract', () => {
it('handles inline tables', () => {
const res = extractPackageFile(cargo3toml, config);
expect(res.deps).toMatchSnapshot();
expect(res.deps).toHaveLength(7);
expect(res.deps).toHaveLength(8);
});
it('handles standard tables', () => {
const res = extractPackageFile(cargo4toml, config);
expect(res.deps).toMatchSnapshot();
expect(res.deps).toHaveLength(5);
expect(res.deps).toHaveLength(6);
});
it('extracts platform specific dependencies', () => {
const res = extractPackageFile(cargo5toml, config);
expect(res.deps).toMatchSnapshot();
expect(res.deps).toHaveLength(4);
});
});
});

View file

@ -2,11 +2,15 @@ const fs = require('fs');
const { updateDependency } = require('../../../lib/manager/cargo/update');
const cargo1toml = fs.readFileSync(
'test/datasource/cargo/_fixtures/Cargo.1.toml',
'test/manager/cargo/_fixtures/Cargo.1.toml',
'utf8'
);
const cargo4toml = fs.readFileSync(
'test/datasource/cargo/_fixtures/Cargo.4.toml',
'test/manager/cargo/_fixtures/Cargo.4.toml',
'utf8'
);
const cargo5toml = fs.readFileSync(
'test/manager/cargo/_fixtures/Cargo.5.toml',
'utf8'
);
@ -16,43 +20,113 @@ describe('lib/manager/cargo/update', () => {
beforeEach(() => {
config = {};
});
it('returns same', () => {
expect(updateDependency('abc', config)).toEqual('abc');
it('returns same for invalid toml', () => {
const cargotoml = 'invalid toml !#$#';
expect(updateDependency(cargotoml, config)).toEqual(cargotoml);
});
it('returns same for null upgrade', () => {
const cargotoml = '[dependencies]\n';
expect(updateDependency(cargotoml, null)).toEqual(cargotoml);
});
it('returns same if version has not changed', () => {
const cargotoml = '[dependencies]\n';
expect(updateDependency(cargotoml, null)).toEqual(cargotoml);
const upgrade = {
depName: 'libc',
depType: 'dependencies',
nestedVersion: false,
newValue: '=0.2.43',
};
expect(updateDependency(cargo1toml, upgrade)).not.toBeNull();
expect(updateDependency(cargo1toml, upgrade)).toBe(cargo1toml);
});
it('returns same for invalid target', () => {
const cargotoml = '[dependencies]\n';
expect(updateDependency(cargotoml, null)).toEqual(cargotoml);
const upgrade = {
depName: 'platform-specific-dep',
depType: 'dependencies',
nestedVersion: false,
target: 'foobar',
newValue: '1.2.3',
};
expect(updateDependency(cargo1toml, upgrade)).not.toBeNull();
expect(updateDependency(cargo1toml, upgrade)).toBe(cargo1toml);
});
it('returns same for invalid depType', () => {
const cargotoml = '[dependencies]\n';
expect(updateDependency(cargotoml, null)).toEqual(cargotoml);
const upgrade = {
depName: 'libc',
depType: 'foobar',
nestedVersion: false,
newValue: '1.2.3',
};
expect(updateDependency(cargo1toml, upgrade)).not.toBeNull();
expect(updateDependency(cargo1toml, upgrade)).toBe(cargo1toml);
});
it('returns same for invalid depName', () => {
const cargotoml = '[dependencies]\n';
expect(updateDependency(cargotoml, null)).toEqual(cargotoml);
const upgrade = {
depName: 'does not exist',
depType: 'dependencies',
nestedVersion: false,
newValue: '1.2.3',
};
expect(updateDependency(cargo1toml, upgrade)).not.toBeNull();
expect(updateDependency(cargo1toml, upgrade)).toBe(cargo1toml);
});
it('updates normal dependency', () => {
const upgrade = {
depName: 'libc',
lineNumber: 16,
depType: 'normal',
depType: 'dependencies',
nestedVersion: false,
newValue: '0.3.0',
};
expect(updateDependency(cargo1toml, upgrade)).not.toBeNull();
expect(updateDependency(cargo1toml, upgrade)).not.toBe(cargo1toml);
expect(updateDependency(cargo1toml, upgrade)).toMatchSnapshot();
});
it('updates inline table dependency', () => {
it('updates normal dependency with mismatch on first try', () => {
const upgrade = {
depName: 'same_version_1',
depType: 'dependencies',
nestedVersion: false,
newValue: '1.2.3',
};
expect(updateDependency(cargo1toml, upgrade)).not.toBeNull();
expect(updateDependency(cargo1toml, upgrade)).not.toBe(cargo1toml);
expect(updateDependency(cargo1toml, upgrade)).toMatchSnapshot();
});
it('updates nested version dependency', () => {
const upgrade = {
depName: 'pcap-sys',
lineNumber: 18,
depType: 'inlineTable',
depType: 'dependencies',
nestedVersion: true,
newValue: '0.2.0',
};
expect(updateDependency(cargo1toml, upgrade)).not.toBeNull();
expect(updateDependency(cargo1toml, upgrade)).not.toBe(cargo1toml);
expect(updateDependency(cargo1toml, upgrade)).toMatchSnapshot();
});
it('updates standard table dependency', () => {
it('updates platform specific dependency', () => {
const upgrade = {
depName: 'winapi',
lineNumber: 21,
versionLineNumber: 22,
depType: 'standardTable',
target: 'cfg(windows)',
depType: 'dependencies',
nestedVersion: true,
newValue: '0.4.0',
};
expect(updateDependency(cargo1toml, upgrade)).not.toBeNull();
expect(updateDependency(cargo1toml, upgrade)).not.toBe(cargo1toml);
expect(updateDependency(cargo1toml, upgrade)).toMatchSnapshot();
});
it('handles invalid standard tables gracefully', () => {
const upgrade = {
depName: 'dep5',
lineNumber: 28,
versionLineNumber: 29,
depType: 'standardTable',
nestedVersion: true,
depType: 'dependencies',
newValue: '2.0.0',
};
expect(updateDependency(cargo4toml, upgrade)).toEqual(cargo4toml);
@ -60,21 +134,51 @@ describe('lib/manager/cargo/update', () => {
it('does not update in case of error', () => {
const upgrade = {
depName: 'libc',
lineNumber: 13, // Wrong lineNumber
depType: 'normal',
devType: 'dev-dependencies', // Wrong devType
nestedVersion: false,
newValue: '0.3.0',
};
expect(updateDependency(cargo1toml, upgrade)).toEqual(cargo1toml);
});
it('does not update commented out standard table dependencies', () => {
it('does not update in case of error', () => {
const upgrade = {
depName: 'dep6',
lineNumber: 33,
versionLineNumber: 34,
depType: 'standardTable',
newValue: '4.0.0',
depName: 'libc',
devType: 'dependencies',
nestedVersion: true, // Should be false
newValue: '0.3.0',
};
expect(updateDependency(cargo4toml, upgrade)).toEqual(cargo4toml);
expect(updateDependency(cargo1toml, upgrade)).toEqual(cargo1toml);
});
it('does not update in case of error', () => {
const upgrade = {
depName: 'pcap-sys',
devType: 'dependencies',
nestedVersion: false, // Should be true
newValue: '0.3.0',
};
expect(updateDependency(cargo1toml, upgrade)).toEqual(cargo1toml);
});
it('updates platform specific normal dependency', () => {
const upgrade = {
depName: 'wasm-bindgen',
depType: 'dependencies',
nestedVersion: false,
target: 'cfg(target_arch = "wasm32")',
newValue: '0.3.0',
};
expect(updateDependency(cargo5toml, upgrade)).not.toBeNull();
expect(updateDependency(cargo5toml, upgrade)).not.toBe(cargo5toml);
});
it('updates platform specific table dependency', () => {
const upgrade = {
depName: 'web-sys',
nestedVersion: true,
depType: 'dependencies',
target: 'cfg(target_arch = "wasm32")',
newValue: '0.4.0',
};
expect(updateDependency(cargo5toml, upgrade)).not.toBeNull();
expect(updateDependency(cargo5toml, upgrade)).not.toBe(cargo5toml);
});
});
});