Skip to content

Commit

Permalink
fix: Dependency tree (#2)
Browse files Browse the repository at this point in the history
* fix: Dependency graph restructured
  • Loading branch information
eavichay committed Nov 1, 2017
1 parent aaece7a commit bf43292
Show file tree
Hide file tree
Showing 9 changed files with 13,713 additions and 1,544 deletions.
2 changes: 1 addition & 1 deletion dev-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,6 @@ parser
console.log('Error parsing ' + targetFile);
process.exit(1);
}
console.log(JSON.stringify(result, null, 2));
console.log(JSON.stringify(result, '', 2));
process.exit(0);
});
35 changes: 15 additions & 20 deletions lib/dependency.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,30 +3,25 @@ function Dependency(name, version, targetFramework) {
this.version = version;
this.targetFramework = targetFramework;
this.dependencies = {};
this.path = '';
this.versionSpec = 'unknown';
}

Object.defineProperty(Dependency.prototype, 'resolvedName', {
get: function () {
return this.name + '.' + this.version;
},
})

/**
* @argument {Dependency} dep
*/
Dependency.prototype.addDependecy = function addDependecy(dep) {
this.flatDependencyMap[dep.name] =
this.flatDependencyMap[dep.name] ||
new Dependency(dep.name, dep.version, dep.targetFramework);
this.dependencies.push(dep);
Dependency.prototype.cloneShallow = function () {
// clone, without the dependencies
var result = new Dependency(this.name, this.version, this.targetFramework);
result.versionSpec = this.versionSpec;
return result;
};

/**
* @argument {string} name
*/
Dependency.prototype.hasDependency = function hasDependency(name) {
return this.flatDependencyMap[name] !== undefined;
Dependency.from = {
packgesConfigEntry: function (manifest) {
var result = new Dependency(
manifest.$.id,
manifest.$.version,
manifest.$.targetFramework);
result.versionSpec = manifest.$.version;
return result;
},
};

module.exports = Dependency;
111 changes: 68 additions & 43 deletions lib/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ var findFolder = require('./find-folder');
var path = require('path');
var parseNuspec = require('./nuspec-parser');

var dependencyTree = {};
var flattendPackageList = {};
var nuspecResolutions = {};

function isJSON(content) {
try {
Expand All @@ -24,19 +25,14 @@ module.exports = {
var fileContent = fs.readFileSync(targetFile).toString();
var contentAsJson = isJSON(fileContent);
var tree = {
plugin: {
name: 'NuGet',
targetFile: targetFile,
},
package: {
name: projectRootFolder,
version: null,
packageFormatVersion: 'Nuget:0.0.0',
dependencies: {},
},
from: null,
};
var chain = new Promise(function (resolve, reject) {
};
var chain = new Promise(function parseFileContents(resolve, reject) {
// Parse the file content

if (contentAsJson) {
// skip parsing from XML
return resolve(contentAsJson);
Expand All @@ -50,65 +46,94 @@ module.exports = {
}
})
}).then(function (rawXML) {
var list = [];
// collect installed packages and add to flat list
var installedPackages = [];
if (rawXML === contentAsJson) {
// start parsing JSON data
var rawDependencies = contentAsJson['dependencies'];
if (rawDependencies) {
for (var name in rawDependencies) {
// Array<{ "libraryName": "version" }>
var version = rawDependencies[name];
var newDependency = new Dependecy(name, version, null);
if (newDependency.resolvedName.indexOf('System.') !== 0) {
list.push(newDependency);
if (newDependency.name.indexOf('System.') !== 0) {
installedPackages.push(newDependency);
}
}
}
} else {
// start parsing XML data
rawXML.packages.package.forEach(function (node) {
var newDependency =
new Dependecy(node.$.id, node.$.version, node.$.targetFramework);
newDependency.path =
path.resolve(
projectRootFolder,
'packages',
newDependency.resolvedName);
if (newDependency.resolvedName.indexOf('System.') !== 0) {
list.push(newDependency);
if (node.$.id.indexOf('System.') !== 0) {
// include only non-system libraries
var installedDependency = Dependecy.from.packgesConfigEntry(node);
installedPackages.push(installedDependency);
}
});
}
list.forEach(function (entry) {
entry.path = path.resolve(
projectRootFolder,
'packages',
entry.resolvedName);
dependencyTree[entry.resolvedName] = entry;
installedPackages.forEach(function (entry) {
entry.path =
path.resolve(
projectRootFolder,
'packages',
entry.name + '.' + entry.version);
flattendPackageList[entry.name] = entry;
});
}).then(function () {
// initiate collecting information from .nuget files on installed packages
var nuspecParserChain = [];
for (var resolvedName in dependencyTree) {
var dep = dependencyTree[resolvedName];
for (var name in flattendPackageList) {
var dep = flattendPackageList[name];
nuspecParserChain.push(parseNuspec(dep));
}
return Promise.all(nuspecParserChain);
}).then(function (nuspecResolutionChain) {
nuspecResolutionChain.forEach(function (resolution) {
if (!resolution) return; // jscs:ignore
var node = dependencyTree[resolution.parent];
resolution.children.forEach(function (childNode) {
var dependency =
dependencyTree[childNode.resolvedName] ||
new Dependecy(
childNode.name,
childNode.version,
childNode.targetFramework);
node.dependencies[dependency.resolvedName] = dependency;
});
nuspecResolutions[resolution.name] = resolution;
});
for (var packageName in dependencyTree) {
if (packageName.indexOf('System.') !== 0) {
tree.package.dependencies[packageName] = dependencyTree[packageName];
}).then(function () {
// .nuget parsing is complete, returned as array of promise resolutions
// now the flat list should be rebuilt as a tree
function buildTree(node, requiredChildren, repository) {
requiredChildren.forEach(function (requiredChild) {
var transitiveDependency;
if (flattendPackageList[requiredChild.name]) {
// fetch from repo
transitiveDependency =
flattendPackageList[requiredChild.name].cloneShallow();
transitiveDependency.versionSpec =
requiredChild.versionSpec || transitiveDependency.versionSpec;
} else {
// create as new (uninstalled)
transitiveDependency = new Dependecy(
requiredChild.name,
requiredChild.version,
requiredChild.targetFramework);
transitiveDependency.versionSpec = requiredChild.version;
}
var transitiveChildren =
(nuspecResolutions[node.name] &&
nuspecResolutions[node.name].children) || [];
buildTree(transitiveDependency, transitiveChildren, repository);
node.dependencies[transitiveDependency.name] = transitiveDependency;
});
}

var _flatKeyCount = Object.keys(flattendPackageList).length;
var _nugtKeyCount = Object.keys(nuspecResolutions).length;
if (_nugtKeyCount >= _flatKeyCount) {
// local folders scanned, build list from .nuspec
for (var key in nuspecResolutions) {
var resolution = nuspecResolutions[key];
var node = flattendPackageList[resolution.name].cloneShallow();
buildTree(node, resolution.children, flattendPackageList);
tree.dependencies[node.name] = node;
}
} else {
tree.dependencies = flattendPackageList;
}

return tree;
})['catch'](function (err) {
throw(err);
Expand Down
23 changes: 13 additions & 10 deletions lib/nuspec-parser.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,11 @@ var safeBufferRead = require('./safe-buffer-read');
var parseXML = require('xml2js').parseString;
var Dependency = require('./dependency');

function parseNuspec(dependency) {
function parseNuspec(library) {
var P = new Promise(function (resolve, reject) {
var nuspecPath = path.resolve(
dependency.path,
dependency.resolvedName + '.nupkg');
library.path,
library.name + '.' + library.version + '.nupkg');
var rawZipped;

try {
Expand All @@ -29,24 +29,27 @@ function parseNuspec(dependency) {
if (err) {
reject(err);
} else {
var dependencies = [];
var ownDependencies = [];
(result.package.metadata || []).forEach(function (metadata) {
(metadata.dependencies || []).forEach(function (rawDependency) {
(rawDependency.group || []).forEach(function (group) {
(group.dependency || []).forEach(function (dep) {
dependencies.push(
new Dependency(dep.$.id, dep.$.version, group.$.targetFramework) // jscs:ignore
);
const transitiveDependency = new Dependency(dep.$.id, dep.$.version, group.$.targetFramework) // jscs:ignore
transitiveDependency.versionSpec = dep.$.versionSpec
ownDependencies.push(transitiveDependency);
})
});
(rawDependency.dependency || []).forEach(function (dep) {
dependencies.push(new Dependency(dep.$.id, dep.$.version, null));
const transitiveDependency =
new Dependency(dep.$.id, dep.$.version, null);
transitiveDependency.versionSpec = dep.$.version;
ownDependencies.push(transitiveDependency);
});
})
});
resolve({
parent: dependency.resolvedName,
children: dependencies.filter(function (dep) {
name: library.name,
children: ownDependencies.filter(function (dep) {
return dep.name.indexOf('System.') !== 0;
}),
});
Expand Down
35 changes: 0 additions & 35 deletions test/cleanPackagePathInformation.js

This file was deleted.

84 changes: 0 additions & 84 deletions test/parse-package.config.test.js

This file was deleted.

Loading

0 comments on commit bf43292

Please sign in to comment.