Skip to content
This repository has been archived by the owner on Jun 2, 2024. It is now read-only.

Commit

Permalink
docs: Deploy a private npm registry in 5 minutes
Browse files Browse the repository at this point in the history
  • Loading branch information
fengmk2 committed Feb 3, 2015
1 parent f4dc41e commit a6a53e3
Show file tree
Hide file tree
Showing 6 changed files with 228 additions and 12 deletions.
1 change: 1 addition & 0 deletions .npmignore
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,4 @@ config/web_readme.md
config/config.js
*.sqlite
.node-dev.json
nohup.out
73 changes: 72 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,78 @@ Our goal is to provide a low cost maintenance and easy to use solution for priva
* Build a mirror NPM. (we use it to build a mirror in China: [cnpmjs.org](http://cnpmjs.org/))
* Build a completely independent NPM registry to store whatever you like.

### Features
## Deploy a private npm registry in 5 minutes

- Install `cnpmjs.org` and `cnpm` from npm

```bash
$ npm install cnpmjs.org cnpm -g
```

- Start `cnpmjs.org` server with configs
- admins: `fengmk2,dead-horse`
- scopes: `my-company-name,other-name`
- default ports: 7001-registry, 7002-web

```bash
$ nohup cnpmjs.org start --admins='fengmk2,dead-horse' --scopes='@my-company-name,@other-name' &
```

- Change `cnpm` default registry to your private registry

```bash
$ cnpm set registry http://localhost:7001
```

- Use `cnpm` to login yourself on your private registry

```bash
$ cnpm login
Username: fengmk2
Password: ***
Email: (this IS public) m@fengmk2.com
```

- Publish your private package now!

```bash
$ cd /tmp
$ mkdir helloworld && cd helloworld
$ cnpm init
name: (helloworld) @my-company-name/helloworld
version: (1.0.0)

{
"name": "@my-compny-name/helloworld",
"version": "1.0.0",
"description": "my first scoped package",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC"
}

$ cnpm publish
+ @my-company-name/helloworld@1.0.0
```

- View your private package

You can visit with bowsers

```bash
$ open http://localhost:7002/@my-company-name/helloworld
```

Or use cnpm info

```bash
$ cnpm info
```

## Features

* **Support "scoped" packages**: [npm/npm#5239](https://github.com/npm/npm/issues/5239)
* **Support [CORS](http://en.wikipedia.org/wiki/Cross-origin_resource_sharing)**
Expand Down
131 changes: 131 additions & 0 deletions bin/cli.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
#!/usr/bin/env node --harmony

/**!
* cnpmjs.org - bin/cli.js
*
* Copyright(c) fengmk2 and other contributors.
* MIT Licensed
*
* Authors:
* fengmk2 <m@fengmk2.com> (http://fengmk2.com)
*/

'use strict';

/**
* Module dependencies.
*/

var debug = require('debug')('cnpmjs.org:cli');
var program = require('commander');
var path = require('path');
var fs = require('fs');
var mkdirp = require('mkdirp');
var treekill = require('treekill');
var version = require('../package.json').version;

function list(val) {
return val.split(',');
}

program
.version(version);

program
.command('start')
.description('start cnpmjs.org server')
.option('--admins <admins>', 'set admins', list)
.option('--scopes <scopes>', 'set scopes', list)
// .option('--cluster', 'enable cluster mode')
.option('--dataDir <dataDir>', 'cnpmjs.org data dir, default is `$HOME/.cnpmjs.org`')
.action(start);

program
.command('stop')
.description('stop cnpmjs.org server')
.option('--dataDir <dataDir>', 'cnpmjs.org data dir, default is `$HOME/.cnpmjs.org`')
.action(stop);

program.parse(process.argv);


function start(options) {
var dataDir = options.dataDir || path.join(process.env.HOME, '.cnpmjs.org');
mkdirp.sync(dataDir);

var configfile = path.join(dataDir, 'config.json');
var config = {};
if (fs.existsSync(configfile)) {
try {
config = require(configfile);
} catch (err) {
console.warn('load old %s error: %s', configfile, err);
}
}
// config.enableCluster = !!options.cluster;
if (options.admins) {
config.admins = {};
for (var i = 0; i < options.admins.length; i++) {
config.admins[options.admins[i]] = options.admins[i] + '@localhost.com';
}
}
if (options.scopes) {
config.scopes = options.scopes.map(function (name) {
if (name[0] !== '@') {
name = '@' + name;
}
return name;
});
}

var configJSON = JSON.stringify(config, null, 2);
fs.writeFileSync(configfile, configJSON);

debug('save config %s to %s', configJSON, configfile);

// if sqlite db file not exists, init first
initDatabase();

require('../dispatch');
fs.writeFileSync(path.join(dataDir, 'pid'), process.pid + '');
}

function stop(options) {
var dataDir = options.dataDir || path.join(process.env.HOME, '.cnpmjs.org');
var pidfile = path.join(dataDir, 'pid');
if (fs.existsSync(pidfile)) {
var pid = Number(fs.readFileSync(pidfile, 'utf8'));
treekill(pid, function (err) {
if (err) {
console.log(err);
throw err;
}
console.log('cnpmjs.org server:%d stop', pid);
fs.unlinkSync(pidfile);
});
} else {
console.log('cnpmjs.org server not start');
}
}

function initDatabase() {
var models = require('../models');

models.sequelize.sync({ force: false })
.then(function () {
models.Total.init(function (err) {
if (err) {
console.error('[models/init_script.js] sequelize init fail');
console.error(err);
throw err;
} else {
console.log('[models/init_script.js] `sqlite` sequelize sync and init success');
}
});
})
.catch(function (err) {
console.error('[models/init_script.js] sequelize sync fail');
console.error(err);
throw err;
});
}
24 changes: 15 additions & 9 deletions config/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@
var mkdirp = require('mkdirp');
var copy = require('copy-to');
var path = require('path');
var fs = require('fs');
var os = require('os');

var version = require('../package.json').version;
Expand Down Expand Up @@ -159,10 +158,7 @@ var config = {
enablePrivate: false,

// registry scopes, if don't set, means do not support scopes
scopes: [
'@cnpm',
'@cnpmtest'
],
scopes: [ '@cnpm', '@cnpmtest' ],

// some registry already have some private packages in global scope
// but we want to treat them as scoped private packages,
Expand Down Expand Up @@ -219,10 +215,20 @@ var config = {
userService: null,
};

// load config/config.js, everything in config.js will cover the same key in index.js
var customConfig = path.join(root, 'config/config.js');
if (fs.existsSync(customConfig)) {
copy(require(customConfig)).override(config);
if (process.env.NODE_ENV !== 'test') {
// 1. try to load `$dataDir/config.js` first, not exists then goto 2.
// 2. load config/config.js, everything in config.js will cover the same key in index.js
var customConfig = path.join(dataDir, 'config');
try {
copy(require(customConfig)).override(config);
} catch (err) {
customConfig = path.join(root, 'config', 'config');
try {
copy(require(customConfig)).override(config);
} catch (err) {
// ignore
}
}
}

mkdirp.sync(config.logdir);
Expand Down
3 changes: 3 additions & 0 deletions dispatch.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ var config = require('./config');
var workerPath = path.join(__dirname, 'worker.js');
var syncPath = path.join(__dirname, 'sync');

console.log('Starting cnpmjs.org ...\ncluster: %s\nadmins: %j\nscopes: %j\nsourceNpmRegistry: %s',
config.enableCluster, config.admins, config.scopes, config.sourceNpmRegistry);

if (config.enableCluster) {
forkWorker();
if (config.syncModel !== 'none') {
Expand Down
8 changes: 6 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@
"status": "./bin/nodejsctl status",
"stop": "./bin/nodejsctl stop"
},
"bin": {
"cnpmjs.org": "bin/cli.js"
},
"dependencies": {
"agentkeepalive": "~1.2.0",
"bluebird": "~2.9.6",
Expand All @@ -18,10 +21,11 @@
"co-defer": "~0.1.2",
"co-gather": "~0.0.1",
"co-sleep": "~0.0.1",
"commander": "~2.6.0",
"copy-to": "~2.0.1",
"debug": "~2.1.1",
"error-formater": "~1.0.3",
"fs-cnpm": "~1.1.0",
"fs-cnpm": "~1.2.0",
"giturl": "~0.0.3",
"graceful": "~1.0.0",
"gravatar": "~1.1.0",
Expand All @@ -42,6 +46,7 @@
"semver": "~4.2.0",
"sequelize": "~2.0.0-rc8",
"thunkify-wrap": "~1.0.4",
"treekill": "~1.0.0",
"urllib": "~2.2.2",
"utility": "~1.3.0",
"xss": "~0.1.20"
Expand All @@ -53,7 +58,6 @@
"contributors": "*",
"istanbul-harmony": "*",
"jshint": "*",
"koa-mock": "~1.1.4",
"mm": "*",
"mocha": "*",
"node-dev": "*",
Expand Down

0 comments on commit a6a53e3

Please sign in to comment.