Browse files

Initial drop. Ugly, sketchy, and not even yet quite a "work in progre…

…ss".
  • Loading branch information...
0 parents commit 4626dfa73b7847e9c42c1f799935f8242794d020 isaacs committed Sep 29, 2009
Showing with 288 additions and 0 deletions.
  1. +61 −0 README.md
  2. +3 −0 install.js
  3. +77 −0 npm.js
  4. +5 −0 sources.json
  5. +96 −0 src/bootstrap.js
  6. +46 −0 src/queue.js
61 README.md
@@ -0,0 +1,61 @@
+# npm – The Node Package Manager
+
+npm is a little package manager for the Node javascript library.
+
+## 5-Second(ish) Install
+
+You should already have node installed and working. If you don't, go do that first.
+
+Then, come back here, and run:
+
+ ./install.js
+
+and it'll install itself and its requirements.
+
+## Commands
+
+You can get more details on any of these by doing `npm <command> --help`. Here are the basics.
+
+All flags with two hyphens can be abbreviated to a single hyphen with the first letter, so you can also do `npm <command> -h` to get its info.
+
+All commands return 0 if they succeed, and usually 1 if they don't. Normal output is on stdout, and oddness goes to stderr. Use the `--verbose` flag with any command to send extra debugging output to stderr.
+
+### Managing Sources
+
+npm learns all it knows about packages by looking at the JSON files specified in its catalog list. Manage this catalog list via the `npm source` commands.
+
+### Update Package Metadata
+
+Fetch the latest info from every source by doing `npm refresh`. Throw a `--force` on there if you want to clear the cache first.
+
+It's a good idea to update every so often, maybe even put it on a weekly cron or something.
+
+ @TODO: Keep track of which packages were updated, and then
+ add them to an "outdated" list. Then, `npm update` could
+ be an alias to `npm refresh && npm install --force --outdated`
+
+### Update Package Code
+
+Version numbers aren't yet supported, so npm can't tell when a package has new code for you. If you know that it does, you can do `npm install --force <package>` to force-install the latest version.
+
+### Find a Package
+
+Find a package in the list by doing `npm search <string>`. If you only want to search through installed packages, then do `npm search --installed <string>`. If you only want to search through activated packages, then do `npm search --active <string>`.
+
+### Activating/Deactivating Packages
+
+Use `npm activate <package>`. Note that installing a package activates it by default, and uninstalling it deactivates it first.
+
+### Starting/stopping Packages
+
+Some packages are servers and the like that must be activated after being installed. To do this, do `npm start <package>`. To stop it, do `npm stop <package>`.
+
+### Remove a Package
+
+You can uninstall a package by doing `npm remove <package>`. This will first `stop` it if it's running, then remove its files from your system.
+
+## Setting Defaults and Aliases via `$HOME/.npmrc`
+
+Gee, it'd sure be nice to be able to have a `$HOME/.npmrc` file that could maybe pre-fix some of these options, dotcha think?
+
+Write it, and send me a pull request, kthx.
3 install.js
@@ -0,0 +1,3 @@
+#!/usr/bin/env node
+
+setTimeout(require("./src/bootstrap.js").bootstrap);
77 npm.js
@@ -0,0 +1,77 @@
+// the main guts
+
+var npm = exports,
+ queue = require("./src/queue.js").queue,
+ http = require("/http.js");
+
+include("/utils.js");
+
+npm.install = function npm_install () {
+ return dummyPromise()
+};
+
+npm.refresh = function npm_refresh () {
+ // return dummyPromise()
+ // get my list of sources.
+ var p = new node.Promise();
+ npm.getSources().addCallback(function (srcArr) {
+ queue(srcArr, function (src) {
+ return npm.refreshSource(src)
+ }).addCallback(function () {
+ p.emitSuccess();
+ }).addErrback(function () {
+ p.emitError();
+ });
+ });
+ return p;
+};
+
+npm.getSources = function npm_getSources () {
+ var p = new node.Promise();
+ node.fs.cat(node.path.join(ENV.HOME, ".npm", "sources.json"))
+ .addErrback(function () {
+ p.emitError(new Error(
+ "Couldn't read " + node.path.join(ENV.HOME, ".npm", "sources.json") + "\n"
+ ));
+ })
+ .addCallback(function (data) {
+ try {
+ data = JSON.parse(data);
+ if (data) p.emitSuccess(data);
+ } catch (ex) { p.emitError(ex); return; }
+ });
+ return p;
+};
+
+npm.refreshSource = function npm_refreshSource (src) {
+ debug("refresh the source: "+src);
+
+ var p = new node.Promise();
+
+ // var u = http.parseUri(src);
+ // var httpClient = http.createClient(uri.port || 80, uri.host);
+ // client.get(uri.path || "/", headers || {})
+
+ http.cat(src, "utf-8", { "User-Agent" : "nodejs" })
+ .addCallback(function (data) {
+ debug("do something");
+ p.emitSuccess(data);
+ })
+ .addErrback(function (er) {
+ debug("error "+JSON.stringify(er)+ " " + JSON.stringify(res));
+ p.emitError(er);
+ });
+
+ return p;
+};
+
+function dummyPromise (name) {
+ var promise = new node.Promise();
+ name = name || arguments.callee.caller.name;
+ setTimeout(function () {
+ node.stdio.writeError("TODO: implement "+ name + "\n");
+ promise.emitSuccess("dummy");
+ });
+ return promise;
+};
+
5 sources.json
@@ -0,0 +1,5 @@
+[
+ "http://localhost/dev/sandbox/phpinfo.php",
+ "../npm-data/catalog.json",
+ "http://github.com/isaacs/npm-data/raw/master/catalog.json"
+]
96 src/bootstrap.js
@@ -0,0 +1,96 @@
+include("/utils.js");
+
+var npmDir = node.path.dirname(node.path.dirname(__filename)),
+ HOME = ENV.HOME,
+ npm = require("../npm.js"),
+ queuePromise = new node.Promise();
+
+exports.bootstrap = function bootstrap () {
+ node.stdio.writeError("npm: bootstrapping\n");
+ queuePromise.addCallback(function () {
+ node.stdio.write("ok");
+ });
+ next();
+}
+
+function statTester (thing, test, success, failure) {
+ return function () {
+ node.fs.stat(thing).addCallback(function (stats) {
+ return (stats[test]()) ? success.apply(this, arguments)
+ : failure.apply(this, arguments);
+ }).addErrback(failure);
+ };
+};
+// mkdir if not already existent.
+// Doesn't handle mkdir -p, which would be nice, but is not necessary for this
+function dirMaker (dir, mode, success, failure) {
+ return statTester(dir, "isDirectory", success, function () {
+ node.fs.mkdir(dir, mode).addErrback(failure).addCallback(success);
+ });
+};
+
+function fail (msg) { return function () {
+ node.stdio.writeError("npm bootstrap failed: "+msg);
+}}
+
+function next () {
+ return script.shift()();
+}
+
+function done () {
+ queuePromise.emitSuccess();
+}
+
+
+var script = [
+ // make sure that the ~/.node_libraries and ~/.npm exist.
+ dirMaker(node.path.join(HOME, ".node_libraries"), 0755, next, fail(
+ "couldn't create " + node.path.join(HOME, ".node_libraries")
+ )),
+ dirMaker(node.path.join(HOME, ".npm"), 0755, next, fail(
+ "couldn't create " + node.path.join(HOME, ".npm")
+ )),
+
+ // If no in ~/.npm/sources.json, then copy over the local one
+ statTester(
+ node.path.join(HOME, ".npm", "sources.json"), "isFile", next,
+ function () {
+ // try to copy the file over.
+ // seems like there outta be a node.fs.cp
+ node.fs.cat(
+ node.path.join(npmDir, "sources.json")
+ ).addErrback(fail(
+ "couldn't read " + node.path.join(npmDir, "sources.json")
+ )).addCallback(function (content) {
+ node.fs.open(
+ node.path.join(HOME, ".npm", "sources.json"),
+ node.O_WRONLY | node.O_TRUNC | node.O_CREAT,
+ 0666
+ ).addErrback(fail(
+ "couldn't open "+node.path.join(HOME, ".npm", "sources.json")+" for writing"
+ )).addCallback(function (fd) {
+ node.fs.write(fd, content, 0).addErrback(fail(
+ "couldn't write to "+node.path.join(HOME, ".npm", "sources.json")
+ )).addCallback(next);
+ });
+ });
+ }
+ ),
+
+ // call npm.refresh()
+ function () {
+ npm.refresh().addErrback(fail(
+ "Failed calling npm.refresh()"
+ )).addCallback(next);
+ },
+
+ // call npm.install("--force", "npm")
+ function () {
+ npm.install("--force", "npm").addErrback(fail(
+ "Failed installing npm with npm"
+ )).addCallback(next);
+ },
+
+ done
+];
+
46 src/queue.js
@@ -0,0 +1,46 @@
+
+exports.queue = function queue (items, fn) {
+ return new Queue(items, fn).start();
+};
+
+// items are the things
+// fn is what to do to each one.
+// promise is the promise that is fulfilled when it works.
+function Queue (items, fn) {
+ this.items = [];
+ for (var i = 0, l = items.length; i < l; i ++) if (i in items) {
+ this.push(items[i]);
+ }
+ this.fn = fn;
+}
+function Queue_next () {
+ if (this.items.length <= 0) return this.promise.emitSuccess();
+
+ var np = new node.Promise(),
+ self = this
+ np.addCallback(function () { Queue_next.call(self) });
+ setTimeout(function () {
+ try {
+ var fnP = self.fn.call(null, self.items.shift());
+ if (fnP instanceof node.Promise) fnP.addCallback(function () {
+ np.emitSuccess();
+ }).addErrback(function () {
+ np.emitError();
+ });
+ else np.emitSuccess();
+ } catch (ex) {
+ self.promise.emitError(ex);
+ }
+ });
+ return this.promise;
+};
+
+Queue.prototype = {
+ start : function Queue_start () {
+ if (this._started) return;
+ this._started = true;
+ this.promise = new node.Promise();
+ return Queue_next.call(this);
+ },
+ push : function (i) { this.items.push(i); }
+};

0 comments on commit 4626dfa

Please sign in to comment.