npm: upgrade to 1.1.39
authorisaacs <i@izs.me>
Thu, 12 Jul 2012 00:54:44 +0000 (17:54 -0700)
committerisaacs <i@izs.me>
Thu, 12 Jul 2012 00:54:53 +0000 (17:54 -0700)
Fix #3616

121 files changed:
deps/npm/doc/cli/list.md
deps/npm/html/api/bin.html
deps/npm/html/api/bugs.html
deps/npm/html/api/commands.html
deps/npm/html/api/config.html
deps/npm/html/api/deprecate.html
deps/npm/html/api/docs.html
deps/npm/html/api/edit.html
deps/npm/html/api/explore.html
deps/npm/html/api/help-search.html
deps/npm/html/api/init.html
deps/npm/html/api/install.html
deps/npm/html/api/link.html
deps/npm/html/api/load.html
deps/npm/html/api/ls.html
deps/npm/html/api/npm.html
deps/npm/html/api/outdated.html
deps/npm/html/api/owner.html
deps/npm/html/api/pack.html
deps/npm/html/api/prefix.html
deps/npm/html/api/prune.html
deps/npm/html/api/publish.html
deps/npm/html/api/rebuild.html
deps/npm/html/api/restart.html
deps/npm/html/api/root.html
deps/npm/html/api/run-script.html
deps/npm/html/api/search.html
deps/npm/html/api/shrinkwrap.html
deps/npm/html/api/start.html
deps/npm/html/api/stop.html
deps/npm/html/api/submodule.html
deps/npm/html/api/tag.html
deps/npm/html/api/test.html
deps/npm/html/api/uninstall.html
deps/npm/html/api/unpublish.html
deps/npm/html/api/update.html
deps/npm/html/api/version.html
deps/npm/html/api/view.html
deps/npm/html/api/whoami.html
deps/npm/html/doc/README.html
deps/npm/html/doc/adduser.html
deps/npm/html/doc/bin.html
deps/npm/html/doc/bugs.html
deps/npm/html/doc/build.html
deps/npm/html/doc/bundle.html
deps/npm/html/doc/cache.html
deps/npm/html/doc/changelog.html
deps/npm/html/doc/coding-style.html
deps/npm/html/doc/completion.html
deps/npm/html/doc/config.html
deps/npm/html/doc/deprecate.html
deps/npm/html/doc/developers.html
deps/npm/html/doc/disputes.html
deps/npm/html/doc/docs.html
deps/npm/html/doc/edit.html
deps/npm/html/doc/explore.html
deps/npm/html/doc/faq.html
deps/npm/html/doc/folders.html
deps/npm/html/doc/help-search.html
deps/npm/html/doc/help.html
deps/npm/html/doc/index.html
deps/npm/html/doc/init.html
deps/npm/html/doc/install.html
deps/npm/html/doc/json.html
deps/npm/html/doc/link.html
deps/npm/html/doc/list.html
deps/npm/html/doc/npm.html
deps/npm/html/doc/outdated.html
deps/npm/html/doc/owner.html
deps/npm/html/doc/pack.html
deps/npm/html/doc/prefix.html
deps/npm/html/doc/prune.html
deps/npm/html/doc/publish.html
deps/npm/html/doc/rebuild.html
deps/npm/html/doc/registry.html
deps/npm/html/doc/removing-npm.html
deps/npm/html/doc/restart.html
deps/npm/html/doc/root.html
deps/npm/html/doc/run-script.html
deps/npm/html/doc/scripts.html
deps/npm/html/doc/search.html
deps/npm/html/doc/semver.html
deps/npm/html/doc/shrinkwrap.html
deps/npm/html/doc/star.html
deps/npm/html/doc/start.html
deps/npm/html/doc/stop.html
deps/npm/html/doc/submodule.html
deps/npm/html/doc/tag.html
deps/npm/html/doc/test.html
deps/npm/html/doc/uninstall.html
deps/npm/html/doc/unpublish.html
deps/npm/html/doc/update.html
deps/npm/html/doc/version.html
deps/npm/html/doc/view.html
deps/npm/html/doc/whoami.html
deps/npm/lib/cache.js
deps/npm/lib/ls.js
deps/npm/lib/npm.js
deps/npm/lib/test.js
deps/npm/lib/utils/fetch.js
deps/npm/man/man1/list.1
deps/npm/man/man1/npm.1
deps/npm/man/man3/npm.3
deps/npm/node_modules/couch-login/README.md [new file with mode: 0644]
deps/npm/node_modules/couch-login/couch-login.js [new file with mode: 0644]
deps/npm/node_modules/couch-login/package.json [new file with mode: 0644]
deps/npm/node_modules/graceful-fs/graceful-fs.js
deps/npm/node_modules/graceful-fs/package.json
deps/npm/node_modules/node-gyp/bin/node-gyp.js
deps/npm/node_modules/node-gyp/lib/build.js
deps/npm/node_modules/node-gyp/lib/configure.js
deps/npm/node_modules/node-gyp/lib/install.js
deps/npm/node_modules/node-gyp/lib/node-gyp.js
deps/npm/node_modules/node-gyp/package.json
deps/npm/node_modules/npm-registry-client/index.js
deps/npm/node_modules/npm-registry-client/lib/get.js
deps/npm/node_modules/npm-registry-client/lib/request.js
deps/npm/node_modules/npm-registry-client/package.json
deps/npm/node_modules/read-package-json/package.json
deps/npm/node_modules/read-package-json/read-json.js
deps/npm/package.json

index 93d86cd..3dd709b 100644 (file)
@@ -3,20 +3,26 @@ npm-ls(1) -- List installed packages
 
 ## SYNOPSIS
 
-    npm list
-    npm ls
-    npm la
-    npm ll
+    npm list [<pkg> ...]
+    npm ls [<pkg> ...]
+    npm la [<pkg> ...]
+    npm ll [<pkg> ...]
 
 ## DESCRIPTION
 
 This command will print to stdout all the versions of packages that are
 installed, as well as their dependencies, in a tree-structure.
 
-It does not take positional arguments, though you may set config flags
-like with any other command, such as `-g` to list global packages.
+Positional arguments are `name@version-range` identifiers, which will
+limit the results to only the paths to the packages named.  Note that
+nested packages will *also* show the paths to the specified packages.
+For example, running `npm ls promzard` in npm's source tree will show:
 
-It will print out extraneous, missing, and invalid packages.
+    npm@@VERSION@ /path/to/npm
+    â””─┬ init-package-json@0.0.4
+      â””── promzard@0.1.5
+
+It will show print out extraneous, missing, and invalid packages.
 
 When run as `ll` or `la`, it shows extended information by default.
 
index 9071e79..1582117 100644 (file)
@@ -19,7 +19,7 @@
 <p>This function should not be used programmatically.  Instead, just refer
 to the <code>npm.bin</code> member.</p>
 </div>
-<p id="footer">bin &mdash; npm@1.1.36</p>
+<p id="footer">bin &mdash; npm@1.1.39</p>
 <script>
 ;(function () {
 var wrapper = document.getElementById("wrapper")
index 9e658db..b51d61d 100644 (file)
@@ -25,7 +25,7 @@ optional version number.</p>
 <p>This command will launch a browser, so this command may not be the most
 friendly for programmatic use.</p>
 </div>
-<p id="footer">bugs &mdash; npm@1.1.36</p>
+<p id="footer">bugs &mdash; npm@1.1.39</p>
 <script>
 ;(function () {
 var wrapper = document.getElementById("wrapper")
index 61cdac2..15b5961 100644 (file)
@@ -28,7 +28,7 @@ usage, or <code>man 3 npm-&lt;command&gt;</code> for programmatic usage.</p>
 
 <ul><li><a href="../doc/index.html">index(1)</a></li></ul>
 </div>
-<p id="footer">commands &mdash; npm@1.1.36</p>
+<p id="footer">commands &mdash; npm@1.1.39</p>
 <script>
 ;(function () {
 var wrapper = document.getElementById("wrapper")
index 7977282..712f290 100644 (file)
@@ -33,7 +33,7 @@ functions instead.</p>
 
 <ul><li><a href="../api/npm.html">npm(3)</a></li></ul>
 </div>
-<p id="footer">config &mdash; npm@1.1.36</p>
+<p id="footer">config &mdash; npm@1.1.39</p>
 <script>
 ;(function () {
 var wrapper = document.getElementById("wrapper")
index 727aa43..4f4f02f 100644 (file)
@@ -30,7 +30,7 @@ install the package.</p></li></ul>
 
 <ul><li><a href="../api/publish.html">publish(3)</a></li><li><a href="../api/unpublish.html">unpublish(3)</a></li><li><a href="../doc/registry.html">registry(1)</a></li></ul>
 </div>
-<p id="footer">deprecate &mdash; npm@1.1.36</p>
+<p id="footer">deprecate &mdash; npm@1.1.39</p>
 <script>
 ;(function () {
 var wrapper = document.getElementById("wrapper")
index 7c22c55..e1a59d9 100644 (file)
@@ -25,7 +25,7 @@ optional version number.</p>
 <p>This command will launch a browser, so this command may not be the most
 friendly for programmatic use.</p>
 </div>
-<p id="footer">docs &mdash; npm@1.1.36</p>
+<p id="footer">docs &mdash; npm@1.1.39</p>
 <script>
 ;(function () {
 var wrapper = document.getElementById("wrapper")
index ce5e41a..33ea95c 100644 (file)
@@ -30,7 +30,7 @@ to open. The package can optionally have a version number attached.</p>
 <p>Since this command opens an editor in a new process, be careful about where
 and how this is used.</p>
 </div>
-<p id="footer">edit &mdash; npm@1.1.36</p>
+<p id="footer">edit &mdash; npm@1.1.39</p>
 <script>
 ;(function () {
 var wrapper = document.getElementById("wrapper")
index cda6d48..0761a82 100644 (file)
@@ -24,7 +24,7 @@ sure to use <code>npm rebuild &lt;pkg&gt;</code> if you make any changes.</p>
 
 <p>The first element in the 'args' parameter must be a package name.  After that is the optional command, which can be any number of strings. All of the strings will be combined into one, space-delimited command.</p>
 </div>
-<p id="footer">explore &mdash; npm@1.1.36</p>
+<p id="footer">explore &mdash; npm@1.1.39</p>
 <script>
 ;(function () {
 var wrapper = document.getElementById("wrapper")
index fb8ff2c..8b57f48 100644 (file)
@@ -32,7 +32,7 @@ Name of the file that matched</li></ul>
 
 <p>The silent parameter is not neccessary not used, but it may in the future.</p>
 </div>
-<p id="footer">help-search &mdash; npm@1.1.36</p>
+<p id="footer">help-search &mdash; npm@1.1.39</p>
 <script>
 ;(function () {
 var wrapper = document.getElementById("wrapper")
index 7f19cc1..6acf5c2 100644 (file)
@@ -35,7 +35,7 @@ then go ahead and use this programmatically.</p>
 
 <p><a href="../doc/json.html">json(1)</a></p>
 </div>
-<p id="footer">init &mdash; npm@1.1.36</p>
+<p id="footer">init &mdash; npm@1.1.39</p>
 <script>
 ;(function () {
 var wrapper = document.getElementById("wrapper")
index bb3302d..f364118 100644 (file)
@@ -25,7 +25,7 @@ the name of a package to be installed.</p>
 <p>Finally, 'callback' is a function that will be called when all packages have been
 installed or when an error has been encountered.</p>
 </div>
-<p id="footer">install &mdash; npm@1.1.36</p>
+<p id="footer">install &mdash; npm@1.1.39</p>
 <script>
 ;(function () {
 var wrapper = document.getElementById("wrapper")
index 1afd31e..507296e 100644 (file)
@@ -39,7 +39,7 @@ npm.commands.link('redis', cb)  # link-install the package</code></pre>
 <p>Now, any changes to the redis package will be reflected in
 the package in the current working directory</p>
 </div>
-<p id="footer">link &mdash; npm@1.1.36</p>
+<p id="footer">link &mdash; npm@1.1.39</p>
 <script>
 ;(function () {
 var wrapper = document.getElementById("wrapper")
index 71df640..b710405 100644 (file)
@@ -32,7 +32,7 @@ config object.</p>
 
 <p>For a list of all the available command-line configs, see <code>npm help config</code></p>
 </div>
-<p id="footer">load &mdash; npm@1.1.36</p>
+<p id="footer">load &mdash; npm@1.1.39</p>
 <script>
 ;(function () {
 var wrapper = document.getElementById("wrapper")
index f067240..a54639d 100644 (file)
@@ -59,7 +59,7 @@ project.</p>
 This means that if a submodule a same dependency as a parent module, then the
 dependency will only be output once.</p>
 </div>
-<p id="footer">ls &mdash; npm@1.1.36</p>
+<p id="footer">ls &mdash; npm@1.1.39</p>
 <script>
 ;(function () {
 var wrapper = document.getElementById("wrapper")
index a9cf167..110ad0d 100644 (file)
@@ -24,7 +24,7 @@ npm.load(configObject, function (er, npm) {
 
 <h2 id="VERSION">VERSION</h2>
 
-<p>1.1.36</p>
+<p>1.1.39</p>
 
 <h2 id="DESCRIPTION">DESCRIPTION</h2>
 
@@ -91,7 +91,7 @@ method names.  Use the <code>npm.deref</code> method to find the real name.</p>
 
 <pre><code>var cmd = npm.deref("unp") // cmd === "unpublish"</code></pre>
 </div>
-<p id="footer">npm &mdash; npm@1.1.36</p>
+<p id="footer">npm &mdash; npm@1.1.39</p>
 <script>
 ;(function () {
 var wrapper = document.getElementById("wrapper")
index 4e8dae3..2ee552b 100644 (file)
@@ -19,7 +19,7 @@ currently outdated.</p>
 
 <p>If the 'packages' parameter is left out, npm will check all packages.</p>
 </div>
-<p id="footer">outdated &mdash; npm@1.1.36</p>
+<p id="footer">outdated &mdash; npm@1.1.39</p>
 <script>
 ;(function () {
 var wrapper = document.getElementById("wrapper")
index d40b0f7..2025d49 100644 (file)
@@ -34,7 +34,7 @@ that is not implemented at this time.</p>
 
 <ul><li><a href="../api/publish.html">publish(3)</a></li><li><a href="../doc/registry.html">registry(1)</a></li></ul>
 </div>
-<p id="footer">owner &mdash; npm@1.1.36</p>
+<p id="footer">owner &mdash; npm@1.1.39</p>
 <script>
 ;(function () {
 var wrapper = document.getElementById("wrapper")
index 0fcc3b5..db67feb 100644 (file)
@@ -25,7 +25,7 @@ overwritten the second time.</p>
 
 <p>If no arguments are supplied, then npm packs the current package folder.</p>
 </div>
-<p id="footer">pack &mdash; npm@1.1.36</p>
+<p id="footer">pack &mdash; npm@1.1.39</p>
 <script>
 ;(function () {
 var wrapper = document.getElementById("wrapper")
index b7ad956..d18c608 100644 (file)
@@ -21,7 +21,7 @@
 
 <p>This function is not useful programmatically</p>
 </div>
-<p id="footer">prefix &mdash; npm@1.1.36</p>
+<p id="footer">prefix &mdash; npm@1.1.39</p>
 <script>
 ;(function () {
 var wrapper = document.getElementById("wrapper")
index 1aad29b..d57d8fe 100644 (file)
@@ -23,7 +23,7 @@
 <p>Extraneous packages are packages that are not listed on the parent
 package's dependencies list.</p>
 </div>
-<p id="footer">prune &mdash; npm@1.1.36</p>
+<p id="footer">prune &mdash; npm@1.1.39</p>
 <script>
 ;(function () {
 var wrapper = document.getElementById("wrapper")
index a425f37..9d2decf 100644 (file)
@@ -32,7 +32,7 @@ the registry.  Overwrites when the "force" environment variable is set.</p>
 
 <ul><li><a href="../doc/registry.html">registry(1)</a></li><li><a href="../doc/adduser.html">adduser(1)</a></li><li><a href="../api/owner.html">owner(3)</a></li></ul>
 </div>
-<p id="footer">publish &mdash; npm@1.1.36</p>
+<p id="footer">publish &mdash; npm@1.1.39</p>
 <script>
 ;(function () {
 var wrapper = document.getElementById("wrapper")
index cc86371..063db44 100644 (file)
@@ -22,7 +22,7 @@ the new binary. If no 'packages' parameter is specify, every package will be reb
 
 <p>See <code>npm help build</code></p>
 </div>
-<p id="footer">rebuild &mdash; npm@1.1.36</p>
+<p id="footer">rebuild &mdash; npm@1.1.39</p>
 <script>
 ;(function () {
 var wrapper = document.getElementById("wrapper")
index 172db36..7152326 100644 (file)
@@ -27,7 +27,7 @@ in the <code>packages</code> parameter.</p>
 
 <ul><li><a href="../api/start.html">start(3)</a></li><li><a href="../api/stop.html">stop(3)</a></li></ul>
 </div>
-<p id="footer">restart &mdash; npm@1.1.36</p>
+<p id="footer">restart &mdash; npm@1.1.39</p>
 <script>
 ;(function () {
 var wrapper = document.getElementById("wrapper")
index 7437950..6a5d37a 100644 (file)
@@ -21,7 +21,7 @@
 
 <p>This function is not useful programmatically.</p>
 </div>
-<p id="footer">root &mdash; npm@1.1.36</p>
+<p id="footer">root &mdash; npm@1.1.39</p>
 <script>
 ;(function () {
 var wrapper = document.getElementById("wrapper")
index 34cb7ca..9beae53 100644 (file)
@@ -29,7 +29,7 @@ assumed to be the command to run. All other elements are ignored.</p>
 
 <ul><li><a href="../doc/scripts.html">scripts(1)</a></li><li><a href="../api/test.html">test(3)</a></li><li><a href="../api/start.html">start(3)</a></li><li><a href="../api/restart.html">restart(3)</a></li><li><a href="../api/stop.html">stop(3)</a></li></ul>
 </div>
-<p id="footer">run-script &mdash; npm@1.1.36</p>
+<p id="footer">run-script &mdash; npm@1.1.39</p>
 <script>
 ;(function () {
 var wrapper = document.getElementById("wrapper")
index 6acf530..b86bbb4 100644 (file)
@@ -32,7 +32,7 @@ excluded term (the "searchexclude" config). The search is case insensitive
 and doesn't try to read your mind (it doesn't do any verb tense matching or the
 like).</p>
 </div>
-<p id="footer">search &mdash; npm@1.1.36</p>
+<p id="footer">search &mdash; npm@1.1.39</p>
 <script>
 ;(function () {
 var wrapper = document.getElementById("wrapper")
index 69fd1bd..26d8cbb 100644 (file)
@@ -26,7 +26,7 @@ but the shrinkwrap file will still be written.</p>
 <p>Finally, 'callback' is a function that will be called when the shrinkwrap has
 been saved.</p>
 </div>
-<p id="footer">shrinkwrap &mdash; npm@1.1.36</p>
+<p id="footer">shrinkwrap &mdash; npm@1.1.39</p>
 <script>
 ;(function () {
 var wrapper = document.getElementById("wrapper")
index 94a43b8..cd9142c 100644 (file)
@@ -19,7 +19,7 @@
 <p>npm can run tests on multiple packages. Just specify multiple packages
 in the <code>packages</code> parameter.</p>
 </div>
-<p id="footer">start &mdash; npm@1.1.36</p>
+<p id="footer">start &mdash; npm@1.1.39</p>
 <script>
 ;(function () {
 var wrapper = document.getElementById("wrapper")
index 8d5ab88..38baa07 100644 (file)
@@ -19,7 +19,7 @@
 <p>npm can run stop on multiple packages. Just specify multiple packages
 in the <code>packages</code> parameter.</p>
 </div>
-<p id="footer">stop &mdash; npm@1.1.36</p>
+<p id="footer">stop &mdash; npm@1.1.39</p>
 <script>
 ;(function () {
 var wrapper = document.getElementById("wrapper")
index 109abda..af4b184 100644 (file)
@@ -33,7 +33,7 @@ dependencies into the submodule folder.</p>
 
 <ul><li>npm help json</li><li>git help submodule</li></ul>
 </div>
-<p id="footer">submodule &mdash; npm@1.1.36</p>
+<p id="footer">submodule &mdash; npm@1.1.39</p>
 <script>
 ;(function () {
 var wrapper = document.getElementById("wrapper")
index 7c349c9..01d5c78 100644 (file)
@@ -29,7 +29,7 @@ parameter is missing or falsey (empty), the default froom the config will be
 used. For more information about how to set this config, check
 <code>man 3 npm-config</code> for programmatic usage or <code>man npm-config</code> for cli usage.</p>
 </div>
-<p id="footer">tag &mdash; npm@1.1.36</p>
+<p id="footer">tag &mdash; npm@1.1.39</p>
 <script>
 ;(function () {
 var wrapper = document.getElementById("wrapper")
index 8cdd763..0021cca 100644 (file)
@@ -22,7 +22,7 @@ true.</p>
 <p>npm can run tests on multiple packages. Just specify multiple packages
 in the <code>packages</code> parameter.</p>
 </div>
-<p id="footer">test &mdash; npm@1.1.36</p>
+<p id="footer">test &mdash; npm@1.1.39</p>
 <script>
 ;(function () {
 var wrapper = document.getElementById("wrapper")
index f372bf6..8db52ed 100644 (file)
@@ -22,7 +22,7 @@ the name of a package to be uninstalled.</p>
 <p>Finally, 'callback' is a function that will be called when all packages have been
 uninstalled or when an error has been encountered.</p>
 </div>
-<p id="footer">uninstall &mdash; npm@1.1.36</p>
+<p id="footer">uninstall &mdash; npm@1.1.39</p>
 <script>
 ;(function () {
 var wrapper = document.getElementById("wrapper")
index 860c1c5..1bb37f0 100644 (file)
@@ -26,7 +26,7 @@ is what is meant.</p>
 <p>If no version is specified, or if all versions are removed then
 the root package entry is removed from the registry entirely.</p>
 </div>
-<p id="footer">unpublish &mdash; npm@1.1.36</p>
+<p id="footer">unpublish &mdash; npm@1.1.39</p>
 <script>
 ;(function () {
 var wrapper = document.getElementById("wrapper")
index f40b264..b97eb7e 100644 (file)
@@ -18,7 +18,7 @@
 
 <p>The 'packages' argument is an array of packages to update. The 'callback' parameter will be called when done or when an error occurs.</p>
 </div>
-<p id="footer">update &mdash; npm@1.1.36</p>
+<p id="footer">update &mdash; npm@1.1.39</p>
 <script>
 ;(function () {
 var wrapper = document.getElementById("wrapper")
index e842bb0..c4ed3a2 100644 (file)
@@ -24,7 +24,7 @@ fail if the repo is not clean.</p>
 parameter. The difference, however, is this function will fail if it does
 not have exactly one element. The only element should be a version number.</p>
 </div>
-<p id="footer">version &mdash; npm@1.1.36</p>
+<p id="footer">version &mdash; npm@1.1.39</p>
 <script>
 ;(function () {
 var wrapper = document.getElementById("wrapper")
index 74e8648..fe1b993 100644 (file)
@@ -99,7 +99,7 @@ the field name.</p>
 
 <p>corresponding to the list of fields selected.</p>
 </div>
-<p id="footer">view &mdash; npm@1.1.36</p>
+<p id="footer">view &mdash; npm@1.1.39</p>
 <script>
 ;(function () {
 var wrapper = document.getElementById("wrapper")
index 1a4fb26..1d84277 100644 (file)
@@ -21,7 +21,7 @@
 
 <p>This function is not useful programmatically</p>
 </div>
-<p id="footer">whoami &mdash; npm@1.1.36</p>
+<p id="footer">whoami &mdash; npm@1.1.39</p>
 <script>
 ;(function () {
 var wrapper = document.getElementById("wrapper")
index a2c01ae..56a7511 100644 (file)
@@ -261,7 +261,7 @@ will no doubt tell you to put the output in a gist or email.</p>
 
 <ul><li><a href="../doc/npm.html">npm(1)</a></li><li><a href="../doc/faq.html">faq(1)</a></li><li><a href="../doc/help.html">help(1)</a></li><li><a href="../doc/index.html">index(1)</a></li></ul>
 </div>
-<p id="footer"><a href="../doc/README.html">README</a> &mdash; npm@1.1.36</p>
+<p id="footer"><a href="../doc/README.html">README</a> &mdash; npm@1.1.39</p>
 <script>
 ;(function () {
 var wrapper = document.getElementById("wrapper")
index 1afb3c0..e38ff53 100644 (file)
@@ -39,7 +39,7 @@ authorize on a new machine.</p>
 
 <ul><li><a href="../doc/registry.html">registry(1)</a></li><li><a href="../doc/config.html">config(1)</a></li><li><a href="../doc/owner.html">owner(1)</a></li><li><a href="../doc/whoami.html">whoami(1)</a></li></ul>
 </div>
-<p id="footer">adduser &mdash; npm@1.1.36</p>
+<p id="footer">adduser &mdash; npm@1.1.39</p>
 <script>
 ;(function () {
 var wrapper = document.getElementById("wrapper")
index cd5a94b..646360e 100644 (file)
@@ -20,7 +20,7 @@
 
 <ul><li><a href="../doc/prefix.html">prefix(1)</a></li><li><a href="../doc/root.html">root(1)</a></li><li><a href="../doc/folders.html">folders(1)</a></li><li><a href="../doc/config.html">config(1)</a></li></ul>
 </div>
-<p id="footer">bin &mdash; npm@1.1.36</p>
+<p id="footer">bin &mdash; npm@1.1.39</p>
 <script>
 ;(function () {
 var wrapper = document.getElementById("wrapper")
index e3def71..8c61768 100644 (file)
@@ -36,7 +36,7 @@ config param.</p>
 
 <ul><li><a href="../doc/docs.html">docs(1)</a></li><li><a href="../doc/view.html">view(1)</a></li><li><a href="../doc/publish.html">publish(1)</a></li><li><a href="../doc/registry.html">registry(1)</a></li><li><a href="../doc/config.html">config(1)</a></li><li><a href="../doc/json.html">json(1)</a></li></ul>
 </div>
-<p id="footer">bugs &mdash; npm@1.1.36</p>
+<p id="footer">bugs &mdash; npm@1.1.39</p>
 <script>
 ;(function () {
 var wrapper = document.getElementById("wrapper")
index 9351cdb..de61f26 100644 (file)
@@ -25,7 +25,7 @@ A folder containing a <code>package.json</code> file in its root.</li></ul>
 
 <ul><li><a href="../doc/install.html">install(1)</a></li><li><a href="../doc/link.html">link(1)</a></li><li><a href="../doc/scripts.html">scripts(1)</a></li><li><a href="../doc/json.html">json(1)</a></li></ul>
 </div>
-<p id="footer">build &mdash; npm@1.1.36</p>
+<p id="footer">build &mdash; npm@1.1.39</p>
 <script>
 ;(function () {
 var wrapper = document.getElementById("wrapper")
index 72eade4..a0cd97b 100644 (file)
@@ -20,7 +20,7 @@ install packages into the local space.</p>
 
 <ul><li><a href="../doc/install.html">install(1)</a></li></ul>
 </div>
-<p id="footer">bundle &mdash; npm@1.1.36</p>
+<p id="footer">bundle &mdash; npm@1.1.39</p>
 <script>
 ;(function () {
 var wrapper = document.getElementById("wrapper")
index 5da9402..d081ead 100644 (file)
@@ -66,7 +66,7 @@ they do not make an HTTP request to the registry.</p>
 
 <ul><li><a href="../doc/folders.html">folders(1)</a></li><li><a href="../doc/config.html">config(1)</a></li><li><a href="../doc/install.html">install(1)</a></li><li><a href="../doc/publish.html">publish(1)</a></li><li><a href="../doc/pack.html">pack(1)</a></li></ul>
 </div>
-<p id="footer">cache &mdash; npm@1.1.36</p>
+<p id="footer">cache &mdash; npm@1.1.39</p>
 <script>
 ;(function () {
 var wrapper = document.getElementById("wrapper")
index 3c2687f..c536e72 100644 (file)
@@ -65,7 +65,7 @@
 
 <ul><li><a href="../doc/npm.html">npm(1)</a></li><li><a href="../doc/faq.html">faq(1)</a></li></ul>
 </div>
-<p id="footer">changelog &mdash; npm@1.1.36</p>
+<p id="footer">changelog &mdash; npm@1.1.39</p>
 <script>
 ;(function () {
 var wrapper = document.getElementById("wrapper")
index df86286..3f3cfd2 100644 (file)
@@ -180,7 +180,7 @@ set to anything."</p>
 
 <ul><li><a href="../doc/developers.html">developers(1)</a></li><li><a href="../doc/faq.html">faq(1)</a></li><li><a href="../doc/npm.html">npm(1)</a></li></ul>
 </div>
-<p id="footer">coding-style &mdash; npm@1.1.36</p>
+<p id="footer">coding-style &mdash; npm@1.1.39</p>
 <script>
 ;(function () {
 var wrapper = document.getElementById("wrapper")
index 73501b8..5909d8c 100644 (file)
@@ -33,7 +33,7 @@ completions based on the arguments.</p>
 
 <ul><li><a href="../doc/developers.html">developers(1)</a></li><li><a href="../doc/faq.html">faq(1)</a></li><li><a href="../doc/npm.html">npm(1)</a></li></ul>
 </div>
-<p id="footer">completion &mdash; npm@1.1.36</p>
+<p id="footer">completion &mdash; npm@1.1.39</p>
 <script>
 ;(function () {
 var wrapper = document.getElementById("wrapper")
index 27ed281..92ccaa2 100644 (file)
@@ -735,7 +735,7 @@ then answer "no" to any prompt.</p>
 
 <ul><li><a href="../doc/folders.html">folders(1)</a></li><li><a href="../doc/npm.html">npm(1)</a></li></ul>
 </div>
-<p id="footer">config &mdash; npm@1.1.36</p>
+<p id="footer">config &mdash; npm@1.1.39</p>
 <script>
 ;(function () {
 var wrapper = document.getElementById("wrapper")
index e30db82..821ee22 100644 (file)
@@ -29,7 +29,7 @@ something like this:</p>
 
 <ul><li><a href="../doc/publish.html">publish(1)</a></li><li><a href="../doc/registry.html">registry(1)</a></li></ul>
 </div>
-<p id="footer">deprecate &mdash; npm@1.1.36</p>
+<p id="footer">deprecate &mdash; npm@1.1.39</p>
 <script>
 ;(function () {
 var wrapper = document.getElementById("wrapper")
index dbd006e..ce48284 100644 (file)
@@ -160,7 +160,7 @@ from a fresh checkout.</p>
 
 <ul><li><a href="../doc/faq.html">faq(1)</a></li><li><a href="../doc/npm.html">npm(1)</a></li><li><a href="../doc/init.html">init(1)</a></li><li><a href="../doc/json.html">json(1)</a></li><li><a href="../doc/scripts.html">scripts(1)</a></li><li><a href="../doc/publish.html">publish(1)</a></li><li><a href="../doc/adduser.html">adduser(1)</a></li><li><a href="../doc/registry.html">registry(1)</a></li></ul>
 </div>
-<p id="footer">developers &mdash; npm@1.1.36</p>
+<p id="footer">developers &mdash; npm@1.1.39</p>
 <script>
 ;(function () {
 var wrapper = document.getElementById("wrapper")
index a229f48..a398ad3 100644 (file)
@@ -80,7 +80,7 @@ license statement)</li><li>Illegal content.</li></ol>
 
 <ul><li><a href="../doc/registry.html">registry(1)</a></li><li><a href="../doc/owner.html">owner(1)</a></li></ul>
 </div>
-<p id="footer">disputes &mdash; npm@1.1.36</p>
+<p id="footer">disputes &mdash; npm@1.1.39</p>
 <script>
 ;(function () {
 var wrapper = document.getElementById("wrapper")
index 7e0640a..5aea2fd 100644 (file)
@@ -37,7 +37,7 @@ config param.</p>
 
 <ul><li><a href="../doc/view.html">view(1)</a></li><li><a href="../doc/publish.html">publish(1)</a></li><li><a href="../doc/registry.html">registry(1)</a></li><li><a href="../doc/config.html">config(1)</a></li><li><a href="../doc/json.html">json(1)</a></li></ul>
 </div>
-<p id="footer">docs &mdash; npm@1.1.36</p>
+<p id="footer">docs &mdash; npm@1.1.39</p>
 <script>
 ;(function () {
 var wrapper = document.getElementById("wrapper")
index d84553e..8ad9ce1 100644 (file)
@@ -37,7 +37,7 @@ or <code>"notepad"</code> on Windows.</li><li>Type: path</li></ul>
 
 <ul><li><a href="../doc/folders.html">folders(1)</a></li><li><a href="../doc/explore.html">explore(1)</a></li><li><a href="../doc/install.html">install(1)</a></li><li><a href="../doc/config.html">config(1)</a></li></ul>
 </div>
-<p id="footer">edit &mdash; npm@1.1.36</p>
+<p id="footer">edit &mdash; npm@1.1.39</p>
 <script>
 ;(function () {
 var wrapper = document.getElementById("wrapper")
index 89320f1..7d8e479 100644 (file)
@@ -40,7 +40,7 @@ Windows</li><li>Type: path</li></ul>
 
 <ul><li><a href="../doc/submodule.html">submodule(1)</a></li><li><a href="../doc/folders.html">folders(1)</a></li><li><a href="../doc/edit.html">edit(1)</a></li><li><a href="../doc/rebuild.html">rebuild(1)</a></li><li><a href="../doc/build.html">build(1)</a></li><li><a href="../doc/install.html">install(1)</a></li></ul>
 </div>
-<p id="footer">explore &mdash; npm@1.1.36</p>
+<p id="footer">explore &mdash; npm@1.1.39</p>
 <script>
 ;(function () {
 var wrapper = document.getElementById("wrapper")
index d8a1a32..0aac7c8 100644 (file)
@@ -241,7 +241,7 @@ We'll have someone kick it or something.</p>
 
 <ul><li><a href="../doc/npm.html">npm(1)</a></li><li><a href="../doc/developers.html">developers(1)</a></li><li><a href="../doc/json.html">json(1)</a></li><li><a href="../doc/config.html">config(1)</a></li><li><a href="../doc/folders.html">folders(1)</a></li></ul>
 </div>
-<p id="footer">faq &mdash; npm@1.1.36</p>
+<p id="footer">faq &mdash; npm@1.1.39</p>
 <script>
 ;(function () {
 var wrapper = document.getElementById("wrapper")
index 0b68254..0adeb05 100644 (file)
@@ -205,7 +205,7 @@ cannot be found elsewhere.  See <code><a href="../doc/json.html">json(1)</a></co
 
 <ul><li><a href="../doc/faq.html">faq(1)</a></li><li><a href="../doc/json.html">json(1)</a></li><li><a href="../doc/install.html">install(1)</a></li><li><a href="../doc/pack.html">pack(1)</a></li><li><a href="../doc/cache.html">cache(1)</a></li><li><a href="../doc/config.html">config(1)</a></li><li><a href="../doc/publish.html">publish(1)</a></li></ul>
 </div>
-<p id="footer">folders &mdash; npm@1.1.36</p>
+<p id="footer">folders &mdash; npm@1.1.39</p>
 <script>
 ;(function () {
 var wrapper = document.getElementById("wrapper")
index 61f6ad9..ec27b93 100644 (file)
@@ -38,7 +38,7 @@ where the terms were found in the documentation.</p>
 
 <ul><li><a href="../doc/npm.html">npm(1)</a></li><li><a href="../doc/faq.html">faq(1)</a></li><li><a href="../doc/help.html">help(1)</a></li></ul>
 </div>
-<p id="footer">help-search &mdash; npm@1.1.36</p>
+<p id="footer">help-search &mdash; npm@1.1.39</p>
 <script>
 ;(function () {
 var wrapper = document.getElementById("wrapper")
index 0802f4b..442103b 100644 (file)
@@ -36,7 +36,7 @@ matches are equivalent to specifying a topic name.</p>
 
 <ul><li><a href="../doc/npm.html">npm(1)</a></li><li><a href="../doc/README.html">README</a></li><li><a href="../doc/faq.html">faq(1)</a></li><li><a href="../doc/folders.html">folders(1)</a></li><li><a href="../doc/config.html">config(1)</a></li><li><a href="../doc/json.html">json(1)</a></li><li><a href="../doc/help-search.html">help-search(1)</a></li><li><a href="../doc/index.html">index(1)</a></li></ul>
 </div>
-<p id="footer">help &mdash; npm@1.1.36</p>
+<p id="footer">help &mdash; npm@1.1.39</p>
 <script>
 ;(function () {
 var wrapper = document.getElementById("wrapper")
index 9720b92..428ade4 100644 (file)
 
 <p> Display npm username</p>
 </div>
-<p id="footer">index &mdash; npm@1.1.36</p>
+<p id="footer">index &mdash; npm@1.1.39</p>
 <script>
 ;(function () {
 var wrapper = document.getElementById("wrapper")
index 433f360..8abaa31 100644 (file)
@@ -29,7 +29,7 @@ without a really good reason to do so.</p>
 
 <ul><li><a href="https://github.com/isaacs/init-package-json">https://github.com/isaacs/init-package-json</a></li><li><a href="../doc/json.html">json(1)</a></li><li><a href="../doc/version.html">version(1)</a></li></ul>
 </div>
-<p id="footer">init &mdash; npm@1.1.36</p>
+<p id="footer">init &mdash; npm@1.1.39</p>
 <script>
 ;(function () {
 var wrapper = document.getElementById("wrapper")
index 294ef28..c5e8273 100644 (file)
@@ -133,7 +133,7 @@ affects a real use-case, it will be investigated.</p>
 
 <ul><li><a href="../doc/folders.html">folders(1)</a></li><li><a href="../doc/update.html">update(1)</a></li><li><a href="../doc/link.html">link(1)</a></li><li><a href="../doc/rebuild.html">rebuild(1)</a></li><li><a href="../doc/scripts.html">scripts(1)</a></li><li><a href="../doc/build.html">build(1)</a></li><li><a href="../doc/config.html">config(1)</a></li><li><a href="../doc/registry.html">registry(1)</a></li><li><a href="../doc/folders.html">folders(1)</a></li><li><a href="../doc/tag.html">tag(1)</a></li><li><a href="../doc/rm.html">rm(1)</a></li><li><a href="../doc/shrinkwrap.html">shrinkwrap(1)</a></li></ul>
 </div>
-<p id="footer">install &mdash; npm@1.1.36</p>
+<p id="footer">install &mdash; npm@1.1.39</p>
 <script>
 ;(function () {
 var wrapper = document.getElementById("wrapper")
index 082e2ba..2d3c9df 100644 (file)
@@ -524,7 +524,7 @@ overridden.</p>
 
 <ul><li><a href="../doc/semver.html">semver(1)</a></li><li><a href="../doc/init.html">init(1)</a></li><li><a href="../doc/version.html">version(1)</a></li><li><a href="../doc/config.html">config(1)</a></li><li><a href="../doc/help.html">help(1)</a></li><li><a href="../doc/faq.html">faq(1)</a></li><li><a href="../doc/install.html">install(1)</a></li><li><a href="../doc/publish.html">publish(1)</a></li><li><a href="../doc/rm.html">rm(1)</a></li></ul>
 </div>
-<p id="footer">json &mdash; npm@1.1.36</p>
+<p id="footer">json &mdash; npm@1.1.39</p>
 <script>
 ;(function () {
 var wrapper = document.getElementById("wrapper")
index 18c3f9f..5d72c48 100644 (file)
@@ -58,7 +58,7 @@ installation target into your project's <code>node_modules</code> folder.</p>
 
 <ul><li><a href="../doc/developers.html">developers(1)</a></li><li><a href="../doc/faq.html">faq(1)</a></li><li><a href="../doc/json.html">json(1)</a></li><li><a href="../doc/install.html">install(1)</a></li><li><a href="../doc/folders.html">folders(1)</a></li><li><a href="../doc/config.html">config(1)</a></li></ul>
 </div>
-<p id="footer">link &mdash; npm@1.1.36</p>
+<p id="footer">link &mdash; npm@1.1.39</p>
 <script>
 ;(function () {
 var wrapper = document.getElementById("wrapper")
index 5fd5595..f275843 100644 (file)
 
 <h2 id="SYNOPSIS">SYNOPSIS</h2>
 
-<pre><code>npm list
-npm ls
-npm la
-npm ll</code></pre>
+<pre><code>npm list [&lt;pkg&gt; ...]
+npm ls [&lt;pkg&gt; ...]
+npm la [&lt;pkg&gt; ...]
+npm ll [&lt;pkg&gt; ...]</code></pre>
 
 <h2 id="DESCRIPTION">DESCRIPTION</h2>
 
 <p>This command will print to stdout all the versions of packages that are
 installed, as well as their dependencies, in a tree-structure.</p>
 
-<p>It does not take positional arguments, though you may set config flags
-like with any other command, such as <code>-g</code> to list global packages.</p>
+<p>Positional arguments are <code>name@version-range</code> identifiers, which will
+limit the results to only the paths to the packages named.  Note that
+nested packages will <em>also</em> show the paths to the specified packages.
+For example, running <code>npm ls promzard</code> in npm's source tree will show:</p>
 
-<p>It will print out extraneous, missing, and invalid packages.</p>
+<pre><code>npm@1.1.39 /path/to/npm
+└─┬ init-package-json@0.0.4
+  â””── promzard@0.1.5</code></pre>
+
+<p>It will show print out extraneous, missing, and invalid packages.</p>
 
 <p>When run as <code>ll</code> or <code>la</code>, it shows extended information by default.</p>
 
@@ -58,7 +64,7 @@ project.</p>
 
 <ul><li><a href="../doc/config.html">config(1)</a></li><li><a href="../doc/folders.html">folders(1)</a></li><li><a href="../doc/install.html">install(1)</a></li><li><a href="../doc/link.html">link(1)</a></li><li><a href="../doc/prune.html">prune(1)</a></li><li><a href="../doc/outdated.html">outdated(1)</a></li><li><a href="../doc/update.html">update(1)</a></li></ul>
 </div>
-<p id="footer">list &mdash; npm@1.1.36</p>
+<p id="footer">list &mdash; npm@1.1.39</p>
 <script>
 ;(function () {
 var wrapper = document.getElementById("wrapper")
index 9e8120c..8773464 100644 (file)
@@ -14,7 +14,7 @@
 
 <h2 id="VERSION">VERSION</h2>
 
-<p>1.1.36</p>
+<p>1.1.39</p>
 
 <h2 id="DESCRIPTION">DESCRIPTION</h2>
 
@@ -135,7 +135,7 @@ will no doubt tell you to put the output in a gist or email.</p>
 
 <ul><li><a href="../doc/help.html">help(1)</a></li><li><a href="../doc/faq.html">faq(1)</a></li><li><a href="../doc/README.html">README</a></li><li><a href="../doc/json.html">json(1)</a></li><li><a href="../doc/install.html">install(1)</a></li><li><a href="../doc/config.html">config(1)</a></li><li><a href="../doc/index.html">index(1)</a></li><li><a href="../api/npm.html">npm(3)</a></li></ul>
 </div>
-<p id="footer">npm &mdash; npm@1.1.36</p>
+<p id="footer">npm &mdash; npm@1.1.39</p>
 <script>
 ;(function () {
 var wrapper = document.getElementById("wrapper")
index b7f4a58..fbd142a 100644 (file)
@@ -21,7 +21,7 @@ packages are currently outdated.</p>
 
 <ul><li><a href="../doc/update.html">update(1)</a></li><li><a href="../doc/registry.html">registry(1)</a></li><li><a href="../doc/folders.html">folders(1)</a></li></ul>
 </div>
-<p id="footer">outdated &mdash; npm@1.1.36</p>
+<p id="footer">outdated &mdash; npm@1.1.39</p>
 <script>
 ;(function () {
 var wrapper = document.getElementById("wrapper")
index e9f01a5..55a4100 100644 (file)
@@ -34,7 +34,7 @@ that is not implemented at this time.</p>
 
 <ul><li><a href="../doc/publish.html">publish(1)</a></li><li><a href="../doc/registry.html">registry(1)</a></li><li><a href="../doc/adduser.html">adduser(1)</a></li><li><a href="../doc/disputes.html">disputes(1)</a></li></ul>
 </div>
-<p id="footer">owner &mdash; npm@1.1.36</p>
+<p id="footer">owner &mdash; npm@1.1.39</p>
 <script>
 ;(function () {
 var wrapper = document.getElementById("wrapper")
index 5990294..5f834e5 100644 (file)
@@ -29,7 +29,7 @@ overwritten the second time.</p>
 
 <ul><li><a href="../doc/cache.html">cache(1)</a></li><li><a href="../doc/publish.html">publish(1)</a></li><li><a href="../doc/config.html">config(1)</a></li></ul>
 </div>
-<p id="footer">pack &mdash; npm@1.1.36</p>
+<p id="footer">pack &mdash; npm@1.1.39</p>
 <script>
 ;(function () {
 var wrapper = document.getElementById("wrapper")
index afa7fde..46bb2cc 100644 (file)
@@ -20,7 +20,7 @@
 
 <ul><li><a href="../doc/root.html">root(1)</a></li><li><a href="../doc/bin.html">bin(1)</a></li><li><a href="../doc/folders.html">folders(1)</a></li><li><a href="../doc/config.html">config(1)</a></li></ul>
 </div>
-<p id="footer">prefix &mdash; npm@1.1.36</p>
+<p id="footer">prefix &mdash; npm@1.1.39</p>
 <script>
 ;(function () {
 var wrapper = document.getElementById("wrapper")
index ec678aa..4c2e499 100644 (file)
@@ -25,7 +25,7 @@ package's dependencies list.</p>
 
 <ul><li><a href="../doc/rm.html">rm(1)</a></li><li><a href="../doc/folders.html">folders(1)</a></li><li><a href="../doc/list.html">list(1)</a></li></ul>
 </div>
-<p id="footer">prune &mdash; npm@1.1.36</p>
+<p id="footer">prune &mdash; npm@1.1.39</p>
 <script>
 ;(function () {
 var wrapper = document.getElementById("wrapper")
index 1b0b4e5..7e973fb 100644 (file)
@@ -29,7 +29,7 @@ the registry.  Overwrites when the "--force" flag is set.</p>
 
 <ul><li><a href="../doc/registry.html">registry(1)</a></li><li><a href="../doc/adduser.html">adduser(1)</a></li><li><a href="../doc/owner.html">owner(1)</a></li><li><a href="../doc/deprecate.html">deprecate(1)</a></li><li><a href="../doc/tag.html">tag(1)</a></li></ul>
 </div>
-<p id="footer">publish &mdash; npm@1.1.36</p>
+<p id="footer">publish &mdash; npm@1.1.39</p>
 <script>
 ;(function () {
 var wrapper = document.getElementById("wrapper")
index 10b6432..76f7e2d 100644 (file)
@@ -25,7 +25,7 @@ the new binary.</p>
 
 <ul><li><a href="../doc/build.html">build(1)</a></li><li><a href="../doc/install.html">install(1)</a></li></ul>
 </div>
-<p id="footer">rebuild &mdash; npm@1.1.36</p>
+<p id="footer">rebuild &mdash; npm@1.1.39</p>
 <script>
 ;(function () {
 var wrapper = document.getElementById("wrapper")
index e85aacf..683a255 100644 (file)
@@ -97,7 +97,7 @@ ask for help on the <a href="mailto:npm-@googlegroups.com">npm-@googlegroups.com
 
 <ul><li><a href="../doc/config.html">config(1)</a></li><li><a href="../doc/developers.html">developers(1)</a></li><li><a href="../doc/disputes.html">disputes(1)</a></li></ul>
 </div>
-<p id="footer">registry &mdash; npm@1.1.36</p>
+<p id="footer">registry &mdash; npm@1.1.39</p>
 <script>
 ;(function () {
 var wrapper = document.getElementById("wrapper")
index 8fcd3bc..40bad83 100644 (file)
@@ -58,7 +58,7 @@ modules.  To track those down, you can do the following:</p>
 
 <ul><li><a href="../doc/README.html">README</a></li><li><a href="../doc/rm.html">rm(1)</a></li><li><a href="../doc/prune.html">prune(1)</a></li></ul>
 </div>
-<p id="footer">removing-npm &mdash; npm@1.1.36</p>
+<p id="footer">removing-npm &mdash; npm@1.1.39</p>
 <script>
 ;(function () {
 var wrapper = document.getElementById("wrapper")
index 33c6f89..691a631 100644 (file)
@@ -24,7 +24,7 @@ the "start" script.</p>
 
 <ul><li><a href="../doc/run-script.html">run-script(1)</a></li><li><a href="../doc/scripts.html">scripts(1)</a></li><li><a href="../doc/test.html">test(1)</a></li><li><a href="../doc/start.html">start(1)</a></li><li><a href="../doc/stop.html">stop(1)</a></li></ul>
 </div>
-<p id="footer">restart &mdash; npm@1.1.36</p>
+<p id="footer">restart &mdash; npm@1.1.39</p>
 <script>
 ;(function () {
 var wrapper = document.getElementById("wrapper")
index 9725e59..89fbc09 100644 (file)
@@ -20,7 +20,7 @@
 
 <ul><li><a href="../doc/prefix.html">prefix(1)</a></li><li><a href="../doc/bin.html">bin(1)</a></li><li><a href="../doc/folders.html">folders(1)</a></li><li><a href="../doc/config.html">config(1)</a></li></ul>
 </div>
-<p id="footer">root &mdash; npm@1.1.36</p>
+<p id="footer">root &mdash; npm@1.1.39</p>
 <script>
 ;(function () {
 var wrapper = document.getElementById("wrapper")
index 6ebc209..cb52814 100644 (file)
@@ -23,7 +23,7 @@ called directly, as well.</p>
 
 <ul><li><a href="../doc/scripts.html">scripts(1)</a></li><li><a href="../doc/test.html">test(1)</a></li><li><a href="../doc/start.html">start(1)</a></li><li><a href="../doc/restart.html">restart(1)</a></li><li><a href="../doc/stop.html">stop(1)</a></li></ul>
 </div>
-<p id="footer">run-script &mdash; npm@1.1.36</p>
+<p id="footer">run-script &mdash; npm@1.1.39</p>
 <script>
 ;(function () {
 var wrapper = document.getElementById("wrapper")
index 053a3b2..1446b67 100644 (file)
@@ -177,7 +177,7 @@ will sudo the npm command in question.</li></ul>
 
 <ul><li><a href="../doc/run-script.html">run-script(1)</a></li><li><a href="../doc/json.html">json(1)</a></li><li><a href="../doc/developers.html">developers(1)</a></li><li><a href="../doc/install.html">install(1)</a></li></ul>
 </div>
-<p id="footer">scripts &mdash; npm@1.1.36</p>
+<p id="footer">scripts &mdash; npm@1.1.39</p>
 <script>
 ;(function () {
 var wrapper = document.getElementById("wrapper")
index f9a5bd5..3178af1 100644 (file)
@@ -24,7 +24,7 @@ expression characters must be escaped or quoted in most shells.)</p>
 
 <ul><li><a href="../doc/registry.html">registry(1)</a></li><li><a href="../doc/config.html">config(1)</a></li><li><a href="../doc/view.html">view(1)</a></li></ul>
 </div>
-<p id="footer">search &mdash; npm@1.1.36</p>
+<p id="footer">search &mdash; npm@1.1.39</p>
 <script>
 ;(function () {
 var wrapper = document.getElementById("wrapper")
index b1e6443..f0d0d5b 100644 (file)
@@ -104,7 +104,7 @@ that satisfies the range, or null if none of them do.</li></ul>
 
 <ul><li><a href="../doc/json.html">json(1)</a></li></ul>
 </div>
-<p id="footer">semver &mdash; npm@1.1.36</p>
+<p id="footer">semver &mdash; npm@1.1.39</p>
 <script>
 ;(function () {
 var wrapper = document.getElementById("wrapper")
index 29dd869..e1d0288 100644 (file)
@@ -169,7 +169,7 @@ versions.</p>
 
 <ul><li><a href="../doc/install.html">install(1)</a></li><li><a href="../doc/json.html">json(1)</a></li><li><a href="../doc/list.html">list(1)</a></li></ul>
 </div>
-<p id="footer">shrinkwrap &mdash; npm@1.1.36</p>
+<p id="footer">shrinkwrap &mdash; npm@1.1.39</p>
 <script>
 ;(function () {
 var wrapper = document.getElementById("wrapper")
index ef75bf9..2caa4ff 100644 (file)
@@ -26,7 +26,7 @@ a vaguely positive way to show that you care.</p>
 
 <ul><li><a href="../doc/view.html">view(1)</a></li><li><a href="../doc/whoami.html">whoami(1)</a></li><li><a href="../doc/adduser.html">adduser(1)</a></li></ul>
 </div>
-<p id="footer">star &mdash; npm@1.1.36</p>
+<p id="footer">star &mdash; npm@1.1.39</p>
 <script>
 ;(function () {
 var wrapper = document.getElementById("wrapper")
index 0a17b06..0ba8e1f 100644 (file)
@@ -20,7 +20,7 @@
 
 <ul><li><a href="../doc/run-script.html">run-script(1)</a></li><li><a href="../doc/scripts.html">scripts(1)</a></li><li><a href="../doc/test.html">test(1)</a></li><li><a href="../doc/restart.html">restart(1)</a></li><li><a href="../doc/stop.html">stop(1)</a></li></ul>
 </div>
-<p id="footer">start &mdash; npm@1.1.36</p>
+<p id="footer">start &mdash; npm@1.1.39</p>
 <script>
 ;(function () {
 var wrapper = document.getElementById("wrapper")
index 55203f9..9283cd9 100644 (file)
@@ -20,7 +20,7 @@
 
 <ul><li><a href="../doc/run-script.html">run-script(1)</a></li><li><a href="../doc/scripts.html">scripts(1)</a></li><li><a href="../doc/test.html">test(1)</a></li><li><a href="../doc/start.html">start(1)</a></li><li><a href="../doc/restart.html">restart(1)</a></li></ul>
 </div>
-<p id="footer">stop &mdash; npm@1.1.36</p>
+<p id="footer">stop &mdash; npm@1.1.39</p>
 <script>
 ;(function () {
 var wrapper = document.getElementById("wrapper")
index c98b0a9..68f7324 100644 (file)
@@ -33,7 +33,7 @@ dependencies into the submodule folder.</p>
 
 <ul><li><a href="../doc/json.html">json(1)</a></li><li>git help submodule</li></ul>
 </div>
-<p id="footer">submodule &mdash; npm@1.1.36</p>
+<p id="footer">submodule &mdash; npm@1.1.39</p>
 <script>
 ;(function () {
 var wrapper = document.getElementById("wrapper")
index 81e3afa..5c1e539 100644 (file)
@@ -21,7 +21,7 @@
 
 <ul><li><a href="../doc/publish.html">publish(1)</a></li><li><a href="../doc/registry.html">registry(1)</a></li><li><a href="../doc/config.html">config(1)</a></li></ul>
 </div>
-<p id="footer">tag &mdash; npm@1.1.36</p>
+<p id="footer">tag &mdash; npm@1.1.39</p>
 <script>
 ;(function () {
 var wrapper = document.getElementById("wrapper")
index 6921008..5212194 100644 (file)
@@ -23,7 +23,7 @@ true.</p>
 
 <ul><li><a href="../doc/run-script.html">run-script(1)</a></li><li><a href="../doc/scripts.html">scripts(1)</a></li><li><a href="../doc/start.html">start(1)</a></li><li><a href="../doc/restart.html">restart(1)</a></li><li><a href="../doc/stop.html">stop(1)</a></li></ul>
 </div>
-<p id="footer">test &mdash; npm@1.1.36</p>
+<p id="footer">test &mdash; npm@1.1.39</p>
 <script>
 ;(function () {
 var wrapper = document.getElementById("wrapper")
index e59fe56..743629a 100644 (file)
@@ -22,7 +22,7 @@ on its behalf.</p>
 
 <ul><li><a href="../doc/prune.html">prune(1)</a></li><li><a href="../doc/install.html">install(1)</a></li><li><a href="../doc/folders.html">folders(1)</a></li><li><a href="../doc/config.html">config(1)</a></li></ul>
 </div>
-<p id="footer">uninstall &mdash; npm@1.1.36</p>
+<p id="footer">uninstall &mdash; npm@1.1.39</p>
 <script>
 ;(function () {
 var wrapper = document.getElementById("wrapper")
index 524fe2e..203f318 100644 (file)
@@ -34,7 +34,7 @@ the root package entry is removed from the registry entirely.</p>
 
 <ul><li><a href="../doc/deprecate.html">deprecate(1)</a></li><li><a href="../doc/publish.html">publish(1)</a></li><li><a href="../doc/registry.html">registry(1)</a></li><li><a href="../doc/adduser.html">adduser(1)</a></li><li><a href="../doc/owner.html">owner(1)</a></li></ul>
 </div>
-<p id="footer">unpublish &mdash; npm@1.1.36</p>
+<p id="footer">unpublish &mdash; npm@1.1.39</p>
 <script>
 ;(function () {
 var wrapper = document.getElementById("wrapper")
index 3b84fde..5778f4d 100644 (file)
@@ -23,7 +23,7 @@
 
 <ul><li><a href="../doc/install.html">install(1)</a></li><li><a href="../doc/outdated.html">outdated(1)</a></li><li><a href="../doc/registry.html">registry(1)</a></li><li><a href="../doc/folders.html">folders(1)</a></li><li><a href="../doc/list.html">list(1)</a></li></ul>
 </div>
-<p id="footer">update &mdash; npm@1.1.36</p>
+<p id="footer">update &mdash; npm@1.1.39</p>
 <script>
 ;(function () {
 var wrapper = document.getElementById("wrapper")
index e9d0726..40298eb 100644 (file)
@@ -31,7 +31,7 @@ will use it as a commit message when creating a version commit.</p>
 
 <ul><li><a href="../doc/init.html">init(1)</a></li><li><a href="../doc/json.html">json(1)</a></li><li><a href="../doc/semver.html">semver(1)</a></li></ul>
 </div>
-<p id="footer">version &mdash; npm@1.1.36</p>
+<p id="footer">version &mdash; npm@1.1.39</p>
 <script>
 ;(function () {
 var wrapper = document.getElementById("wrapper")
index fe67a60..0099b83 100644 (file)
@@ -88,7 +88,7 @@ the field name.</p>
 
 <ul><li><a href="../doc/search.html">search(1)</a></li><li><a href="../doc/registry.html">registry(1)</a></li><li><a href="../doc/config.html">config(1)</a></li><li><a href="../doc/docs.html">docs(1)</a></li></ul>
 </div>
-<p id="footer">view &mdash; npm@1.1.36</p>
+<p id="footer">view &mdash; npm@1.1.39</p>
 <script>
 ;(function () {
 var wrapper = document.getElementById("wrapper")
index 3824ae5..c3c9e0c 100644 (file)
@@ -20,7 +20,7 @@
 
 <ul><li><a href="../doc/config.html">config(1)</a></li><li><a href="../doc/adduser.html">adduser(1)</a></li></ul>
 </div>
-<p id="footer">whoami &mdash; npm@1.1.36</p>
+<p id="footer">whoami &mdash; npm@1.1.39</p>
 <script>
 ;(function () {
 var wrapper = document.getElementById("wrapper")
index 3d77272..de7ccad 100644 (file)
@@ -506,19 +506,6 @@ function addNameRange (name, range, data, cb) {
              , {name:name, range:range, hasData:!!data})
     engineFilter(data)
 
-    if (npm.config.get("registry")) return next_()
-
-    cachedFilter(data, range, function (er) {
-      if (er) return cb(er)
-      if (Object.keys(data.versions).length === 0) {
-        return cb(new Error( "Can't fetch, and not cached: "
-                           + data.name + "@" + range))
-      }
-      next_()
-    })
-  }
-
-  function next_ () {
     log.silly("addNameRange", "versions"
              , [data.name, Object.keys(data.versions || {})])
 
@@ -540,39 +527,6 @@ function addNameRange (name, range, data, cb) {
   }
 }
 
-// filter the versions down based on what's already in cache.
-function cachedFilter (data, range, cb) {
-  log.silly("cachedFilter", data.name)
-  ls_(data.name, 1, function (er, files) {
-    if (er) {
-      log.error("cachedFilter", "Not in cache, can't fetch", data.name)
-      return cb(er)
-    }
-    files = files.map(function (f) {
-      return path.basename(f.replace(/(\\|\/)$/, ""))
-    }).filter(function (f) {
-      return semver.valid(f) && semver.satisfies(f, range)
-    })
-
-    if (files.length === 0) {
-      return cb(new Error("Not in cache, can't fetch: "+data.name+"@"+range))
-    }
-
-    log.silly("cached", [data.name, files])
-    Object.keys(data.versions).forEach(function (v) {
-      if (files.indexOf(v) === -1) delete data.versions[v]
-    })
-
-    if (Object.keys(data.versions).length === 0) {
-      log.error("cachedFilter", "Not in cache, can't fetch", data.name)
-      return cb(new Error("Not in cache, can't fetch: "+data.name+"@"+range))
-    }
-
-    log.silly("filtered", [data.name, Object.keys(data.versions)])
-    cb(null, data)
-  })
-}
-
 function installTargetsError (requested, data) {
   var targets = Object.keys(data["dist-tags"]).filter(function (f) {
     return (data.versions || {}).hasOwnProperty(f)
index 02e7fe2..2b45ca3 100644 (file)
@@ -13,22 +13,30 @@ var npm = require("./npm.js")
   , log = require("npmlog")
   , path = require("path")
   , archy = require("archy")
+  , semver = require("semver")
 
 ls.usage = "npm ls"
 
+ls.completion = require("./utils/completion/installed-deep.js")
+
 function ls (args, silent, cb) {
   if (typeof cb !== "function") cb = silent, silent = false
 
-  if (args.length) {
-    // TODO: it would actually be nice to maybe show the locally
-    // installed packages only matching the argument names.
-    log.warn("ls doesn't take positional args. Try the 'search' command")
-  }
-
   var dir = path.resolve(npm.dir, "..")
 
+  // npm ls 'foo@~1.3' bar 'baz@<2'
+  if (!args) args = []
+  else args = args.map(function (a) {
+    var nv = a.split("@")
+      , name = nv.shift()
+      , ver = semver.validRange(nv.join("@")) || ""
+
+    return [ name, ver ]
+  })
+
   readInstalled(dir, npm.config.get("depth"), function (er, data) {
-    var lite = getLite(bfsify(data))
+    var bfs = bfsify(data, args)
+      , lite = getLite(bfs)
     if (er || silent) return cb(er, data, lite)
 
     var long = npm.config.get("long")
@@ -36,7 +44,7 @@ function ls (args, silent, cb) {
       , out
     if (json) {
       var seen = []
-      var d = long ? bfsify(data) : lite
+      var d = long ? bfs : lite
       // the raw data can be circular
       out = JSON.stringify(d, function (k, o) {
         if (typeof o === "object") {
@@ -46,14 +54,19 @@ function ls (args, silent, cb) {
         return o
       }, 2)
     } else if (npm.config.get("parseable")) {
-      out = makeParseable(bfsify(data), long, dir)
+      out = makeParseable(bfs, long, dir)
     } else if (data) {
-      out = makeArchy(bfsify(data), long, dir)
+      out = makeArchy(bfs, long, dir)
     }
     output.write(out, function (er) { cb(er, data, lite) })
   })
 }
 
+// only include 
+function filter (data, args) {
+
+}
+
 function alphasort (a, b) {
   a = a.toLowerCase()
   b = b.toLowerCase()
@@ -124,7 +137,7 @@ function getLite (data, noname) {
   return lite
 }
 
-function bfsify (root, current, queue, seen) {
+function bfsify (root, args, current, queue, seen) {
   // walk over the data, and turn it from this:
   // +-- a
   // |   `-- b
@@ -134,6 +147,7 @@ function bfsify (root, current, queue, seen) {
   // +-- a
   // `-- b
   // which looks nicer
+  args = args || []
   current = current || root
   queue = queue || []
   seen = seen || [root]
@@ -153,10 +167,37 @@ function bfsify (root, current, queue, seen) {
     queue.push(dep)
     seen.push(dep)
   })
-  if (!queue.length) return root
-  return bfsify(root, queue.shift(), queue, seen)
+
+  if (!queue.length) {
+    // if there were args, then only show the paths to found nodes.
+    return filterFound(root, args)
+  }
+  return bfsify(root, args, queue.shift(), queue, seen)
 }
 
+function filterFound (root, args) {
+  if (!args.length) return root
+  var deps = root.dependencies
+  if (deps) Object.keys(deps).forEach(function (d) {
+    var dep = filterFound(deps[d], args)
+
+    // see if this one itself matches
+    var found = false
+    for (var i = 0; !found && i < args.length; i ++) {
+      if (d === args[i][0]) {
+        found = semver.satisfies(dep.version, args[i][1])
+      }
+    }
+    // included explicitly
+    if (found) dep._found = true
+    // included because a child was included
+    if (dep._found && !root._found) root._found = 1
+    // not included
+    if (!dep._found) delete deps[d]
+  })
+  if (!root._found) root._found = false
+  return root
+}
 
 function makeArchy (data, long, dir) {
   var out = makeArchy_(data, long, dir, 0)
@@ -178,8 +219,11 @@ function makeArchy_ (data, long, dir, depth, parent, d) {
 
   var out = {}
   // the top level is a bit special.
-  out.label = data._id ? data._id + " " : ""
-  if (data.link) out.label += "-> " + data.link
+  out.label = data._id || ""
+  if (data._found === true && data._id) {
+    out.label = "\033[33;40m" + out.label.trim() + "\033[m "
+  }
+  if (data.link) out.label += " -> " + data.link
 
   if (data.invalid) {
     if (data.realName !== data.name) out.label += " ("+data.realName+")"
@@ -237,10 +281,13 @@ function makeParseable (data, long, dir, depth, parent, d) {
     .sort(alphasort).map(function (d) {
       return makeParseable(data.dependencies[d], long, dir, depth + 1, data, d)
     }))
+  .filter(function (x) { return x })
   .join("\n")
 }
 
 function makeParseable_ (data, long, dir, depth, parent, d) {
+  if (data.hasOwnProperty("_found") && data._found !== true) return ""
+
   if (typeof data === "string") {
     if (data.depth < npm.config.get("depth")) {
       var p = parent.link || parent.path
index 6113604..dd85b83 100644 (file)
@@ -275,10 +275,15 @@ function load (npm, conf, cb) {
 
       // at this point the configs are all set.
       // go ahead and spin up the registry client.
+      var token
+      try { token = JSON.parse(npm.config.get("_token")) }
+      catch (er) { token = null }
+
       npm.registry = new RegClient(
         { registry: npm.config.get("registry")
         , cache: npm.config.get("cache")
         , auth: npm.config.get("_auth")
+        , token: token
         , alwaysAuth: npm.config.get("always-auth")
         , email: npm.config.get("email")
         , proxy: npm.config.get("proxy")
@@ -293,8 +298,19 @@ function load (npm, conf, cb) {
         , retryFactor: npm.config.get("fetch-retry-factor")
         , retryMinTimeout: npm.config.get("fetch-retry-mintimeout")
         , retryMaxTimeout: npm.config.get("fetch-retry-maxtimeout")
+        , cacheMin: npm.config.get("cache-min")
+        , cacheMax: npm.config.get("cache-max")
         })
 
+      // save the token cookie in the config file
+      if (npm.registry.couchLogin) {
+        npm.registry.couchLogin.tokenSet = function (tok, cb) {
+          ini.set("_token", JSON.stringify(tok), "user")
+          // ignore save error.  best effort.
+          ini.save("user", function () {})
+        }
+      }
+
       var umask = parseInt(conf.umask, 8)
       npm.modes = { exec: 0777 & (~umask)
                   , file: 0666 & (~umask)
index 9a9c642..d741807 100644 (file)
@@ -6,6 +6,9 @@ var testCmd = require("./utils/lifecycle.js").cmd("test")
 function test (args, cb) {
   testCmd(args, function (er) {
     if (!er) return cb()
-    return cb("Test failed.  See above for more details.")
+    if (er.code === "ELIFECYCLE") {
+      return cb("Test failed.  See above for more details.")
+    }
+    return cb(er)
   })
 }
index f1e004e..6042abc 100644 (file)
@@ -71,7 +71,6 @@ function makeRequest (remote, fstr, headers) {
 
   var opts = { url: remote
              , proxy: proxy
-             , follow: false
              , strictSSL: npm.config.get("strict-ssl")
              , ca: remote.host === regHost ? npm.config.get("ca") : undefined
              , headers: { "user-agent": npm.config.get("user-agent") }}
index 6e84ff4..1eae1dc 100644 (file)
@@ -9,10 +9,10 @@
 .SH "SYNOPSIS"
 .
 .nf
-npm list
-npm ls
-npm la
-npm ll
+npm list [<pkg> \.\.\.]
+npm ls [<pkg> \.\.\.]
+npm la [<pkg> \.\.\.]
+npm ll [<pkg> \.\.\.]
 .
 .fi
 .
@@ -21,11 +21,24 @@ This command will print to stdout all the versions of packages that are
 installed, as well as their dependencies, in a tree\-structure\.
 .
 .P
-It does not take positional arguments, though you may set config flags
-like with any other command, such as \fB\-g\fR to list global packages\.
+Positional arguments are \fBname@version\-range\fR identifiers, which will
+limit the results to only the paths to the packages named\.  Note that
+nested packages will \fIalso\fR show the paths to the specified packages\.
+For example, running \fBnpm ls promzard\fR in npm\'s source tree will show:
+.
+.IP "" 4
+.
+.nf
+npm@1.1.39 /path/to/npm
+└─┬ init\-package\-json@0\.0\.4
+  â””── promzard@0\.1\.5
+.
+.fi
+.
+.IP "" 0
 .
 .P
-It will print out extraneous, missing, and invalid packages\.
+It will show print out extraneous, missing, and invalid packages\.
 .
 .P
 When run as \fBll\fR or \fBla\fR, it shows extended information by default\.
index a6129e0..f9e6d06 100644 (file)
@@ -14,7 +14,7 @@ npm <command> [args]
 .fi
 .
 .SH "VERSION"
-1.1.36
+1.1.39
 .
 .SH "DESCRIPTION"
 npm is the package manager for the Node JavaScript platform\.  It puts
index a6860c9..3e0e3d0 100644 (file)
@@ -21,7 +21,7 @@ npm\.load(configObject, function (er, npm) {
 .fi
 .
 .SH "VERSION"
-1.1.36
+1.1.39
 .
 .SH "DESCRIPTION"
 This is the API documentation for npm\.
diff --git a/deps/npm/node_modules/couch-login/README.md b/deps/npm/node_modules/couch-login/README.md
new file mode 100644 (file)
index 0000000..0b6c75d
--- /dev/null
@@ -0,0 +1,241 @@
+# couch-login
+
+This module lets you log into couchdb to get a session token, then make
+requests using that session.  It is basically just a thin wrapper around
+[@mikeal's request module](https://github.com/mikeal/request).
+
+This is handy if you want a user to take actions in a couchdb database
+on behalf of a user, without having to store their couchdb username and
+password anywhere.  (You do need to store the AuthSession token
+somewhere, though.)
+
+## Usage
+
+```javascript
+var CouchLogin = require('couch-login')
+
+// Nothing about this module is http-server specific of course.
+// You could also use it to do authenticated requests against
+// a couchdb using sessions and storing the token somewhere else.
+
+http.createServer(function (req, res) {
+  var couch = new CouchLogin('http://my-couch.iriscouch.com:5984/')
+
+  // .. look up the token in the user's session or whatever ..
+  // Look at couch.decorate(req, res) for more on doing that
+  // automatically, below.
+
+  if (sessionToken) {
+    // this user already logged in.
+    couch.token = sessionToken
+
+    // now we can do things on their behalf, like:
+    // 1. View their session info.
+    // like doing request.get({ uri: couch + '/_session', ... })
+    // but with the cookie and whatnot
+
+    couch.get('/_session', function (er, resp, data) {
+      // er = some kind of communication error.
+      // resp = response object from the couchdb request.
+      // data = parsed JSON response body.
+      if (er || resp.statusCode !== 200) {
+        res.statusCode = resp.statusCode || 403
+        return res.end('Invalid login or something')
+      }
+
+      // now we have the session info, we know who this user is.
+      // hitting couchdb for this on every request is kinda costly,
+      // so maybe you should store the username wherever you're storing
+      // the sessionToken.  RedSess is a good util for this, if you're
+      // into redis.  And if you're not into redis, you're crazy,
+      // because it is awesome.
+
+      // now let's get the user record.
+      // note that this will 404 for anyone other than the user,
+      // unless they're a server admin.
+      couch.get('/_users/org.couchdb.user:' + data.userCtx.name, etc)
+
+      // PUTs and DELETEs will also use their session, of course, so
+      // your validate_doc_update's will see their info in userCtx
+    })
+
+  } else {
+    // don't have a sessionToken.
+    // get a username and password from the post body or something.
+    // maybe redirect to a /login page or something to ask for that.
+    var login = { name: name, password: password }
+    couch.login(login, function (er, resp, data) {
+      // again, er is an error, resp is the response obj, data is the json
+      if (er || resp.statusCode !== 200) {
+        res.statusCode = resp.statusCode || 403
+        return res.end('Invalid login or something')
+      }
+
+      // the data is something like
+      // {"ok":true,"name":"testuser","roles":[]}
+      // and couch.token is the token you'll need to save somewhere.
+
+      // at this point, you can start making authenticated requests to
+      // couchdb, or save data in their session, or do whatever it is
+      // that you need to do.
+
+      res.statusCode = 200
+      res.write("Who's got two thumbs and just logged you into couch?\n")
+      setTimeout(function () {
+        res.end("THIS GUY!")
+      }, 500)
+    })
+  }
+})
+```
+
+## Class: CouchLogin
+### new CouchLogin(couchdbUrl, token)
+
+Create a new CouchLogin object bound to the couchdb url.
+
+In addition to these, the `get`, `post`, `put`, and `del` methods all
+proxy to the associated method on [request](https://github.com/mikeal/request).
+
+However, as you'll note in the example above, only the pathname portion
+of the url is required.  Urls will be appended to the couchdb url passed
+into the constructor.
+
+If you have to talk to more than one couchdb, then you'll need more than
+one CouchLogin object, for somewhat obvious reasons.
+
+All callbacks get called with the following arguments, which are exactly
+identical to the arguments passed to a `request` callback.
+
+* `er` {Error | null} Set if a communication error happens.
+* `resp` {HTTP Response} The response from the request to couchdb
+* `data` {Object} The parsed JSON data from couch
+
+If the token is the string "anonymous", then it will not attempt to log
+in before making requests.  If the token is not "anonymous", then it
+must be an object with the appropriate fields.
+
+### couch.token
+
+* {Object}
+
+An object representing the couchdb session token.  (Basically just a
+cookie and a timeout.)
+
+If the token has already timed out, then setting it will have no effect.
+
+### couch.tokenSet
+
+If set, this method is called whenever the token is saved.
+
+For example, you could assign a function to this method to save the
+token into a redis session, a cookie, or in some other database.
+
+Takes a callback which should be called when the token is saved.
+
+### couch.tokenGet
+
+If set, this method is called to look up the token on demand.
+
+The inverse of couch.tokenSet.  Takes a callback which is called with
+the `cb(er || null, token)`.
+
+### couch.tokenDel
+
+If set, this method is called to delete the token when it should be
+discarded.
+
+Related to tokenGet and tokenSet.  Takes a callback which should be
+called when the token is deleted.
+
+### couch.anonymous()
+
+Return a new CouchLogin object that points at the same couchdb server,
+but doesn't try to log in before making requests.
+
+This is handy for situations where the user is not logged in at the
+moment, but a request needs to be made anyway, and does not require
+authorization.
+
+### couch.login(auth, callback)
+
+* `auth` {Object} The login details
+  * `name` {String}
+  * `password` {String}
+* `callback` {Function}
+
+When the callback is called, the `couch.token` will already have been
+set (assuming it worked!), so subsequent requests will be done as that
+user.
+
+### couch.get(path, callback)
+
+GET the supplied path from the couchdb using the credentials on the
+token.
+
+Fails if the token is invalid or expired.
+
+### couch.del(path, callback)
+
+DELETE the supplied path from the couchdb using the credentials on the
+token.
+
+Fails if the token is invalid or expired.
+
+### couch.post(path, data, callback)
+
+POST the data to the supplied path in the couchdb, using the credentials
+on the token.
+
+Fails if the token is invalid or expired.
+
+### couch.put(path, data, callback)
+
+PUT the data to the supplied path in the couchdb, using the credentials
+on the token.
+
+Fails if the token is invalid or expired.
+
+### couch.changePass(newAuth, callback)
+
+Must already be logged in.  Updates the `_users` document with new salt
+and hash, and re-logs in with the new credentials.  Callback is called
+with the same arguments as login, or the first step of the process that
+failed.
+
+### couch.signup(userData, callback)
+
+Create a new user account.  The userData must contain at least a `name`
+and `password` field.  Any additional data will be copied to the user
+record.  The `_id`, `name`, `roles`, `type`, `password_sha`, `salt`, and
+`date` fields are generated.
+
+Also signs in as the newly created user, on successful account creation.
+
+### couch.deleteAccount(name, callback)
+
+Deletes a user account.  If not logged in as the user, or a server
+admin, then the request will fail.
+
+Note that this immediately invalidates any session tokens for the
+deleted user account.  If you are deleting the user's record, then you
+ought to follow this with `couch.logout(callback)` so that it won't try
+to re-use the invalid session.
+
+### couch.logout(callback)
+
+Delete the session out of couchdb.  This makes the token permanently
+invalid, and deletes it.
+
+### couch.decorate(req, res)
+
+Set up `req.couch` and `res.couch` as references to this couch login
+instance.
+
+Additionall, if `req.session` or `res.session` is set, then it'll call
+`session.get('couch_token', cb)` as the tokenGet method,
+`session.set('couch_token', token, cb)` as the tokenSet method, and
+`session.del('couch_token', cb)` as the tokenDel method.
+
+This works really nice with
+[RedSess](https://github.com/isaacs/redsess).
diff --git a/deps/npm/node_modules/couch-login/couch-login.js b/deps/npm/node_modules/couch-login/couch-login.js
new file mode 100644 (file)
index 0000000..d240da0
--- /dev/null
@@ -0,0 +1,287 @@
+var request = require('request')
+, url = require('url')
+, crypto = require('crypto')
+
+module.exports = CouchLogin
+
+function CouchLogin (couch, tok) {
+  if (!(this instanceof CouchLogin)) {
+    return new CouchLogin(couch)
+  }
+
+  if (!couch) throw new Error(
+    "Need to pass a couch url to CouchLogin constructor")
+
+  // having auth completely defeats the purpose
+  couch = url.parse(couch)
+  delete couch.auth
+
+  if (tok === 'anonymous') tok = NaN
+  this.token = tok
+  this.couch = url.format(couch)
+}
+
+CouchLogin.prototype =
+{ get: makeReq('GET')
+, del: makeReq('DELETE')
+, put: makeReq('PUT', true)
+, post: makeReq('POST', true)
+, login: login
+, logout: logout
+, decorate: decorate
+, changePass: changePass
+, signup: signup
+, deleteAccount: deleteAccount
+, anon: anon
+, anonymous: anon
+, valid: valid
+}
+
+Object.defineProperty(CouchLogin.prototype, 'constructor',
+  { value: CouchLogin, enumerable: false })
+
+function decorate (req, res) {
+  req.couch = res.couch = this
+
+  // backed by some sort of set(k,v,cb), get(k,cb) session storage.
+  var session = req.session || res.session || null
+  if (session) {
+    this.tokenGet = function (cb) {
+      session.get('couch_token', cb)
+    }
+
+    // don't worry about it failing.  it'll just mean a login next time.
+    this.tokenSet = function (tok, cb) {
+      session.set('couch_token', tok, cb || function () {})
+    }
+
+    this.tokenDel = function (cb) {
+      session.del('couch_token', cb || function () {})
+    }
+  }
+
+  return this
+}
+
+function anon () {
+  return new CouchLogin(this.couch, NaN)
+}
+
+function makeReq (meth, body, f) { return function madeReq (p, d, cb) {
+  f = f || (this.token !== this.token)
+  if (!f && !valid(this.token)) {
+    // lazily get the token.
+    if (this.tokenGet) return this.tokenGet(function (er, tok) {
+      if (er || !valid(tok)) {
+        if (!body) cb = d, d = null
+        return cb(new Error('auth token expired or invalid'))
+      }
+      this.token = tok
+      return madeReq.call(this, p, d, cb)
+    }.bind(this))
+
+    // no getter, no token, no business.
+    return process.nextTick(function () {
+      if (!body) cb = d, d = null
+      cb(new Error('auth token expired or invalid'))
+    })
+  }
+
+  if (!body) cb = d, d = null
+
+  var h = {}
+  , u = url.resolve(this.couch, p)
+  , req = { uri: u, headers: h, json: true, body: d, method: meth }
+
+  if (this.token) {
+    h.cookie = 'AuthSession=' + this.token.AuthSession
+  }
+
+  request(req, function (er, res, data) {
+    // update cookie.
+    if (er || res.statusCode !== 200) return cb(er, res, data)
+    addToken.call(this, res)
+    return cb(er, res, data)
+  }.bind(this))
+}}
+
+function login (auth, cb) {
+  var a = { name: auth.name, password: auth.password }
+  makeReq('post', true, true).call(this, '/_session', a, cb)
+}
+
+function changePass (auth, cb) {
+  if (!auth.name || !auth.password) return cb(new Error('invalid auth'))
+
+  var u = '/_users/org.couchdb.user:' + auth.name
+  this.get(u, function (er, res, data) {
+    if (er || res.statusCode !== 200) return cb(er, res, data)
+
+    // copy any other keys we're setting here.
+    // note that name, password_sha, salt, and date
+    // are all set explicitly below.
+    Object.keys(auth).filter(function (k) {
+      return k.charAt(0) !== '_'
+          && k !== 'password'
+          && k !== 'password_sha'
+          && k !== 'salt'
+    }).forEach(function (k) {
+      data[k] = auth[k]
+    })
+
+    var newSalt = crypto.randomBytes(30).toString('hex')
+    , newPass = auth.password
+    , newSha = sha(newPass + newSalt)
+
+    data.password_sha = newSha
+    data.salt = newSalt
+    data.date = new Date().toISOString()
+
+    this.put(u + '?rev=' + data._rev, data, function (er, res, data) {
+      if (er || res.statusCode >= 400) return cb(er, res, data)
+      this.login(auth, cb)
+    }.bind(this))
+  }.bind(this))
+}
+
+// They said that there should probably be a warning before
+// deleting the user's whole account, so here it is:
+//
+// WATCH OUT!
+function deleteAccount (name, cb) {
+  var u = '/_users/org.couchdb.user:' + name
+  this.get(u, thenPut.bind(this))
+
+  function thenPut (er, res, data) {
+    if (er || res.statusCode !== 200) {
+      return cb(er, res, data)
+    }
+
+    // user accts can't be just DELETE'd by non-admins
+    // so we take the existing doc and just slap a _deleted
+    // flag on it to fake it.  Works the same either way
+    // in couch.
+    data._deleted = true
+    this.put(u + '?rev=' + data._rev, data, cb)
+  }
+}
+
+
+
+function signup (auth, cb) {
+  if (this.token) return this.logout(function (er, res, data) {
+    if (er || res.statusCode !== 200) {
+      return cb(er, res, data)
+    }
+
+    if (this.token) {
+      return cb(new Error('failed to delete token'), res, data)
+    }
+
+    this.signup(auth, cb)
+  }.bind(this))
+
+  // make a new user record.
+  var newSalt = crypto.randomBytes(30).toString('hex')
+  , newSha = sha(auth.password + newSalt)
+  , user = { _id: 'org.couchdb.user:' + auth.name
+           , name: auth.name
+           , roles: []
+           , type: 'user'
+           , password_sha: newSha
+           , salt: newSalt
+           , date: new Date().toISOString() }
+
+  Object.keys(auth).forEach(function (k) {
+    if (k === 'name' || k === 'password') return
+    user[k] = auth[k]
+  })
+
+  var u = '/_users/' + user._id
+  makeReq('put', true, true).call(this, u, user, function (er, res, data) {
+    if (er || res.statusCode >= 400) {
+      return cb(er, res, data)
+    }
+
+    // it worked! log in as that user and get their record
+    this.login(auth, function (er, res, data) {
+      if (er || (res && res.statusCode >= 400) || data && data.error) {
+        return cb(er, res, data)
+      }
+      this.get(u, cb)
+    }.bind(this))
+  }.bind(this))
+}
+
+function addToken (res) {
+  // attach the token, if a new one was provided.
+  var sc = res.headers['set-cookie']
+  if (!sc) return
+  if (!Array.isArray(sc)) sc = [sc]
+
+  sc = sc.filter(function (c) {
+    return c.match(/^AuthSession=/)
+  })[0]
+
+  if (!sc.length) return
+
+  sc = sc.split(/\s*;\s*/).map(function (p) {
+    return p.split('=')
+  }).reduce(function (set, p) {
+    var k = p[0] === 'AuthSession' ? p[0] : p[0].toLowerCase()
+    , v = k === 'expires' ? Date.parse(p[1])
+        : p[1] === '' || p[1] === undefined ? true // HttpOnly
+        : p[1]
+    set[k] = v
+    return set
+  }, {})
+
+  if (sc.hasOwnProperty('max-age')) {
+    var ma = sc['max-age']
+    sc.expires = (ma <= 0) ? 0 : Date.now() + (ma * 1000)
+    delete sc['max-age']
+  }
+
+  this.token = sc
+  if (this.tokenSet) this.tokenSet(this.token)
+}
+
+
+function logout (cb) {
+  if (!this.token && this.tokenGet) {
+    return this.tokenGet(function (er, tok) {
+      if (er || !tok) return cb()
+      this.token = tok
+      this.logout(cb)
+    }.bind(this))
+  }
+
+  if (!valid(this.token)) {
+    this.token = null
+    if (this.tokenDel) this.tokenDel()
+    return process.nextTick(cb)
+  }
+
+  var h = { cookie: 'AuthSession=' + this.token.AuthSession }
+  , u = url.resolve(this.couch, '/_session')
+  , req = { uri: u, headers: h, json: true }
+
+  request.del(req, function (er, res, data) {
+    if (er || res.statusCode !== 200) {
+      return cb(er, res, data)
+    }
+
+    this.token = null
+    if (this.tokenDel) this.tokenDel()
+    cb(er, res, data)
+  }.bind(this))
+}
+
+function valid (token) {
+  var d = token && token.expires
+  return token && token.expires > Date.now()
+}
+
+function sha (s) {
+  return crypto.createHash("sha1").update(s).digest("hex")
+}
diff --git a/deps/npm/node_modules/couch-login/package.json b/deps/npm/node_modules/couch-login/package.json
new file mode 100644 (file)
index 0000000..f39660a
--- /dev/null
@@ -0,0 +1,27 @@
+{
+  "author": {
+    "name": "Isaac Z. Schlueter",
+    "email": "i@izs.me",
+    "url": "http://blog.izs.me/"
+  },
+  "name": "couch-login",
+  "description": "A module for doing logged-in requests to a couchdb server",
+  "version": "0.1.6",
+  "repository": {
+    "type": "git",
+    "url": "git://github.com/isaacs/couch-login.git"
+  },
+  "main": "couch-login.js",
+  "scripts": {
+    "test": "tap test/*.js"
+  },
+  "dependencies": {
+    "request": "~2.9.202"
+  },
+  "devDependencies": {
+    "tap": "~0.2.4"
+  },
+  "readme": "# couch-login\n\nThis module lets you log into couchdb to get a session token, then make\nrequests using that session.  It is basically just a thin wrapper around\n[@mikeal's request module](https://github.com/mikeal/request).\n\nThis is handy if you want a user to take actions in a couchdb database\non behalf of a user, without having to store their couchdb username and\npassword anywhere.  (You do need to store the AuthSession token\nsomewhere, though.)\n\n## Usage\n\n```javascript\nvar CouchLogin = require('couch-login')\n\n// Nothing about this module is http-server specific of course.\n// You could also use it to do authenticated requests against\n// a couchdb using sessions and storing the token somewhere else.\n\nhttp.createServer(function (req, res) {\n  var couch = new CouchLogin('http://my-couch.iriscouch.com:5984/')\n\n  // .. look up the token in the user's session or whatever ..\n  // Look at couch.decorate(req, res) for more on doing that\n  // automatically, below.\n\n  if (sessionToken) {\n    // this user already logged in.\n    couch.token = sessionToken\n\n    // now we can do things on their behalf, like:\n    // 1. View their session info.\n    // like doing request.get({ uri: couch + '/_session', ... })\n    // but with the cookie and whatnot\n\n    couch.get('/_session', function (er, resp, data) {\n      // er = some kind of communication error.\n      // resp = response object from the couchdb request.\n      // data = parsed JSON response body.\n      if (er || resp.statusCode !== 200) {\n        res.statusCode = resp.statusCode || 403\n        return res.end('Invalid login or something')\n      }\n\n      // now we have the session info, we know who this user is.\n      // hitting couchdb for this on every request is kinda costly,\n      // so maybe you should store the username wherever you're storing\n      // the sessionToken.  RedSess is a good util for this, if you're\n      // into redis.  And if you're not into redis, you're crazy,\n      // because it is awesome.\n\n      // now let's get the user record.\n      // note that this will 404 for anyone other than the user,\n      // unless they're a server admin.\n      couch.get('/_users/org.couchdb.user:' + data.userCtx.name, etc)\n\n      // PUTs and DELETEs will also use their session, of course, so\n      // your validate_doc_update's will see their info in userCtx\n    })\n\n  } else {\n    // don't have a sessionToken.\n    // get a username and password from the post body or something.\n    // maybe redirect to a /login page or something to ask for that.\n    var login = { name: name, password: password }\n    couch.login(login, function (er, resp, data) {\n      // again, er is an error, resp is the response obj, data is the json\n      if (er || resp.statusCode !== 200) {\n        res.statusCode = resp.statusCode || 403\n        return res.end('Invalid login or something')\n      }\n\n      // the data is something like\n      // {\"ok\":true,\"name\":\"testuser\",\"roles\":[]}\n      // and couch.token is the token you'll need to save somewhere.\n\n      // at this point, you can start making authenticated requests to\n      // couchdb, or save data in their session, or do whatever it is\n      // that you need to do.\n\n      res.statusCode = 200\n      res.write(\"Who's got two thumbs and just logged you into couch?\\n\")\n      setTimeout(function () {\n        res.end(\"THIS GUY!\")\n      }, 500)\n    })\n  }\n})\n```\n\n## Class: CouchLogin\n### new CouchLogin(couchdbUrl, token)\n\nCreate a new CouchLogin object bound to the couchdb url.\n\nIn addition to these, the `get`, `post`, `put`, and `del` methods all\nproxy to the associated method on [request](https://github.com/mikeal/request).\n\nHowever, as you'll note in the example above, only the pathname portion\nof the url is required.  Urls will be appended to the couchdb url passed\ninto the constructor.\n\nIf you have to talk to more than one couchdb, then you'll need more than\none CouchLogin object, for somewhat obvious reasons.\n\nAll callbacks get called with the following arguments, which are exactly\nidentical to the arguments passed to a `request` callback.\n\n* `er` {Error | null} Set if a communication error happens.\n* `resp` {HTTP Response} The response from the request to couchdb\n* `data` {Object} The parsed JSON data from couch\n\nIf the token is the string \"anonymous\", then it will not attempt to log\nin before making requests.  If the token is not \"anonymous\", then it\nmust be an object with the appropriate fields.\n\n### couch.token\n\n* {Object}\n\nAn object representing the couchdb session token.  (Basically just a\ncookie and a timeout.)\n\nIf the token has already timed out, then setting it will have no effect.\n\n### couch.tokenSet\n\nIf set, this method is called whenever the token is saved.\n\nFor example, you could assign a function to this method to save the\ntoken into a redis session, a cookie, or in some other database.\n\nTakes a callback which should be called when the token is saved.\n\n### couch.tokenGet\n\nIf set, this method is called to look up the token on demand.\n\nThe inverse of couch.tokenSet.  Takes a callback which is called with\nthe `cb(er || null, token)`.\n\n### couch.tokenDel\n\nIf set, this method is called to delete the token when it should be\ndiscarded.\n\nRelated to tokenGet and tokenSet.  Takes a callback which should be\ncalled when the token is deleted.\n\n### couch.anonymous()\n\nReturn a new CouchLogin object that points at the same couchdb server,\nbut doesn't try to log in before making requests.\n\nThis is handy for situations where the user is not logged in at the\nmoment, but a request needs to be made anyway, and does not require\nauthorization.\n\n### couch.login(auth, callback)\n\n* `auth` {Object} The login details\n  * `name` {String}\n  * `password` {String}\n* `callback` {Function}\n\nWhen the callback is called, the `couch.token` will already have been\nset (assuming it worked!), so subsequent requests will be done as that\nuser.\n\n### couch.get(path, callback)\n\nGET the supplied path from the couchdb using the credentials on the\ntoken.\n\nFails if the token is invalid or expired.\n\n### couch.del(path, callback)\n\nDELETE the supplied path from the couchdb using the credentials on the\ntoken.\n\nFails if the token is invalid or expired.\n\n### couch.post(path, data, callback)\n\nPOST the data to the supplied path in the couchdb, using the credentials\non the token.\n\nFails if the token is invalid or expired.\n\n### couch.put(path, data, callback)\n\nPUT the data to the supplied path in the couchdb, using the credentials\non the token.\n\nFails if the token is invalid or expired.\n\n### couch.changePass(newAuth, callback)\n\nMust already be logged in.  Updates the `_users` document with new salt\nand hash, and re-logs in with the new credentials.  Callback is called\nwith the same arguments as login, or the first step of the process that\nfailed.\n\n### couch.signup(userData, callback)\n\nCreate a new user account.  The userData must contain at least a `name`\nand `password` field.  Any additional data will be copied to the user\nrecord.  The `_id`, `name`, `roles`, `type`, `password_sha`, `salt`, and\n`date` fields are generated.\n\nAlso signs in as the newly created user, on successful account creation.\n\n### couch.deleteAccount(name, callback)\n\nDeletes a user account.  If not logged in as the user, or a server\nadmin, then the request will fail.\n\nNote that this immediately invalidates any session tokens for the\ndeleted user account.  If you are deleting the user's record, then you\nought to follow this with `couch.logout(callback)` so that it won't try\nto re-use the invalid session.\n\n### couch.logout(callback)\n\nDelete the session out of couchdb.  This makes the token permanently\ninvalid, and deletes it.\n\n### couch.decorate(req, res)\n\nSet up `req.couch` and `res.couch` as references to this couch login\ninstance.\n\nAdditionall, if `req.session` or `res.session` is set, then it'll call\n`session.get('couch_token', cb)` as the tokenGet method,\n`session.set('couch_token', token, cb)` as the tokenSet method, and\n`session.del('couch_token', cb)` as the tokenDel method.\n\nThis works really nice with\n[RedSess](https://github.com/isaacs/redsess).\n",
+  "_id": "couch-login@0.1.6",
+  "_from": "couch-login@~0.1.6"
+}
index ecbda31..856fc66 100644 (file)
@@ -151,14 +151,6 @@ if (constants.hasOwnProperty('O_SYMLINK') &&
 }
 
 
-// lstat on windows, missing from early 0.5 versions
-// replacing with stat isn't quite perfect, but good enough to get by.
-if (process.platform === "win32" && !process.binding("fs").lstat) {
-  fs.lstat = fs.stat
-  fs.lstatSync = fs.statSync
-}
-
-
 // lutimes implementation, or no-op
 if (!fs.lutimes) {
   if (constants.hasOwnProperty("O_SYMLINK")) {
@@ -255,6 +247,22 @@ function chownErOk (er) {
 }
 
 
+// if lchmod/lchown do not exist, then make them no-ops
+if (!fs.lchmod) {
+  fs.lchmod = function (path, mode, cb) {
+    process.nextTick(cb)
+  }
+  fs.lchmodSync = function () {}
+}
+if (!fs.lchown) {
+  fs.lchown = function (path, uid, gid, cb) {
+    process.nextTick(cb)
+  }
+  fs.lchownSync = function () {}
+}
+
+
+
 
 // on Windows, A/V software can lock the directory, causing this
 // to fail with an EACCES or EPERM if the directory contains newly
index 757d301..fe4de9e 100644 (file)
@@ -6,7 +6,7 @@
   },
   "name": "graceful-fs",
   "description": "fs monkey-patching to avoid EMFILE and other problems",
-  "version": "1.1.8",
+  "version": "1.1.9",
   "repository": {
     "type": "git",
     "url": "git://github.com/isaacs/node-graceful-fs.git"
     "node": ">=0.4.0"
   },
   "devDependencies": {},
-  "_npmUser": {
-    "name": "isaacs",
-    "email": "i@izs.me"
-  },
-  "_id": "graceful-fs@1.1.8",
-  "dependencies": {},
-  "optionalDependencies": {},
-  "_engineSupported": true,
-  "_npmVersion": "1.1.10",
-  "_nodeVersion": "v0.7.7-pre",
-  "_defaultsLoaded": true,
+  "readme": "Just like node's `fs` module, but it does an incremental back-off when\nEMFILE is encountered.\n\nUseful in asynchronous situations where one needs to try to open lots\nand lots of files.\n",
+  "_id": "graceful-fs@1.1.9",
   "_from": "graceful-fs@~1.1.1"
 }
index 7b7d621..1f0f2c0 100755 (executable)
@@ -25,8 +25,9 @@ if (prog.todo.length === 0) {
 }
 
 log.info('it worked if it ends with', 'ok')
+log.verbose('cli', process.argv)
 log.info('using', 'node-gyp@%s', prog.version)
-log.info('using', 'node@%s', process.versions.node)
+log.info('using', 'node@%s | %s | %s', process.versions.node, process.platform, process.arch)
 
 
 /**
@@ -61,7 +62,7 @@ function run () {
   if (prog.todo.length === 0) {
     // done!
     completed = true
-    log.info('done', 'ok')
+    log.info('ok')
     return
   }
   var command = prog.todo.shift()
index c29b97e..f38ec99 100644 (file)
@@ -6,19 +6,20 @@ module.exports = exports = build
  */
 
 var fs = require('graceful-fs')
+  , rm = require('rimraf')
   , path = require('path')
   , glob = require('glob')
   , log = require('npmlog')
   , which = require('which')
   , mkdirp = require('mkdirp')
   , win = process.platform == 'win32'
-  , openbsd = process.platform == 'openbsd'
 
 exports.usage = 'Invokes `' + (win ? 'msbuild' : 'make') + '` and builds the module'
 
 function build (gyp, argv, callback) {
 
-  var makeCommand = openbsd ? 'gmake' : 'make'
+  var makeCommand = gyp.opts.make || process.env.MAKE
+    || (process.platform.indexOf('bsd') != -1 ? 'gmake' : 'make')
   var command = win ? 'msbuild' : makeCommand
     , buildDir = path.resolve('build')
     , configPath = path.resolve(buildDir, 'config.gypi')
@@ -216,7 +217,47 @@ function build (gyp, argv, callback) {
     if (signal) {
       return callback(new Error('`' + command + '` got signal: ' + signal))
     }
+    //symlinkNodeBinding()
     callback()
   }
 
+  function symlinkNodeBinding () {
+    var buildDir = path.join('build', buildType, '*.node')
+    log.verbose('globbing for files', buildDir)
+    glob(buildDir, function (err, nodeFiles) {
+      if (err) return callback(err)
+      function link () {
+        var file = nodeFiles.shift()
+        if (!file) {
+          // no more files to link... done!
+          return callback()
+        }
+        var dest = path.join('build', path.basename(file))
+        log.info('symlink', 'creating link %j pointing to %j', file, dest)
+        var rel = path.relative('build', file)
+        log.verbose('symlink data', rel)
+        fs.symlink(rel, dest, 'file', function (err) {
+          if (err) {
+            if (err.code === 'EEXIST') {
+              log.verbose('destination already exists; deleting', dest)
+              rm(dest, function (err) {
+                if (err) return callback(err)
+                log.verbose('delete successful; trying symlink again')
+                nodeFiles.unshift(file)
+                link()
+              })
+            } else {
+              callback(err)
+            }
+            return
+          }
+          // process the next file, if any
+          link()
+        })
+      }
+      // start linking
+      link()
+    })
+  }
+
 }
index 1cdd320..3dbd418 100644 (file)
@@ -47,7 +47,7 @@ function configure (gyp, argv, callback) {
   // We're gonna glob C:\python2*
   function guessPython () {
     log.verbose('could not find "' + python + '". guessing location')
-    var rootDir = process.env.HOMEDRIVE || process.env.SystemDrive || 'C:\\'
+    var rootDir = process.env.SystemDrive || 'C:\\'
     if (rootDir[rootDir.length - 1] !== '\\') {
       rootDir += '\\'
     }
@@ -72,11 +72,21 @@ function configure (gyp, argv, callback) {
       if (err) {
         return callback(err)
       }
+      log.verbose('check python version', '`python --version` returned: %j', stderr)
       var version = stderr.trim().replace(/[^\d\.]+/g, '')
-      if (semver.lt(version, '3.0.0')) {
+      var numDots = 0
+      version.replace(/\./g, function () {
+        numDots++
+      })
+      while (numDots < 2) {
+        version += '.0'
+        numDots++
+      }
+      log.verbose('check python version', 'using version %j to check', version)
+      if (semver.gte(version, '2.5.0') && semver.lt(version, '3.0.0')) {
         getNodeDir()
       } else {
-        failPython3()
+        failPythonVersion(version)
       }
     })
   }
@@ -86,10 +96,10 @@ function configure (gyp, argv, callback) {
           + '", you can set the PYTHON env variable.'))
   }
 
-  function failPython3 () {
+  function failPythonVersion (badVersion) {
     callback(new Error('Python executable "' + python
-          + '" is Python 3, which is not supported.\n'
-          + 'You can set the PYTHON env variable to point to a Python 2 interpreter.'))
+          + '" is v' + badVersion + ', which is not supported by gyp.\n'
+          + 'You can pass the --python switch to point to Python >= v2.5.0 & < 3.0.0.'))
   }
 
   function getNodeDir () {
index 4932b8f..2bcc72b 100644 (file)
@@ -8,6 +8,7 @@ exports.usage = 'Install node development files for the specified node version.'
  */
 
 var fs = require('graceful-fs')
+  , osenv = require('osenv')
   , tar = require('tar')
   , rm = require('rimraf')
   , path = require('path')
@@ -41,7 +42,7 @@ function install (gyp, argv, callback) {
 
   // Determine which node dev files version we are installing
   var versionStr = argv[0] || gyp.opts.target || process.version
-  log.verbose('install', 'input version string', versionStr)
+  log.verbose('install', 'input version string %j', versionStr)
 
   // parse the version to normalize and ensure it's valid
   var version = semver.parse(versionStr)
@@ -57,11 +58,16 @@ function install (gyp, argv, callback) {
     return callback(new Error('Minimum target version is `0.6.0` or greater. Got: ' + versionStr))
   }
 
-  // 0.x.y-pre versions are not published yet. Use previous release.
+  // 0.x.y-pre versions are not published yet and cannot be installed. Bail.
   if (version[5] === '-pre') {
-    version[3] = +version[3] - 1
-    version[5] = null
-    log.verbose('-pre version detected, adjusting patch version')
+    log.verbose('detected "pre" node version', versionStr)
+    if (gyp.opts.nodedir) {
+      log.verbose('--nodedir flag was passed; skipping install', gyp.opts.nodedir)
+      callback()
+    } else {
+      callback(new Error('"pre" versions of node cannot be installed, use the --nodedir flag instead'))
+    }
+    return
   }
 
   // flatten version into String
@@ -107,12 +113,11 @@ function install (gyp, argv, callback) {
     go()
   }
 
-  function download (url, onError) {
+  function download (url) {
     log.http('GET', url)
 
     var requestOpts = {
         uri: url
-      , onResponse: true
     }
 
     // basic support for a proxy server
@@ -124,7 +129,7 @@ function install (gyp, argv, callback) {
       log.verbose('proxy', proxyUrl)
       requestOpts.proxy = proxyUrl
     }
-    var req = request(requestOpts, onError)
+    var req = request(requestOpts)
     req.on('response', function (res) {
       log.http(res.statusCode, url)
     })
@@ -133,181 +138,210 @@ function install (gyp, argv, callback) {
 
   function go () {
 
-  log.verbose('ensuring nodedir is created', devDir)
+    log.verbose('ensuring nodedir is created', devDir)
 
-  // first create the dir for the node dev files
-  mkdir(devDir, function (err, created) {
-    if (err) return cb(err)
-
-    if (created) {
-      log.verbose('created nodedir', created)
-    }
+    // first create the dir for the node dev files
+    mkdir(devDir, function (err, created) {
+      if (err) {
+        if (err.code == 'EACCES') {
+          // this EACCES fallback is a workaround for npm's `sudo` behavior, where
+          // it drops the permissions before invoking any child processes (like
+          // node-gyp). So what happens is the "nobody" user doesn't have
+          // permission to create the dev dir. As a fallback, make the tmpdir() be
+          // the dev dir for this installation. This is not ideal, but at least
+          // the compilation will succeed...
+          gyp.devDir = path.resolve(osenv.tmpdir(), '.node-gyp')
+          log.warn(err.code, 'user "%s" does not have permission to create dev dir "%s"', osenv.user(), devDir)
+          log.warn(err.code, 'attempting to reinstall using temporary dev dir "%s"', gyp.devDir)
+          gyp.commands.install(argv, cb)
+        } else {
+          cb(err)
+        }
+        return
+      }
 
-    // now download the node tarball
-    var tarballUrl = distUrl + '/v' + version + '/node-v' + version + '.tar.gz'
-      , badDownload = false
-      , extractCount = 0
-      , gunzip = zlib.createGunzip()
-      , extracter = tar.Extract({ path: devDir, strip: 1, filter: isValid })
-
-    // checks if a file to be extracted from the tarball is valid.
-    // only .h header files and the gyp files get extracted
-    function isValid () {
-      var name = this.path.substring(devDir.length + 1)
-      var isValid = valid(name)
-      if (name === '' && this.type === 'Directory') {
-        // the first directory entry is ok
-        return true
+      if (created) {
+        log.verbose('created nodedir', created)
       }
-      if (isValid) {
-        log.verbose('extracted file from tarball', name)
-        extractCount++
-      } else {
-        // invalid
-        log.silly('ignoring from tarball', name)
+
+      // now download the node tarball
+      var tarballUrl = distUrl + '/v' + version + '/node-v' + version + '.tar.gz'
+        , badDownload = false
+        , extractCount = 0
+        , gunzip = zlib.createGunzip()
+        , extracter = tar.Extract({ path: devDir, strip: 1, filter: isValid })
+
+      // checks if a file to be extracted from the tarball is valid.
+      // only .h header files and the gyp files get extracted
+      function isValid () {
+        var name = this.path.substring(devDir.length + 1)
+        var isValid = valid(name)
+        if (name === '' && this.type === 'Directory') {
+          // the first directory entry is ok
+          return true
+        }
+        if (isValid) {
+          log.verbose('extracted file from tarball', name)
+          extractCount++
+        } else {
+          // invalid
+          log.silly('ignoring from tarball', name)
+        }
+        return isValid
       }
-      return isValid
-    }
 
-    gunzip.on('error', cb)
-    extracter.on('error', cb)
-    extracter.on('end', afterTarball)
+      gunzip.on('error', cb)
+      extracter.on('error', cb)
+      extracter.on('end', afterTarball)
 
-    // download the tarball, gunzip and extract!
-    var req = download(tarballUrl, downloadError)
-      .pipe(gunzip)
-      .pipe(extracter)
+      // download the tarball, gunzip and extract!
+      var req = download(tarballUrl)
 
-    // something went wrong downloading the tarball?
-    function downloadError (err, res) {
-      if (err || res.statusCode != 200) {
+      // something went wrong downloading the tarball?
+      req.on('error', function (err) {
         badDownload = true
-        cb(err || new Error(res.statusCode + ' status code downloading tarball'))
-      }
-    }
+        cb(err)
+      })
 
-    // invoked after the tarball has finished being extracted
-    function afterTarball () {
-      if (badDownload) return
-      if (extractCount === 0) {
-        return cb(new Error('There was a fatal problem while downloading/extracting the tarball'))
-      }
-      log.verbose('tarball', 'done parsing tarball')
-      var async = 0
+      req.on('close', function () {
+        if (extractCount === 0) {
+          cb(new Error('Connection closed while downloading tarball file'))
+        }
+      })
 
-      if (isLegacy) {
-        // copy over the files from the `legacy` dir
-        async++
-        copyLegacy(deref)
-      }
+      req.on('response', function (res) {
+        if (res.statusCode !== 200) {
+          badDownload = true
+          cb(new Error(res.statusCode + ' status code downloading tarball'))
+          return
+        }
+        // start unzipping and untaring
+        req.pipe(gunzip).pipe(extracter)
+      })
 
-      if (win) {
-        // need to download node.lib
-        async++
-        downloadNodeLib(deref)
-      }
+      // invoked after the tarball has finished being extracted
+      function afterTarball () {
+        if (badDownload) return
+        if (extractCount === 0) {
+          return cb(new Error('There was a fatal problem while downloading/extracting the tarball'))
+        }
+        log.verbose('tarball', 'done parsing tarball')
+        var async = 0
 
-      // write the "installVersion" file
-      async++
-      var installVersionPath = path.resolve(devDir, 'installVersion')
-      fs.writeFile(installVersionPath, gyp.package.installVersion + '\n', deref)
+        if (isLegacy) {
+          // copy over the files from the `legacy` dir
+          async++
+          copyLegacy(deref)
+        }
 
-      if (async === 0) {
-        // no async tasks required
-        cb()
-      }
+        if (win) {
+          // need to download node.lib
+          async++
+          downloadNodeLib(deref)
+        }
 
-      function deref (err) {
-        if (err) return cb(err)
-        --async || cb()
-      }
-    }
+        // write the "installVersion" file
+        async++
+        var installVersionPath = path.resolve(devDir, 'installVersion')
+        fs.writeFile(installVersionPath, gyp.package.installVersion + '\n', deref)
 
-    function copyLegacy (done) {
-      // legacy versions of node (< 0.8) require the legacy files to be copied
-      // over since they contain many bugfixes from the current node build system
-      log.verbose('legacy', 'copying "legacy" gyp configuration files for version', version)
+        if (async === 0) {
+          // no async tasks required
+          cb()
+        }
 
-      var legacyDir = path.resolve(__dirname, '..', 'legacy')
-      log.verbose('legacy', 'using "legacy" dir', legacyDir)
-      log.verbose('legacy', 'copying to "dev" dir', devDir)
+        function deref (err) {
+          if (err) return cb(err)
+          --async || cb()
+        }
+      }
 
-      var reader = fstream.Reader({ path: legacyDir, type: 'Directory' })
-      var writer = fstream.Writer({ path: devDir, type: 'Directory' })
+      function copyLegacy (done) {
+        // legacy versions of node (< 0.8) require the legacy files to be copied
+        // over since they contain many bugfixes from the current node build system
+        log.verbose('legacy', 'copying "legacy" gyp configuration files for version', version)
 
-      reader.on('entry', function onEntry (entry) {
-        log.verbose('legacy', 'reading entry:', entry.path)
-        entry.on('entry', onEntry)
-      })
+        var legacyDir = path.resolve(__dirname, '..', 'legacy')
+        log.verbose('legacy', 'using "legacy" dir', legacyDir)
+        log.verbose('legacy', 'copying to "dev" dir', devDir)
 
-      reader.on('error', done)
-      writer.on('error', done)
+        var reader = fstream.Reader({ path: legacyDir, type: 'Directory' })
+        var writer = fstream.Writer({ path: devDir, type: 'Directory' })
 
-      // Like `cp -rpf`
-      reader.pipe(writer)
+        reader.on('entry', function onEntry (entry) {
+          log.verbose('legacy', 'reading entry:', entry.path)
+          entry.on('entry', onEntry)
+        })
 
-      reader.on('end', done)
-    }
+        reader.on('error', done)
+        writer.on('error', done)
 
-    function downloadNodeLib (done) {
-      log.verbose('on Windows; need to download `node.lib`...')
-      var dir32 = path.resolve(devDir, 'ia32')
-        , dir64 = path.resolve(devDir, 'x64')
-        , nodeLibPath32 = path.resolve(dir32, 'node.lib')
-        , nodeLibPath64 = path.resolve(dir64, 'node.lib')
-        , nodeLibUrl32 = distUrl + '/v' + version + '/node.lib'
-        , nodeLibUrl64 = distUrl + '/v' + version + '/x64/node.lib'
-
-      log.verbose('32-bit node.lib dir', dir32)
-      log.verbose('64-bit node.lib dir', dir64)
-      log.verbose('`node.lib` 32-bit url', nodeLibUrl32)
-      log.verbose('`node.lib` 64-bit url', nodeLibUrl64)
-
-      var async = 2
-      mkdir(dir32, function (err) {
-        if (err) return done(err)
-        log.verbose('streaming 32-bit node.lib to:', nodeLibPath32)
-
-        var req = download(nodeLibUrl32)
-        req.on('error', done)
-        req.on('response', function (res) {
-          if (res.statusCode !== 200) {
-            done(new Error(res.statusCode + ' status code downloading 32-bit node.lib'))
-          }
-        })
-        req.on('end', function () {
-          --async || done()
-        })
+        // Like `cp -rpf`
+        reader.pipe(writer)
 
-        var ws = fs.createWriteStream(nodeLibPath32)
-        ws.on('error', cb)
-        req.pipe(ws)
-      })
-      mkdir(dir64, function (err) {
-        if (err) return done(err)
-        log.verbose('streaming 64-bit node.lib to:', nodeLibPath64)
-
-        var req = download(nodeLibUrl64)
-        req.on('error', done)
-        req.on('response', function (res) {
-          if (res.statusCode !== 200) {
-            done(new Error(res.statusCode + ' status code downloading 64-bit node.lib'))
-          }
+        reader.on('end', done)
+      }
+
+      function downloadNodeLib (done) {
+        log.verbose('on Windows; need to download `node.lib`...')
+        var dir32 = path.resolve(devDir, 'ia32')
+          , dir64 = path.resolve(devDir, 'x64')
+          , nodeLibPath32 = path.resolve(dir32, 'node.lib')
+          , nodeLibPath64 = path.resolve(dir64, 'node.lib')
+          , nodeLibUrl32 = distUrl + '/v' + version + '/node.lib'
+          , nodeLibUrl64 = distUrl + '/v' + version + '/x64/node.lib'
+
+        log.verbose('32-bit node.lib dir', dir32)
+        log.verbose('64-bit node.lib dir', dir64)
+        log.verbose('`node.lib` 32-bit url', nodeLibUrl32)
+        log.verbose('`node.lib` 64-bit url', nodeLibUrl64)
+
+        var async = 2
+        mkdir(dir32, function (err) {
+          if (err) return done(err)
+          log.verbose('streaming 32-bit node.lib to:', nodeLibPath32)
+
+          var req = download(nodeLibUrl32)
+          req.on('error', done)
+          req.on('response', function (res) {
+            if (res.statusCode !== 200) {
+              done(new Error(res.statusCode + ' status code downloading 32-bit node.lib'))
+              return
+            }
+
+            var ws = fs.createWriteStream(nodeLibPath32)
+            ws.on('error', cb)
+            req.pipe(ws)
+          })
+          req.on('end', function () {
+            --async || done()
+          })
         })
-        req.on('end', function () {
-          --async || done()
+        mkdir(dir64, function (err) {
+          if (err) return done(err)
+          log.verbose('streaming 64-bit node.lib to:', nodeLibPath64)
+
+          var req = download(nodeLibUrl64)
+          req.on('error', done)
+          req.on('response', function (res) {
+            if (res.statusCode !== 200) {
+              done(new Error(res.statusCode + ' status code downloading 64-bit node.lib'))
+              return
+            }
+
+            var ws = fs.createWriteStream(nodeLibPath64)
+            ws.on('error', cb)
+            req.pipe(ws)
+          })
+          req.on('end', function () {
+            --async || done()
+          })
         })
+      } // downloadNodeLib()
 
-        var ws = fs.createWriteStream(nodeLibPath64)
-        ws.on('error', cb)
-        req.pipe(ws)
-      })
-    }
-
-
-  })
+    }) // mkdir()
 
-  }
+  } // go()
 
   /**
    * Checks if a given filename is "valid" for this installation.
index 61e9dd1..9b22825 100644 (file)
@@ -72,16 +72,17 @@ proto.package = require('../package')
  */
 
 proto.configDefs = {
-    help: Boolean    // everywhere
-  , arch: String     // 'configure'
-  , debug: Boolean   // 'build'
+    help: Boolean     // everywhere
+  , arch: String      // 'configure'
+  , debug: Boolean    // 'build'
   , directory: String // bin
+  , make: String      // 'build'
   , msvs_version: String // 'configure'
-  , ensure: Boolean  // 'install'
-  , solution: String // 'build' (windows only)
-  , proxy: String // 'install'
-  , nodedir: String // 'configure'
-  , loglevel: String // everywhere
+  , ensure: Boolean   // 'install'
+  , solution: String  // 'build' (windows only)
+  , proxy: String     // 'install'
+  , nodedir: String   // 'configure'
+  , loglevel: String  // everywhere
 }
 
 /**
index f3fc686..07c9178 100644 (file)
@@ -1,6 +1,6 @@
 {
   "name": "node-gyp",
-  "description": "`node-gyp` is a cross-platform command-line tool written in Node.js for compiling",
+  "description": "Node.js native addon build tool",
   "keywords": [
     "native",
     "addon",
@@ -10,7 +10,7 @@
     "bindings",
     "gyp"
   ],
-  "version": "0.5.2",
+  "version": "0.5.8",
   "installVersion": 9,
   "author": {
     "name": "Nathan Rajlich",
@@ -34,6 +34,7 @@
     "mkdirp": "0.3",
     "nopt": "1",
     "npmlog": "0",
+    "osenv": "0",
     "request": "2.9",
     "rimraf": "2",
     "semver": "1",
@@ -44,9 +45,9 @@
     "node": ">= 0.6.0"
   },
   "readme": "node-gyp\n=========\n### Node.js native addon build tool\n\n`node-gyp` is a cross-platform command-line tool written in Node.js for compiling\nnative addon modules for Node.js, which takes away the pain of dealing with the\nvarious differences in build platforms. It is the replacement to the `node-waf`\nprogram which is removed for node `v0.8`. If you have a native addon for node that\nstill has a `wscript` file, then you should definitely add a `binding.gyp` file\nto support the latest versions of node.\n\nMultiple target versions of node are supported (i.e. `0.6`, `0.7`,..., `1.0`,\netc.), regardless of what version of node is actually installed on your system\n(`node-gyp` downloads the necessary development files for the target version).\n\n#### Features:\n\n * Easy to use, consistent interface\n * Same commands to build your module on every platform\n * Supports multiple target versions of Node\n\n\nInstallation\n------------\n\nYou can install with `npm`:\n\n``` bash\n$ npm install -g node-gyp\n```\n\nYou will also need to install:\n\n  * On Unix:\n    * `python`\n    * `make`\n    * A proper C/C++ compiler toolchain, like GCC\n  * On Windows:\n    * [Python][windows-python] ([`v2.7.2`][windows-python-v2.7.2] recommended, `v3.x.x` not yet supported)\n    * Microsoft Visual C++ ([Express][msvc] version works well)\n      * For 64-bit builds of node and native modules you will _also_ need the [Windows 7 64-bit SDK][win7sdk]\n\nHow to Use\n----------\n\nTo compile your native addon, first go to its root directory:\n\n``` bash\n$ cd my_node_addon\n```\n\nThe next step is to generate the appropriate project build files for the current\nplatform. Use `configure` for that:\n\n``` bash\n$ node-gyp configure\n```\n\n__Note__: The `configure` step looks for the `binding.gyp` file in the current\ndirectory to processs. See below for instructions on creating the `binding.gyp` file.\n\nNow you will have either a `Makefile` (on Unix platforms) or a `vcxproj` file\n(on Windows) in the `build/` directory. Next invoke the `build` command:\n\n``` bash\n$ node-gyp build\n```\n\nNow you have your compiled `.node` bindings file! The compiled bindings end up\nin `build/Debug/` or `build/Release/`, depending on the build mode. At this point\nyou can require the `.node` file with Node and run your tests!\n\n__Note:__ To create a _Debug_ build of the bindings file, pass the `--debug` (or\n`-d`) switch when running the either `configure` or `build` command.\n\n\nThe \"binding.gyp\" file\n----------------------\n\nPreviously when node had `node-waf` you had to write a `wscript` file. The\nreplacement for that is the `binding.gyp` file, which describes the configuration\nto build your module in a JSON-like format. This file gets placed in the root of\nyour package, alongside the `package.json` file.\n\nA barebones `gyp` file appropriate for building a node addon looks like:\n\n``` json\n{\n  \"targets\": [\n    {\n      \"target_name\": \"binding\",\n      \"sources\": [ \"src/binding.cc\" ]\n    }\n  ]\n}\n```\n\nSome additional resources for writing `gyp` files:\n\n * [\"Hello World\" node addon example](https://github.com/joyent/node/tree/master/test/addons/hello-world)\n * [gyp user documentation](http://code.google.com/p/gyp/wiki/GypUserDocumentation)\n * [gyp input format reference](http://code.google.com/p/gyp/wiki/InputFormatReference)\n * ['\"binding.gyp\" files out in the wild' wiki page](https://github.com/TooTallNate/node-gyp/wiki/%22binding.gyp%22-files-out-in-the-wild)\n\n\nCommands\n--------\n\n`node-gyp` responds to the following commands:\n\n * `build` - Invokes `make`/`msbuild.exe` and builds the native addon\n * `clean` - Removes any generated project files and the `out` dir\n * `configure` - Generates project build files for the current platform\n * `rebuild` - Runs \"clean\", \"configure\" and \"build\" all at once\n * `install` - Installs node development files for the given version.\n * `list` - Lists the currently installed node development file versions\n * `remove` - Removes a node development files for a given version\n\n\nLicense\n-------\n\n(The MIT License)\n\nCopyright (c) 2012 Nathan Rajlich &lt;nathan@tootallnate.net&gt;\n\nPermission is hereby granted, free of charge, to any person obtaining\na copy of this software and associated documentation files (the\n'Software'), to deal in the Software without restriction, including\nwithout limitation the rights to use, copy, modify, merge, publish,\ndistribute, sublicense, and/or sell copies of the Software, and to\npermit persons to whom the Software is furnished to do so, subject to\nthe following conditions:\n\nThe above copyright notice and this permission notice shall be\nincluded in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,\nEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\nMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\nIN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\nCLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\nTORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\nSOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n\n[windows-python]: http://www.python.org/getit/windows\n[windows-python-v2.7.2]: http://www.python.org/download/releases/2.7.2#download\n[msvc]: http://www.microsoft.com/visualstudio/en-us/products/2010-editions/visual-cpp-express\n[win7sdk]: http://www.microsoft.com/download/en/details.aspx?displayLang=en&id=8279\n",
-  "_id": "node-gyp@0.5.2",
+  "_id": "node-gyp@0.5.8",
   "dist": {
-    "shasum": "7410e3dd9d950592ee80d09c7e5ef22286f79c0f"
+    "shasum": "2e6cdb28159c9bdd3fe484c7db81f119ee17e594"
   },
-  "_from": "node-gyp@0.5.2"
+  "_from": "node-gyp@~0.5"
 }
index 673789f..c7bc21e 100644 (file)
@@ -6,24 +6,34 @@ module.exports = RegClient
 var fs = require('fs')
 , url = require('url')
 , path = require('path')
+, CouchLogin = require('couch-login')
 , npmlog
 
 try {
   npmlog = require("npmlog")
 } catch (er) {
   npmlog = { error: noop, warn: noop, info: noop,
-             verbose: noop, silly: noop, http: silly,
+             verbose: noop, silly: noop, http: noop,
              pause: noop, resume: noop }
 }
 
 function noop () {}
 
 function RegClient (options) {
-  // a registry url must be provided.
-  var registry = url.parse(options.registry)
-  if (!registry.protocol) throw new Error(
-    'Invalid registry: ' + registry.url)
-  this.registry = registry.href
+  // if provided, then the registry needs to be a url.
+  // if it's not provided, then we're just using the cache only.
+  var registry = options.registry
+  if (registry) {
+    registry = url.parse(registry)
+    if (!registry.protocol) throw new Error(
+      'Invalid registry: ' + registry.url)
+    this.registry = registry.href
+    if (this.registry.slice(-1) !== '/') {
+      this.registry += '/'
+    }
+  } else {
+    this.registry = null
+  }
 
   this.retries = options.retries || 2
   this.retryFactor = options.retryFactor || 10
@@ -41,7 +51,25 @@ function RegClient (options) {
     a = a.split(":")
     this.username = a.shift()
     this.password = a.join(":")
+  } else {
+    this.username = options.username
+    this.password = options.password
+
+    // if username and password are set, but auth isn't, use them.
+    if (this.username && this.password) {
+      var a = this.username + ":" + this.password
+      this.auth = new Buffer(a, "utf8").toString("base64")
+    }
+  }
+
+  if (this.auth && !this.alwaysAuth && this.registry) {
+    // if we're always authing, then we just send the
+    // user/pass on every thing.  otherwise, create a
+    // session, and use that.
+    this.token = options.token
+    this.couchLogin = new CouchLogin(this.registry, this.token)
   }
+
   this.email = options.email || null
   this.defaultTag = options.tag || "latest"
 
index b56fefc..835eb4c 100644 (file)
@@ -15,6 +15,8 @@ function get (uri, timeout, nofollow, staleOk, cb) {
   timeout = Math.min(timeout, this.cacheMax)
   timeout = Math.max(timeout, this.cacheMin)
 
+  if (!this.registry) timeout = Infinity
+
   if ( process.env.COMP_CWORD !== undefined
     && process.env.COMP_LINE !== undefined
     && process.env.COMP_POINT !== undefined
index 1c6eb35..384b0d8 100644 (file)
@@ -13,6 +13,9 @@ function regRequest (method, where, what, etag, nofollow, cb_) {
   if (typeof cb_ !== "function") cb_ = etag, etag = null
   if (typeof cb_ !== "function") cb_ = what, what = null
 
+  if (!this.registry) return cb(new Error(
+    "No registry url provided: " + method + " " + where))
+
   // Since there are multiple places where an error could occur,
   // don't let the cb be called more than once.
   var errState = null
@@ -29,11 +32,12 @@ function regRequest (method, where, what, etag, nofollow, cb_) {
   var registry = this.registry
 
   var adduserChange = /^\/?-\/user\/org\.couchdb\.user:([^\/]+)\/-rev/
-    , adduserNew = /^\/?-\/user\/org\.couchdb\.user:([^\/]+)/
-    , authRequired = (what || this.alwaysAuth)
-                      && !where.match(adduserNew)
-                   || where.match(adduserChange)
-                   || method === "DELETE"
+  , adduserNew = /^\/?-\/user\/org\.couchdb\.user:([^\/]+)/
+  , nu = where.match(adduserNew)
+  , uc = where.match(adduserChange)
+  , isUpload = what || this.alwaysAuth
+  , isDel = method === "DELETE"
+  , authRequired = isUpload && !nu || uc || isDel
 
   // resolve to a full url on the registry
   if (!where.match(/^https?:\/\//)) {
@@ -58,20 +62,39 @@ function regRequest (method, where, what, etag, nofollow, cb_) {
   }
 
   var remote = url.parse(where)
-    , auth = authRequired && this.auth
-
-  if (authRequired && !auth && this.username && this.password) {
-    var a = this.username + ":" + this.password
-    a = new Buffer(a, "utf8").toString("base64")
-    auth = this.auth = a
+  , auth = this.auth
+
+  if (authRequired && !this.alwaysAuth) {
+    var couch = this.couchLogin
+    , token = couch && (this.token || couch.token)
+    , validToken = token && couch.valid(token)
+
+    if (!validToken) token = null
+    else this.token = token
+
+    if (couch && !token) {
+      // login to get a valid token
+      var a = { name: this.username, password: this.password }
+      var args = arguments
+      return this.couchLogin.login(a, function (er, cr, data) {
+        if (er || !couch.valid(couch.token)) {
+          er = er || new Error('login error')
+          return cb(er, cr, data)
+        }
+        this.token = this.couchLogin.token
+        return regRequest.call(this, method, where, what, etag, nofollow, cb_)
+      }.bind(this))
+    }
   }
 
-  if (authRequired && !auth) {
+  // now we either have a valid token, or an auth.
+
+  if (authRequired && !auth && !token) {
     return cb(new Error(
       "Cannot insert data into the registry without auth"))
   }
 
-  if (auth) {
+  if (auth && !token) {
     remote.auth = new Buffer(auth, "base64").toString("utf8")
   }
 
@@ -87,7 +110,7 @@ function regRequest (method, where, what, etag, nofollow, cb_) {
   operation.attempt(function (currentAttempt) {
     self.log.info("retry", "registry request attempt " + currentAttempt
         + " at " + (new Date()).toLocaleTimeString())
-    makeRequest.call(self, method, remote, where, what, etag, nofollow
+    makeRequest.call(self, method, remote, where, what, etag, nofollow, token
                      , function (er, parsed, raw, response) {
       // Only retry on 408, 5xx or no `response`.
       var statusCode = response && response.statusCode
@@ -101,7 +124,7 @@ function regRequest (method, where, what, etag, nofollow, cb_) {
   })
 }
 
-function makeRequest (method, remote, where, what, etag, nofollow, cb_) {
+function makeRequest (method, remote, where, what, etag, nofollow, tok, cb_) {
   var cbCalled = false
   function cb () {
     if (cbCalled) return
@@ -112,7 +135,6 @@ function makeRequest (method, remote, where, what, etag, nofollow, cb_) {
   var opts = { url: remote
              , method: method
              , ca: this.ca
-             , follow: false
              , strictSSL: this.strictSSL }
     , headers = opts.headers = {}
   if (etag) {
@@ -120,6 +142,10 @@ function makeRequest (method, remote, where, what, etag, nofollow, cb_) {
     headers[method === "GET" ? "if-none-match" : "if-match"] = etag
   }
 
+  if (tok) {
+    headers.cookie = 'AuthSession=' + tok.AuthSession
+  }
+
   headers.accept = "application/json"
 
   headers["user-agent"] = this.userAgent
index 08ecd7e..47b6dc4 100644 (file)
@@ -6,7 +6,7 @@
   },
   "name": "npm-registry-client",
   "description": "Client for the npm registry",
-  "version": "0.0.8",
+  "version": "0.0.10",
   "repository": {
     "url": "git://github.com/isaacs/npm-registry-client"
   },
@@ -24,6 +24,7 @@
     "mkdirp": "~0.3.3",
     "rimraf": "~2.0.1",
     "retry": "0.6.0",
+    "couch-login": "~0.1.6",
     "npmlog": ""
   },
   "devDependencies": {
@@ -34,6 +35,6 @@
   },
   "license": "BSD",
   "readme": "# npm-registry-client\n\nThe code that npm uses to talk to the registry.\n\nIt handles all the caching and HTTP calls.\n\n## Usage\n\n```javascript\nvar RegClient = require('npm-registry-client')\nvar client = new RegClient(options)\n\nclient.get(\"npm\", \"latest\", 1000, function (er, data, raw, res) {\n  // error is an error if there was a problem.\n  // data is the parsed data object\n  // raw is the json string\n  // res is the response from couch\n})\n```\n\n# Options\n\n* `registry` **Required** {String} URL to the registry\n* `cache` **Required** {String} Path to the cache folder\n* `alwaysAuth` {Boolean} Auth even for GET requests.\n* `auth` {String} A base64-encoded `username:password`\n* `email` {String} User's email address\n* `tag` {String} The default tag to use when publishing new packages.\n  Default = `\"latest\"`\n* `ca` {String} Cerficate signing authority certificates to trust.\n* `strictSSL` {Boolean} Whether or not to be strict with SSL\n  certificates.  Default = `true`\n* `userAgent` {String} User agent header to send.  Default =\n  `\"node/{process.version}\"`\n* `log` {Object} The logger to use.  Defaults to `require(\"npmlog\")` if\n  that works, otherwise logs are disabled.\n* `retries` {Number} Number of times to retry on GET failures.\n  Default=2\n* `retryFactor` {Number} `factor` setting for `node-retry`. Default=10\n* `retryMinTimeout` {Number} `minTimeout` setting for `node-retry`.\n  Default=10000 (10 seconds)\n* `retryMaxTimeout` {Number} `maxTimeout` setting for `node-retry`.\n  Default=60000 (60 seconds)\n\n# client.request(method, where, [what], [etag], [nofollow], cb)\n\n* `method` {String} HTTP method\n* `where` {String} Path to request on the server\n* `what` {Stream | Buffer | String | Object} The request body.  Objects\n  that are not Buffers or Streams are encoded as JSON.\n* `etag` {String} The cached ETag\n* `nofollow` {Boolean} Prevent following 302/301 responses\n* `cb` {Function}\n  * `error` {Error | null}\n  * `data` {Object} the parsed data object\n  * `raw` {String} the json\n  * `res` {Response Object} response from couch\n\nMake a request to the registry.  All the other methods are wrappers\naround this. one.\n\n# client.adduser(username, password, email, cb)\n\n* `username` {String}\n* `password` {String}\n* `email` {String}\n* `cb` {Function}\n\nAdd a user account to the registry, or verify the credentials.\n\n# client.get(url, [timeout], [nofollow], [staleOk], cb)\n\n* `url` {String} The url path to fetch\n* `timeout` {Number} Number of seconds old that a cached copy must be\n  before a new request will be made.\n* `nofollow` {Boolean} Do not follow 301/302 responses\n* `staleOk` {Boolean} If there's cached data available, then return that\n  to the callback quickly, and update the cache the background.\n\nFetches data from the registry via a GET request, saving it in\nthe cache folder with the ETag.\n\n# client.publish(data, tarball, [readme], cb)\n\n* `data` {Object} Package data\n* `tarball` {String | Stream} Filename or stream of the package tarball\n* `readme` {String} Contents of the README markdown file\n* `cb` {Function}\n\nPublish a package to the registry.\n\nNote that this does not create the tarball from a folder.  However, it\ncan accept a gzipped tar stream or a filename to a tarball.\n\n# client.star(package, starred, cb)\n\n* `package` {String} Name of the package to star\n* `starred` {Boolean} True to star the package, false to unstar it.\n* `cb` {Function}\n\nStar or unstar a package.\n\nNote that the user does not have to be the package owner to star or\nunstar a package, though other writes do require that the user be the\npackage owner.\n\n# client.tag(project, version, tag, cb)\n\n* `project` {String} Project name\n* `version` {String} Version to tag\n* `tag` {String} Tag name to apply\n* `cb` {Function}\n\nMark a version in the `dist-tags` hash, so that `pkg@tag`\nwill fetch the specified version.\n\n# client.unpublish(name, [ver], cb)\n\n* `name` {String} package name\n* `ver` {String} version to unpublish. Leave blank to unpublish all\n  versions.\n* `cb` {Function}\n\nRemove a version of a package (or all versions) from the registry.  When\nthe last version us unpublished, the entire document is removed from the\ndatabase.\n\n# client.upload(where, file, [etag], [nofollow], cb)\n\n* `where` {String} URL path to upload to\n* `file` {String | Stream} Either the filename or a readable stream\n* `etag` {String} Cache ETag\n* `nofollow` {Boolean} Do not follow 301/302 responses\n* `cb` {Function}\n\nUpload an attachment.  Mostly used by `client.publish()`.\n",
-  "_id": "npm-registry-client@0.0.8",
+  "_id": "npm-registry-client@0.0.10",
   "_from": "npm-registry-client@0"
 }
index e147c24..c3b3000 100644 (file)
@@ -1,6 +1,6 @@
 {
   "name": "read-package-json",
-  "version": "0.0.12",
+  "version": "0.1.1",
   "author": {
     "name": "Isaac Z. Schlueter",
     "email": "i@izs.me",
@@ -31,6 +31,6 @@
     "graceful-fs": "~1.1.8"
   },
   "readme": "# read-package-json\n\nThis is the thing that npm uses to read package.json files.  It\nvalidates some stuff, and loads some default things.\n\nIt keeps a cache of the files you've read, so that you don't end\nup reading the same package.json file multiple times.\n\nNote that if you just want to see what's literally in the package.json\nfile, you can usually do `var data = require('some-module/package.json')`.\n\nThis module is basically only needed by npm, but it's handy to see what\nnpm will see when it looks at your package.\n\n## Usage\n\n```javascript\nvar readJson = require('read-package-json')\n\nreadJson('/path/to/package.json', function (er, data) {\n  if (er) {\n    console.error(\"There was an error reading the file\")\n    return\n  }\n\n  console.error('the package data is', data)\n}\n```\n\n## readJson(file, cb)\n\n* `file` {String} The path to the package.json file\n* `cb` {Function}\n\nReads the JSON file and does the things.\n\n## `package.json` Fields\n\nSee `man 5 package.json` or `npm help json`.\n\n## readJson.log\n\nBy default this is a reference to the `npmlog` module.  But if that\nmodule can't be found, then it'll be set to just a dummy thing that does\nnothing.\n\nReplace with your own `{log,warn,error}` object for fun loggy time.\n\n## readJson.extras(file, data, cb)\n\nRun all the extra stuff relative to the file, with the parsed data.\n\nModifies the data as it does stuff.  Calls the cb when it's done.\n\n## readJson.extraSet = [fn, fn, ...]\n\nArray of functions that are called by `extras`.  Each one receives the\narguments `fn(file, data, cb)` and is expected to call `cb(er, data)`\nwhen done or when an error occurs.\n\nOrder is indeterminate, so each function should be completely\nindependent.\n\nMix and match!\n\n## readJson.cache\n\nThe `lru-cache` object that readJson uses to not read the same file over\nand over again.  See\n[lru-cache](https://github.com/isaacs/node-lru-cache) for details.\n\n## Other Relevant Files Besides `package.json`\n\nSome other files have an effect on the resulting data object, in the\nfollowing ways:\n\n### `README?(.*)`\n\nIf there is a `README` or `README.*` file present, then npm will attach\na `readme` field to the data with the contents of this file.\n\nOwing to the fact that roughly 100% of existing node modules have\nMarkdown README files, it will generally be assumed to be Markdown,\nregardless of the extension.  Please plan accordingly.\n\n### `server.js`\n\nIf there is a `server.js` file, and there is not already a\n`scripts.start` field, then `scripts.start` will be set to `node\nserver.js`.\n\n### `AUTHORS`\n\nIf there is not already a `contributors` field, then the `contributors`\nfield will be set to the contents of the `AUTHORS` file, split by lines,\nand parsed.\n\n### `bindings.gyp`\n\nIf a bindings.gyp file exists, and there is not already a\n`scripts.install` field, then the `scripts.install` field will be set to\n`node-gyp rebuild`.\n\n### `wscript`\n\nIf a wscript file exists, and there is not already a `scripts.install`\nfield, then the `scripts.install` field will be set to `node-waf clean ;\nnode-waf configure build`.\n\nNote that the `bindings.gyp` file supercedes this, since node-waf has\nbeen deprecated in favor of node-gyp.\n\n### `index.js`\n\nIf the json file does not exist, but there is a `index.js` file\npresent instead, and that file has a package comment, then it will try\nto parse the package comment, and use that as the data instead.\n\nA package comment looks like this:\n\n```javascript\n/**package\n * { \"name\": \"my-bare-module\"\n * , \"version\": \"1.2.3\"\n * , \"description\": \"etc....\" }\n **/\n\n// or...\n\n/**package\n{ \"name\": \"my-bare-module\"\n, \"version\": \"1.2.3\"\n, \"description\": \"etc....\" }\n**/\n```\n\nThe important thing is that it starts with `/**package`, and ends with\n`**/`.  If the package.json file exists, then the index.js is not\nparsed.\n\n### `{directories.man}/*.[0-9]`\n\nIf there is not already a `man` field defined as an array of files or a\nsingle file, and\nthere is a `directories.man` field defined, then that directory will\nbe searched for manpages.\n\nAny valid manpages found in that directory will be assigned to the `man`\narray, and installed in the appropriate man directory at package install\ntime, when installed globally on a Unix system.\n\n### `{directories.bin}/*`\n\nIf there is not already a `bin` field defined as a string filename or a\nhash of `<name> : <filename>` pairs, then the `directories.bin`\ndirectory will be searched and all the files within it will be linked as\nexecutables at install time.\n\nWhen installing locally, npm links bins into `node_modules/.bin`, which\nis in the `PATH` environ when npm runs scripts.  When\ninstalling globally, they are linked into `{prefix}/bin`, which is\npresumably in the `PATH` environment variable.\n",
-  "_id": "read-package-json@0.0.12",
-  "_from": "read-package-json@0"
+  "_id": "read-package-json@0.1.1",
+  "_from": "read-package-json@~0.1.0"
 }
index ec3bf70..bb1c952 100644 (file)
@@ -223,7 +223,8 @@ function readmeDescription (file, data) {
 function readme (file, data, cb) {
                 if (data.readme) return cb(null, data);
                 var dir = path.dirname(file)
-                glob("README?(.*)", { cwd: dir }, function (er, files) {
+                var globOpts = { cwd: dir, nocase: true }
+                glob("README?(.*)", globOpts, function (er, files) {
                                 if (er) return cb(er);
                                 if (!files.length) return cb()
                                 var rm = path.resolve(dir, files[0])
@@ -340,6 +341,13 @@ function typoWarn (file, data) {
                 })
                 bugsTypoWarn(file, data)
                 scriptTypoWarn(file, data)
+                noreadmeWarn(file, data)
+}
+
+function noreadmeWarn (file, data) {
+                if (data.readme) return;
+                warn(file, data, "No README.md file found!")
+                data.readme = "ERROR: No README.md file found!"
 }
 
 function checkTypo (file, data, d) {
index 3ead8aa..1ef86b8 100644 (file)
@@ -1,5 +1,5 @@
 {
-  "version": "1.1.36",
+  "version": "1.1.39",
   "name": "npm",
   "publishConfig": {
     "proprietary-attribs": false
     "npmlog": "0",
     "ansi": "~0.1.2",
     "npm-registry-client": "0",
-    "read-package-json": "0",
+    "read-package-json": "~0.1.1",
     "read-installed": "0",
     "glob": "~3.1.9",
     "init-package-json": "0",
     "osenv": "0",
     "lockfile": ">=0.2",
-    "retry": "~0.6.0"
+    "retry": "~0.6.0",
+    "couch-login": "~0.1.6"
   },
   "bundleDependencies": [
     "semver",
     "init-package-json",
     "osenv",
     "lockfile",
-    "retry"
+    "retry",
+    "couch-login"
   ],
   "devDependencies": {
     "ronn": "https://github.com/isaacs/ronnjs/tarball/master",
     "tap": "~0.2.5"
   },
   "engines": {
-    "node": "0.6 || 0.7 || 0.8",
+    "node": ">0.6",
     "npm": "1"
   },
   "scripts": {