mirror of
https://github.com/bower/bower.git
synced 2026-02-12 15:05:05 -05:00
Some other tweaks to the API.
This commit is contained in:
@@ -17,24 +17,33 @@ var Manager = function (options) {
|
||||
this._repository = new PackageRepository(options);
|
||||
};
|
||||
|
||||
Manager.prototype.configure = function (unresolved, resolved) {
|
||||
// -----------------
|
||||
|
||||
Manager.prototype.configure = function (targets, installed) {
|
||||
// If working, error out
|
||||
if (this._working) {
|
||||
throw createError('Can\'t configure while working', 'EWORKING');
|
||||
}
|
||||
|
||||
// Store stuff
|
||||
this._targets = unresolved;
|
||||
this._targets = {};
|
||||
this._resolved = {};
|
||||
|
||||
mout.object.forOwn(resolved, function (decEndpoint) {
|
||||
// Only accept resolved endpoints with a name, dir and json properties
|
||||
if (!decEndpoint.name || !decEndpoint.dir || !decEndpoint.json) {
|
||||
throw createError('The properties "name", "dir" and "json" must be set when configuring resolved endpoints');
|
||||
}
|
||||
// Parse targets
|
||||
targets.forEach(function (decEndpoint) {
|
||||
this._targets[decEndpoint.name] = decEndpoint;
|
||||
}, this);
|
||||
|
||||
this._resolved[decEndpoint.name] = [decEndpoint];
|
||||
decEndpoint.initial = true; // Mark this endpoint
|
||||
// Parse installed
|
||||
mout.object.forOwn(installed, function (value, name) {
|
||||
// TODO: If value is a string, read package meta
|
||||
// If is not a string, than it's already the package meta
|
||||
this._resolved[name] = [{
|
||||
name: name,
|
||||
source: null,
|
||||
target: value.version || '*',
|
||||
pkgMeta: value,
|
||||
installed: true
|
||||
}];
|
||||
}, this);
|
||||
|
||||
return this;
|
||||
@@ -85,36 +94,33 @@ Manager.prototype.install = function () {
|
||||
.then(function () {
|
||||
var promises = [];
|
||||
|
||||
mout.object.forOwn(that._dissected, function (decEndpoint) {
|
||||
mout.object.forOwn(that._dissected, function (decEndpoint, name) {
|
||||
var promise;
|
||||
var dest;
|
||||
var release = decEndpoint.json._release;
|
||||
|
||||
// Do not copy if it was initially configured as resolved
|
||||
if (decEndpoint.initial) {
|
||||
return;
|
||||
}
|
||||
var release = decEndpoint.pkgMeta._release;
|
||||
|
||||
deferred.notify({
|
||||
type: 'action',
|
||||
data: 'Installing' + (release ? ' "' + release + '"' : ''),
|
||||
from: decEndpoint.name || decEndpoint.resolverName,
|
||||
origin: name,
|
||||
endpoint: decEndpoint
|
||||
});
|
||||
|
||||
dest = path.join(destDir, decEndpoint.name);
|
||||
|
||||
// Remove existent
|
||||
// Remove existent and copy canonical package
|
||||
dest = path.join(destDir, name);
|
||||
promise = Q.nfcall(rimraf, dest)
|
||||
// Copy dir
|
||||
.then(copy.copyDir.bind(copy, decEndpoint.dir, dest));
|
||||
|
||||
promises.push(promise);
|
||||
});
|
||||
|
||||
return Q.all(promises)
|
||||
.then(function () {
|
||||
return that._dissected;
|
||||
return Q.all(promises);
|
||||
})
|
||||
.then(function () {
|
||||
// Resolve with an object where keys are names and values
|
||||
// are the package metas
|
||||
return mout.object.map(this._dissected, function (decEndpoint) {
|
||||
return decEndpoint.pkgMeta;
|
||||
});
|
||||
})
|
||||
.then(deferred.resolve, deferred.reject, deferred.notify);
|
||||
@@ -126,48 +132,49 @@ Manager.prototype.install = function () {
|
||||
}.bind(this));
|
||||
};
|
||||
|
||||
Manager.prototype.areCompatible = function (source, subject) {
|
||||
var validSource = semver.valid(source.target) != null;
|
||||
var validSubject = semver.valid(subject.target) != null;
|
||||
var validRangeSource = semver.validRange(source.target) != null;
|
||||
var validRangeSubject = semver.validRange(subject.target) != null;
|
||||
|
||||
var highestSubject;
|
||||
var highestSource;
|
||||
Manager.prototype.areCompatible = function (first, second) {
|
||||
var validFirst = semver.valid(first) != null;
|
||||
var validSecond = semver.valid(second) != null;
|
||||
var validRangeFirst;
|
||||
var validRangeSecond;
|
||||
var highestSecond;
|
||||
var highestFirst;
|
||||
|
||||
// Version -> Version
|
||||
if (validSource && validSubject) {
|
||||
return semver.eq(source.target, subject.target);
|
||||
if (validFirst && validSecond) {
|
||||
return semver.eq(first, second);
|
||||
}
|
||||
|
||||
// Range -> Version
|
||||
if (validRangeSource && validSubject) {
|
||||
return semver.satisfies(subject.target, source.target);
|
||||
validRangeFirst = semver.validRange(first) != null;
|
||||
if (validRangeFirst && validSecond) {
|
||||
return semver.satisfies(second, first);
|
||||
}
|
||||
|
||||
// Version -> Range
|
||||
if (validSource && validRangeSubject) {
|
||||
return semver.satisfies(source.target, subject.target);
|
||||
validRangeSecond = semver.validRange(second) != null;
|
||||
if (validFirst && validRangeSecond) {
|
||||
return semver.satisfies(first, second);
|
||||
}
|
||||
|
||||
// Range -> Range
|
||||
if (validRangeSource && validRangeSubject) {
|
||||
if (validRangeFirst && validRangeSecond) {
|
||||
// Special case which both targets are *
|
||||
if (source.target === '*' && subject.target === '*') {
|
||||
if (first === '*' && second === '*') {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Grab the highest version possible for both
|
||||
highestSubject = this._findHighestVersion(semver.toComparators(subject.target));
|
||||
highestSource = this._findHighestVersion(semver.toComparators(source.target));
|
||||
highestSecond = this._findHighestVersion(semver.toComparators(second));
|
||||
highestFirst = this._findHighestVersion(semver.toComparators(first));
|
||||
|
||||
// Check if the highest resolvable version for the
|
||||
// subject is the same as the source one
|
||||
return semver.eq(highestSubject, highestSource);
|
||||
// second is the same as the first one
|
||||
return semver.eq(highestSecond, highestFirst);
|
||||
}
|
||||
|
||||
// Otherwise check if both targets are the same
|
||||
return source.target === subject.target;
|
||||
// As fallback, check if both are the equal
|
||||
return first === second;
|
||||
};
|
||||
|
||||
// -----------------
|
||||
@@ -187,10 +194,10 @@ Manager.prototype._fetch = function (decEndpoint) {
|
||||
// When done, call onFetch
|
||||
.spread(this._onFetch.bind(this, decEndpoint))
|
||||
// Listen to progress to proxy them to the resolve deferred
|
||||
// Note that we mark where the notification is coming from
|
||||
// Note that we also mark where the notification is coming from
|
||||
.progress(function (notification) {
|
||||
notification.endpoint = decEndpoint;
|
||||
notification.from = decEndpoint.name || decEndpoint.registryName || decEndpoint.resolverName;
|
||||
notification.origin = name || decEndpoint.registryName || decEndpoint.resolverName;
|
||||
this._deferred.notify(notification);
|
||||
}.bind(this));
|
||||
|
||||
@@ -198,7 +205,6 @@ Manager.prototype._fetch = function (decEndpoint) {
|
||||
};
|
||||
|
||||
Manager.prototype._onFetch = function (decEndpoint, canonicalPkg, pkgMeta) {
|
||||
var json;
|
||||
var name;
|
||||
var resolved;
|
||||
var index;
|
||||
@@ -208,10 +214,10 @@ Manager.prototype._onFetch = function (decEndpoint, canonicalPkg, pkgMeta) {
|
||||
mout.array.remove(this._fetching[initialName], decEndpoint);
|
||||
this._nrFetching--;
|
||||
|
||||
// Set the name, dir, json property in the decomposed endpoint
|
||||
decEndpoint.dir = canonicalPkg;
|
||||
// Store some needed stuff
|
||||
decEndpoint.name = name = decEndpoint.name || pkgMeta.name;
|
||||
decEndpoint.json = json = pkgMeta;
|
||||
decEndpoint.dir = canonicalPkg;
|
||||
decEndpoint.pkgMeta = pkgMeta;
|
||||
|
||||
// Add to the resolved list, marking it as resolved
|
||||
resolved = this._resolved[name] = this._resolved[name] || [];
|
||||
@@ -222,7 +228,7 @@ Manager.prototype._onFetch = function (decEndpoint, canonicalPkg, pkgMeta) {
|
||||
// we need to remove the initially resolved one that match the new name
|
||||
if (!initialName) {
|
||||
index = mout.array.findIndex(resolved, function (decEndpoint) {
|
||||
return decEndpoint.initial;
|
||||
return decEndpoint.installed;
|
||||
});
|
||||
|
||||
if (index !== -1) {
|
||||
@@ -231,7 +237,7 @@ Manager.prototype._onFetch = function (decEndpoint, canonicalPkg, pkgMeta) {
|
||||
}
|
||||
|
||||
// Parse dependencies
|
||||
this._parseDependencies(decEndpoint, json);
|
||||
this._parseDependencies(decEndpoint, pkgMeta);
|
||||
|
||||
// If the resolve process ended, parse the resolved packages
|
||||
// to find the most suitable version for each package
|
||||
@@ -240,25 +246,26 @@ Manager.prototype._onFetch = function (decEndpoint, canonicalPkg, pkgMeta) {
|
||||
}
|
||||
};
|
||||
|
||||
Manager.prototype._parseDependencies = function (decEndpoint, json) {
|
||||
Manager.prototype._parseDependencies = function (decEndpoint, pkgMeta) {
|
||||
// Parse package dependencies
|
||||
mout.object.forOwn(json.dependencies, function (value, key) {
|
||||
var decEndpoints;
|
||||
mout.object.forOwn(pkgMeta.dependencies, function (value, key) {
|
||||
var resolved;
|
||||
var beingFetched;
|
||||
var compatible;
|
||||
var childDecEndpoint = endpointParser.json2decomposed(key, value);
|
||||
|
||||
// Check if a compatible one is already resolved
|
||||
// If there's one, we don't need to resolve it twice
|
||||
decEndpoints = this._resolved[key];
|
||||
if (decEndpoints) {
|
||||
compatible = mout.array.find(decEndpoints, function (resolved) {
|
||||
return this.areCompatible(resolved, childDecEndpoint);
|
||||
resolved = this._resolved[key];
|
||||
if (resolved) {
|
||||
compatible = mout.array.find(resolved, function (resolved) {
|
||||
return this.areCompatible(resolved.target, childDecEndpoint.target);
|
||||
}, this);
|
||||
|
||||
// Simply mark it as resolved
|
||||
if (compatible) {
|
||||
childDecEndpoint.dir = compatible.dir;
|
||||
childDecEndpoint.json = compatible.json;
|
||||
childDecEndpoint.pkgMeta = compatible.pkgMeta;
|
||||
this._resolved[key].push(childDecEndpoint);
|
||||
return;
|
||||
}
|
||||
@@ -266,17 +273,17 @@ Manager.prototype._parseDependencies = function (decEndpoint, json) {
|
||||
|
||||
// Check if a compatible one is being fetched
|
||||
// If there's one, we reuse it to avoid resolving it twice
|
||||
decEndpoints = this._fetching[key];
|
||||
if (decEndpoints) {
|
||||
compatible = mout.array.find(decEndpoints, function (beingFetched) {
|
||||
return this.areCompatible(beingFetched, childDecEndpoint);
|
||||
beingFetched = this._fetching[key];
|
||||
if (beingFetched) {
|
||||
compatible = mout.array.find(beingFetched, function (beingFetched) {
|
||||
return this.areCompatible(beingFetched.target, childDecEndpoint.target);
|
||||
}, this);
|
||||
|
||||
// Wait for it to resolve and then add it to the resolved packages
|
||||
if (compatible) {
|
||||
childDecEndpoint = compatible.promise.then(function () {
|
||||
childDecEndpoint.dir = compatible.dir;
|
||||
childDecEndpoint.json = compatible.json;
|
||||
childDecEndpoint.pkgMeta = compatible.pkgMeta;
|
||||
this._resolved[key].push(childDecEndpoint);
|
||||
}.bind(this));
|
||||
|
||||
@@ -290,30 +297,31 @@ Manager.prototype._parseDependencies = function (decEndpoint, json) {
|
||||
};
|
||||
|
||||
Manager.prototype._dissect = function () {
|
||||
this._dissected = {};
|
||||
var pkgMetas;
|
||||
var dissected = {};
|
||||
|
||||
mout.object.forOwn(this._resolved, function (decEndpoints, name) {
|
||||
var configured = this._targets[name];
|
||||
var target = this._targets[name];
|
||||
var nonSemver;
|
||||
var validSemver;
|
||||
var suitable;
|
||||
|
||||
// If this was initially configured as a target without a valid semver target,
|
||||
// it means the user wants it regardless of other ones
|
||||
if (configured && configured.target && !semver.valid(configured.target)) {
|
||||
this._dissected[name] = this._targets[name];
|
||||
if (target && target.target && !semver.valid(target.target)) {
|
||||
dissected[name] = this._targets[name];
|
||||
// TODO: issue warning
|
||||
return;
|
||||
}
|
||||
|
||||
// Filter non-semver ones
|
||||
nonSemver = decEndpoints.filter(function (decEndpoint) {
|
||||
return !decEndpoint.json.version;
|
||||
return !decEndpoint.pkgMeta.version;
|
||||
});
|
||||
|
||||
// Filter semver ones
|
||||
validSemver = decEndpoints.filter(function (decEndpoint) {
|
||||
return !!decEndpoint.json.version;
|
||||
return !!decEndpoint.pkgMeta.version;
|
||||
});
|
||||
|
||||
// Sort semver ones
|
||||
@@ -324,7 +332,10 @@ Manager.prototype._dissect = function () {
|
||||
if (semver.lt(first, second)) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
|
||||
// If it gets here, they are equal but priority is given to
|
||||
// installed ones
|
||||
return first.installed ? -1 : (second.installed ? 1 : 0);
|
||||
});
|
||||
|
||||
// If there are no semver targets
|
||||
@@ -336,7 +347,7 @@ Manager.prototype._dissect = function () {
|
||||
// TODO: handle conflicts if there is no suitable version
|
||||
suitable = mout.array.find(validSemver, function (subject) {
|
||||
return validSemver.every(function (decEndpoint) {
|
||||
return semver.satisfies(subject.json.version, decEndpoint.target);
|
||||
return semver.satisfies(subject.pkgMeta.version, decEndpoint.target);
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -344,13 +355,22 @@ Manager.prototype._dissect = function () {
|
||||
// TODO: handle case which there is a suitable version but there are no-semver ones too
|
||||
|
||||
if (suitable) {
|
||||
this._dissected[name] = suitable;
|
||||
dissected[name] = suitable;
|
||||
} else {
|
||||
throw new Error('No suitable version for "' + name + '"');
|
||||
}
|
||||
}, this);
|
||||
|
||||
this._deferred.resolve(this._dissected);
|
||||
// Filter only packages that need to be installed
|
||||
this._dissected = mout.object.filter(dissected, function (decEndpoint) {
|
||||
return !decEndpoint.installed;
|
||||
});
|
||||
|
||||
// Resolve just with the package metas of the dissected object
|
||||
pkgMetas = mout.object.map(this._dissected, function (decEndpoint) {
|
||||
return decEndpoint.pkgMeta;
|
||||
});
|
||||
this._deferred.resolve(pkgMetas);
|
||||
};
|
||||
|
||||
Manager.prototype._findHighestVersion = function (comparators) {
|
||||
|
||||
@@ -15,7 +15,7 @@ var PackageRepository = function (options) {
|
||||
|
||||
// Instantiate the registry and store it in the options object
|
||||
// because it will be passed to the resolver factory
|
||||
this._options.registry = new RegistryClient(mout.object.fillIn({
|
||||
this._options.registryClient = new RegistryClient(mout.object.fillIn({
|
||||
cache: this._config.roaming.registry
|
||||
}, this._config));
|
||||
|
||||
|
||||
@@ -17,68 +17,75 @@ var Project = function (options) {
|
||||
this._manager = new Manager(options);
|
||||
};
|
||||
|
||||
Project.prototype.install = function (targets) {
|
||||
// -----------------
|
||||
|
||||
Project.prototype.install = function (endpoints) {
|
||||
var repairResult;
|
||||
var that = this;
|
||||
var repairDissected;
|
||||
|
||||
// If already working, error out
|
||||
if (this._working) {
|
||||
return Q.reject(createError('Already working', 'EWORKING'));
|
||||
}
|
||||
|
||||
// If no targets were specified, simply repair the project if necessary
|
||||
// If no endpoints were specified, simply repair the project
|
||||
// Note that we also repair incompatible packages
|
||||
if (!targets) {
|
||||
if (!endpoints) {
|
||||
return this._repair(true)
|
||||
.fin(function () {
|
||||
that._working = false;
|
||||
}.bind(this));
|
||||
});
|
||||
}
|
||||
|
||||
// Start by repairing the project, installing any missing packages
|
||||
// Start by repairing the project, installing only missing packages
|
||||
return this._repair()
|
||||
// Analyse the project
|
||||
.then(function (dissected) {
|
||||
repairDissected = dissected;
|
||||
.then(function (result) {
|
||||
repairResult = result;
|
||||
return that._analyse();
|
||||
})
|
||||
// Decide which dependencies should be fetched and the ones
|
||||
// that are already resolved
|
||||
.spread(function (json, tree, flattened) {
|
||||
var unresolved = {};
|
||||
var resolved = {};
|
||||
var targetNames = {};
|
||||
var targets = [];
|
||||
var installed = {};
|
||||
|
||||
// Mark targets as unresolved
|
||||
targets.forEach(function (target) {
|
||||
unresolved[target.name] = endpointParser.decompose(target);
|
||||
// Mark targets
|
||||
endpoints.forEach(function (target) {
|
||||
var decEndpoint = endpointParser.decompose(target);
|
||||
targetNames[decEndpoint.name] = true;
|
||||
targets.push(decEndpoint);
|
||||
});
|
||||
|
||||
// Mark every package from the tree as resolved
|
||||
// Mark every package from the tree as installed
|
||||
// if they are not a target or a non-shared descendant of a target
|
||||
// TODO: We should do traverse the tree (vertically) and
|
||||
// TODO: We should traverse the tree (deep first) and
|
||||
// add each leaf to the resolved
|
||||
// If a leaf is a target, we abort traversal of it
|
||||
resolved = mout.object.filter(flattened, function (decEndpoint, name) {
|
||||
return !unresolved[name];
|
||||
mout.object.forOwn(flattened, function (decEndpoint, name) {
|
||||
if (targetNames[name]) {
|
||||
return;
|
||||
}
|
||||
|
||||
installed[name] = decEndpoint.pkgMeta;
|
||||
});
|
||||
|
||||
// Configure the manager with the unresolved and resolved endpoints
|
||||
// And kick in the resolve process
|
||||
// Configure the manager and kick in the resolve process
|
||||
return that._manager
|
||||
.configure(unresolved, resolved)
|
||||
.configure(targets, installed)
|
||||
.resolve()
|
||||
// Install resolved ones
|
||||
.then(function () {
|
||||
return that._manager.install();
|
||||
})
|
||||
// Resolve with the repair and install dissection
|
||||
.then(function (dissected) {
|
||||
return mout.object.fillIn(dissected, repairDissected);
|
||||
// Resolve the promise with the repair and install results,
|
||||
// by merging them together
|
||||
.then(function (result) {
|
||||
return mout.object.fillIn(result, repairResult);
|
||||
});
|
||||
})
|
||||
.fin(function () {
|
||||
that._working = false;
|
||||
}.bind(this));
|
||||
});
|
||||
};
|
||||
|
||||
Project.prototype.update = function (names) {
|
||||
@@ -107,23 +114,22 @@ Project.prototype._analyse = function () {
|
||||
])
|
||||
.spread(function (json, installed) {
|
||||
var root;
|
||||
var flattened = installed;
|
||||
|
||||
root = {
|
||||
name: json.name,
|
||||
source: this._config.cwd,
|
||||
target: json.version || '*',
|
||||
json: json,
|
||||
dir: this._config.cwd
|
||||
pkgMeta: json
|
||||
};
|
||||
|
||||
// Restore the original dependencies cross-references,
|
||||
// that is, the parent-child relationships
|
||||
this._restoreNode(root, installed);
|
||||
this._restoreNode(root, flattened);
|
||||
// Do the same for the dev dependencies
|
||||
if (!this._options.production) {
|
||||
this._restoreNode(root, installed, 'devDependencies');
|
||||
this._restoreNode(root, flattened, 'devDependencies');
|
||||
}
|
||||
return [json, root, installed];
|
||||
|
||||
return [json, root, flattened];
|
||||
}.bind(this));
|
||||
};
|
||||
|
||||
@@ -132,21 +138,21 @@ Project.prototype._repair = function (incompatible) {
|
||||
|
||||
return this._analyse()
|
||||
.spread(function (json, tree, flattened) {
|
||||
var unresolved = {};
|
||||
var resolved = {};
|
||||
var targets = [];
|
||||
var installed = {};
|
||||
var isBroken = false;
|
||||
|
||||
// Figure out which are the missing/incompatible ones
|
||||
// by parsing the flattened tree
|
||||
mout.object.forOwn(flattened, function (decEndpoint, name) {
|
||||
if (decEndpoint.missing) {
|
||||
unresolved[name] = decEndpoint;
|
||||
targets.push(decEndpoint);
|
||||
isBroken = true;
|
||||
} else if (incompatible && decEndpoint.incompatible) {
|
||||
unresolved[name] = decEndpoint;
|
||||
targets.push(decEndpoint);
|
||||
isBroken = true;
|
||||
} else {
|
||||
resolved[name] = decEndpoint;
|
||||
installed[name] = decEndpoint.pkgMeta;
|
||||
}
|
||||
});
|
||||
|
||||
@@ -155,10 +161,9 @@ Project.prototype._repair = function (incompatible) {
|
||||
return {};
|
||||
}
|
||||
|
||||
// Configure the manager with the unresolved and resolved endpoints
|
||||
// And kick in the resolve process
|
||||
// Configure the manager and kick in the resolve process
|
||||
return that._manager
|
||||
.configure(unresolved, resolved)
|
||||
.configure(targets, installed)
|
||||
.resolve()
|
||||
// Install after resolve
|
||||
.then(function () {
|
||||
@@ -213,6 +218,7 @@ Project.prototype._readInstalled = function () {
|
||||
})
|
||||
.then(function (filenames) {
|
||||
var promises = [];
|
||||
var decEndpoints = {};
|
||||
|
||||
// Foreach bower.json found
|
||||
filenames.forEach(function (filename) {
|
||||
@@ -222,16 +228,11 @@ Project.prototype._readInstalled = function () {
|
||||
// Read package metadata
|
||||
promise = Q.nfcall(fs.readFile, path.join(componentsDir, filename))
|
||||
.then(function (contents) {
|
||||
var json = JSON.parse(contents.toString());
|
||||
var dir = path.join(componentsDir, name);
|
||||
var pkgMeta = JSON.parse(contents.toString());
|
||||
|
||||
// Set decomposed endpoint manually
|
||||
return {
|
||||
decEndpoints[name] = {
|
||||
name: name,
|
||||
source: dir,
|
||||
target: json.version || '*',
|
||||
json: json,
|
||||
dir: dir
|
||||
pkgMeta: pkgMeta
|
||||
};
|
||||
});
|
||||
|
||||
@@ -239,21 +240,15 @@ Project.prototype._readInstalled = function () {
|
||||
});
|
||||
|
||||
// Wait until all files have been read
|
||||
// to form the final object of decomposed endpoints
|
||||
// and resolve with the decomposed endpoints
|
||||
return Q.all(promises)
|
||||
.then(function (locals) {
|
||||
var decEndpoints = {};
|
||||
|
||||
locals.forEach(function (decEndpoint) {
|
||||
decEndpoints[decEndpoint.name] = decEndpoint;
|
||||
});
|
||||
|
||||
.then(function () {
|
||||
return decEndpoints;
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
Project.prototype._restoreNode = function (node, locals, jsonKey) {
|
||||
Project.prototype._restoreNode = function (node, flattened, jsonKey) {
|
||||
// Do not restore if already processed or if the node is
|
||||
// missing or incompatible
|
||||
if (node.dependencies || node.missing || node.incompatible) {
|
||||
@@ -261,20 +256,23 @@ Project.prototype._restoreNode = function (node, locals, jsonKey) {
|
||||
}
|
||||
|
||||
node.dependencies = {};
|
||||
node.dependants = {};
|
||||
|
||||
mout.object.forOwn(node.json[jsonKey || 'dependencies'], function (value, key) {
|
||||
var local = locals[key];
|
||||
mout.object.forOwn(node.pkgMeta[jsonKey || 'dependencies'], function (value, key) {
|
||||
var local = flattened[key];
|
||||
var json = endpointParser.json2decomposed(key, value);
|
||||
|
||||
// Check if the dependency is installed
|
||||
// Check if the dependency is not installed
|
||||
if (!local) {
|
||||
local = endpointParser.json2decomposed(key, value);
|
||||
local = json;
|
||||
local.missing = true;
|
||||
locals[key] = local;
|
||||
// If so, also check if it's compatible
|
||||
} else if (!this._manager.areCompatible(local, json)) {
|
||||
flattened[key] = local;
|
||||
// Even if it is installed, check if it's compatible
|
||||
} else if (!local.incompatible && !this._manager.areCompatible(local.pkgMeta.version || '*', json.target)) {
|
||||
json.pkgMeta = local.pkgMeta;
|
||||
local = json;
|
||||
local.incompatible = true;
|
||||
locals[key] = json;
|
||||
flattened[key] = local;
|
||||
}
|
||||
|
||||
// Cross reference
|
||||
@@ -283,7 +281,7 @@ Project.prototype._restoreNode = function (node, locals, jsonKey) {
|
||||
local.dependants[node.name] = node;
|
||||
|
||||
// Call restore for this dependency
|
||||
this._restoreNode(local, locals);
|
||||
this._restoreNode(local, flattened);
|
||||
}, this);
|
||||
};
|
||||
|
||||
|
||||
@@ -19,6 +19,8 @@ var ResolveCache = function (dir) {
|
||||
mkdirp.sync(dir);
|
||||
};
|
||||
|
||||
// -----------------
|
||||
|
||||
ResolveCache.prototype.retrieve = function (source, target) {
|
||||
var sourceId = this._getSourceId(source);
|
||||
var dir = path.join(this._dir, sourceId);
|
||||
@@ -158,6 +160,12 @@ ResolveCache.prototype._getVersions = function (source) {
|
||||
dir = path.join(this._dir, sourceId);
|
||||
return Q.nfcall(fs.readdir, dir)
|
||||
.then(function (versions) {
|
||||
// If there are no versions there, do not cache in memory
|
||||
if (!versions.length) {
|
||||
return versions;
|
||||
}
|
||||
|
||||
// Sort and cache in memory
|
||||
this._sortVersions(versions);
|
||||
return this._versions[sourceId] = versions;
|
||||
}.bind(this), function (err) {
|
||||
|
||||
@@ -87,7 +87,7 @@ function createResolver(decEndpoint, options) {
|
||||
})
|
||||
// As last resort, we try the registry
|
||||
.fail(function (err) {
|
||||
var registry = options.registry;
|
||||
var registry = options.registryClient;
|
||||
|
||||
if (!registry) {
|
||||
throw err;
|
||||
|
||||
Reference in New Issue
Block a user