Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/npm/cli.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorisaacs <i@izs.me>2010-08-03 10:50:15 +0400
committerisaacs <i@izs.me>2010-08-03 10:50:15 +0400
commitf9c9fcdc3b8ef845feddbcb9b41bb8ca8b025843 (patch)
tree89d019c36e967d57cc2e9aec41325dba2cc74f6e /lib
parentced7eb2bdcf4cb1d20bfdeccef9a2f92c6d1d371 (diff)
Add the update and update-dependents commands
Diffstat (limited to 'lib')
-rw-r--r--lib/update-dependents.js214
-rw-r--r--lib/update.js99
2 files changed, 313 insertions, 0 deletions
diff --git a/lib/update-dependents.js b/lib/update-dependents.js
new file mode 100644
index 000000000..095e240ab
--- /dev/null
+++ b/lib/update-dependents.js
@@ -0,0 +1,214 @@
+/*
+
+This command is plumbing.
+
+npm update-deps <pkg>
+
+For each other version of pkg, for each dependent in other
+version's dependents folder, if the new version would satisfy the
+dependency as well, update other version's dependent's dependency
+links to point at the new version
+
+If no dependents are left, then remove old version
+
+*/
+
+module.exports = updateDependents
+
+var readInstalled = require("./utils/read-installed")
+ , path = require("path")
+ , npm = require("../npm")
+ , chain = require("./utils/chain")
+ , semver = require("./utils/semver")
+ , link = require("./utils/link")
+ , linkIfExists = link.ifExists
+ , shim = require("./utils/write-shim")
+ , shimIfExists = shim.ifExists
+ , readJson = require("./utils/read-json")
+ , log = require("./utils/log")
+ , fs = require("fs")
+ , rm = require("./utils/rm-rf")
+
+function updateDependents (args, cb) {
+ // replace args with the installed data
+ if (!args.length) return cb() // nothing to do
+ readArgs(args, function (er, args) {
+ if (er) return log.er(cb, "Error reading args")(er)
+ // now this is an array of package descriptors
+ // and each one is installed, and has siblings.
+ // update any dependents on any other versions to this one,
+ // if it satisfies them, and then remove them if they have
+ // no more dependents
+ if (!args.length) return log(
+ "Nothing to update", "update dependents", cb)
+ chain(args.map(function (arg) {
+ return [updateDepsTo, arg]
+ }).concat(function (er) {
+ // now they've all been updated, so remove the others.
+ var rmList = []
+ args.forEach(function (arg) {
+ // if (!arg._others) log(arg); return
+ arg._others.forEach(function (o) {
+ rmList.push(arg.name+"@"+o)
+ })
+ })
+ npm.commands.rm(rmList, cb)
+ }))
+ })
+}
+
+// update the _others to this one.
+function updateDepsTo (arg, cb) {
+ chain(arg._others.map(function (o) {
+ return [updateOtherVersionDeps, o, arg]
+ }).concat(cb))
+}
+
+function updateOtherVersionDeps (other, pkg, cb) {
+ var depdir = path.join( npm.dir
+ , pkg.name
+ , other
+ , "dependents"
+ )
+ fs.readdir(depdir, function (er, deps) {
+ if (er) return log.er(cb,
+ "failed to read dependents on "+pkg.name+"@"+other)(er)
+ // for each of these, update the dependency on
+ // other to pkg
+ if (!deps.length) return cb()
+ chain(deps.map(function (d) {
+ // todo: make this a @ instead of a -
+ d = d.split("-")
+ var name = d.shift()
+ , ver = d.join("-")
+ return [updateDepToNew, name, ver, pkg, other]
+ }).concat(cb))
+ })
+}
+function updateDepToNew (depName, depVer, pkg, other, cb) {
+ var depdir = path.join(npm.dir, depName, depVer)
+ , jsonFile = path.join(depdir, "package", "package.json")
+ readJson(jsonFile, function (er, data) {
+ if (er) return log.er(cb, "failed to read "+jsonFile)(er)
+ // check if pkg is ok
+ var dependencies = data.dependencies
+ if (!dependencies) return log
+ ( "Weird, "+depName+"@"+depVer+" doesn't have any dependencies"
+ , "wtf?"
+ , cb
+ )
+ if (Array.isArray(dependencies)) {
+ var deps = {}
+ dependencies.forEach(function (d) { deps[d] = "*" })
+ dependencies = deps
+ }
+ var dependency = data.dependencies[pkg.name]
+ if (!dependency) return log
+ ( "Weird, "+depName+"@"+depVer+" doesn't depend on "+pkg.name
+ , "wtf?"
+ , cb
+ )
+ if (!semver.satisfies(pkg.version, dependency)) return log
+ ( pkg._id + " doesn't satisfy "+depName+"@"+depVer
+ , "not updating"
+ , cb
+ )
+
+ chain
+ ( [ removeDependencyLinks, data, pkg, other ]
+ , [ createDependencyLinks, data, pkg ]
+ , cb
+ )
+ })
+}
+
+function removeDependencyLinks (dep, pkg, other, cb) {
+ var depdir = path.join(npm.dir, dep.name, dep.version)
+ , depsOn = path.join(depdir, "dependson", pkg.name+"-"+other)
+ , deps = path.join(depdir, "dependencies", pkg.name)
+ , dependentLink = path.join( npm.dir
+ , pkg.name
+ , other
+ , "dependents"
+ , dep.name + "-" + dep.version
+ )
+ chain
+ ( [ rm, deps+".js" ]
+ , [ rm, deps ]
+ , [ rm, depsOn ]
+ , [ rm, dependentLink ]
+ , cb
+ )
+}
+function createDependencyLinks (dep, pkg, cb) {
+ var depdir = path.join(npm.dir, dep.name, dep.version)
+ , depsOn = path.join( depdir
+ , "dependson"
+ , pkg.name+"-"+pkg.version
+ )
+ , deps = path.join(depdir, "dependencies", pkg.name)
+ , targetRoot = path.join(npm.dir, pkg.name, pkg.version)
+ , targetMain = path.join(targetRoot, "main.js")
+ , targetLib = path.join(targetRoot, "lib")
+ , dependentLink = path.join( npm.dir
+ , pkg.name
+ , pkg.version
+ , "dependents"
+ , dep.name + "-" + dep.version
+ )
+ chain
+ ( [ link, targetRoot, depsOn ]
+ , [ link, depdir, dependentLink ]
+ , [ linkIfExists, targetLib, deps ]
+ , [ shimIfExists, targetMain, deps + ".js" ]
+ , cb
+ )
+}
+
+function readArgs (args, cb) {
+ var p = args.length
+ log(args, "readArgs before")
+ function r () { if (--p === 0) {
+ log(args, "readArgs after")
+ cb(null, args.filter(function (a) { return a }))
+ }}
+ function readOthers (arg, i) {
+ log(arg, "readOthers")
+ readInstalled([arg.name], function (er, inst) {
+ log(inst, "installed "+arg.name)
+ if (er) {
+ args[i] = null
+ return log(er, "Error reading installed", r)
+ }
+ var have = Object.keys(inst[arg.name])
+ if (have.length < 2) {
+ args[i] = null
+ return log(
+ "Only one version installed", "update-dependents "+arg.name, r)
+ }
+ arg._others = have.filter(function (v) { return v !== arg.version })
+ r()
+ })
+ }
+
+ args.forEach(function (arg, i) {
+ if (typeof arg === "object") return readOthers(arg, i)
+ arg = arg.split(/@/)
+ var name = arg.shift()
+ , ver = arg.join("@")
+ , jsonFile = path.join( npm.dir
+ , name
+ , ver
+ , "package"
+ , "package.json"
+ )
+ readJson(jsonFile, function (er, arg) {
+ if (er) {
+ args[i] = null
+ return log(er, "Error reading "+jsonFile, r)
+ }
+ args[i] = arg
+ readOthers(arg, i)
+ })
+ })
+}
diff --git a/lib/update.js b/lib/update.js
new file mode 100644
index 000000000..27d642afc
--- /dev/null
+++ b/lib/update.js
@@ -0,0 +1,99 @@
+/*
+http://github.com/isaacs/npm/issues/issue/7
+
+npm update [pkg]
+
+Does the following:
+
+1. check for a new version of pkg
+2. if not found, then quit
+3. install new version of pkg
+4. For each other version of pkg, for each dependent in
+ other version's dependents folder, if the new version
+ would satisfy the dependency as well, update other
+ version's dependent's dependency links to point at the
+ new version
+5. If no dependents are left, then remove old version
+
+If no packages are specified, then run for all installed
+packages.
+
+Depending on config value, auto-update, run steps 4-5
+after installation
+
+* always - Run an update after every install, so as to
+ minimize the different number of versions of things.
+* true - Default, run if newly installed version is
+ the highest version number (that is, don't downgrade
+ by default)
+* false - Don't run "update" automatically after
+ installation.
+
+*/
+
+module.exports = update
+
+var readInstalled = require("./utils/read-installed")
+ , chain = require("./utils/chain")
+ , log = require("./utils/log")
+ , registry = require("./utils/registry")
+ , npm = require("../npm")
+ , semver = require("./utils/semver")
+
+function update (args, cb) {
+ findUpdates(args, function (er, updates) {
+ if (er) return log.er(cb, "failed to find updates")(er)
+ if (!updates || Object.keys(updates).length === 0) return log(
+ "Nothing to update", "update", cb)
+ installUpdates(updates, cb)
+ })
+}
+function installUpdates (updates, cb) {
+ log(updates, "install updates")
+ npm.config.set("auto-update", true)
+ var installList = []
+ , updateList = []
+ Object.keys(updates).forEach(function (i) {
+ var u = updates[i]
+ if (u.have.indexOf(u.latest) === -1) {
+ installList.push(i+"@"+u.latest)
+ } else {
+ updateList.push(i+"@"+u.latest)
+ }
+ })
+ log(installList, "update installList")
+ log(updateList, "update updateList")
+ npm.commands.install(installList, function (er) {
+ if (er) return log.er(cb, "install failed "+installList)(er)
+ npm.commands["update-dependents"](updateList, function (er) {
+ if (er) return log.er(cb, "update failed "+updateList)(er)
+ cb()
+ })
+ })
+}
+
+function findUpdates (args, cb) {
+ log(args, "findUpdates")
+ readInstalled(args, function (er, inst) {
+ if (er) return log.er(cb, "Couldn't read installed packages")(er)
+ log(inst, "installed")
+ var pkgs = Object.keys(inst)
+ , p = pkgs.length
+ , updates = {}
+ , tag = npm.config.get("tag")
+ function found () { if (--p === 0) cb(null, updates) }
+ pkgs.forEach(function (pkg) {
+ registry.get(pkg, function (er, data) {
+ if (er) return log(pkg, "not in registry", found)
+ var latest = data["dist-tags"] && data["dist-tags"][tag]
+ , have = Object.keys(inst[pkg]).sort(semver.sort)
+ , minHave = have[0]
+ if (!latest || !semver.gt(latest, minHave)) return found()
+ // we have something that's out of date.
+ updates[pkg] = {latest:latest,have:have}
+ found()
+ })
+ })
+ })
+}
+