Compare commits
61 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e497fb354d | ||
|
|
e647d4a1fe | ||
|
|
33465ecf86 | ||
|
|
3eb3eb6be9 | ||
|
|
6ab1556ec0 | ||
|
|
9fd21a5c25 | ||
|
|
53b8398e93 | ||
|
|
c43b117e67 | ||
|
|
7db269e5f4 | ||
|
|
92ed8984d3 | ||
|
|
71d351da29 | ||
|
|
c8e1d8cc4a | ||
|
|
fd79879d0c | ||
|
|
354b82f6ea | ||
|
|
de0487cccc | ||
|
|
081ccd66df | ||
|
|
cebf501182 | ||
|
|
8fe593a182 | ||
|
|
8770458a46 | ||
|
|
559dc03cd4 | ||
|
|
70d12f235a | ||
|
|
aa7077e4b0 | ||
|
|
f5c19668f5 | ||
|
|
2b2a1904c6 | ||
|
|
a234c7e289 | ||
|
|
63562c30ec | ||
|
|
6968331b38 | ||
|
|
fc1a17e4d1 | ||
|
|
3872b7dfdf | ||
|
|
e340ce081a | ||
|
|
170a689168 | ||
|
|
7794d1099d | ||
|
|
bd8686c448 | ||
|
|
d8a76d03e0 | ||
|
|
4460810799 | ||
|
|
4124525eb8 | ||
|
|
ff50946cd3 | ||
|
|
3637eeefdd | ||
|
|
cecb41e6ea | ||
|
|
72b3240ef5 | ||
|
|
869d5681ce | ||
|
|
ff1bfd5acc | ||
|
|
7e3129c8b8 | ||
|
|
0618c732d7 | ||
|
|
9b34ab408c | ||
|
|
d990d3aa91 | ||
|
|
03ef728049 | ||
|
|
f00ed85d41 | ||
|
|
685af2a367 | ||
|
|
818f216fb4 | ||
|
|
1b47495565 | ||
|
|
0ab314f27c | ||
|
|
95076c8787 | ||
|
|
4e6eb0a9cc | ||
|
|
29f17dd5d1 | ||
|
|
3a48637ef1 | ||
|
|
e1029b005f | ||
|
|
66771dfc3b | ||
|
|
66f05a2f07 | ||
|
|
6660cabbb6 | ||
|
|
fbe1971957 |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -22,3 +22,4 @@ docs/web/history.md
|
||||
view/web/_layout.html
|
||||
bin/mysql.js
|
||||
bin/test.sql
|
||||
coverage/
|
||||
|
||||
4
.jshintignore
Normal file
4
.jshintignore
Normal file
@@ -0,0 +1,4 @@
|
||||
node_modules/
|
||||
coverage/
|
||||
.tmp/
|
||||
.git/
|
||||
95
.jshintrc
Normal file
95
.jshintrc
Normal file
@@ -0,0 +1,95 @@
|
||||
{
|
||||
// JSHint Default Configuration File (as on JSHint website)
|
||||
// See http://jshint.com/docs/ for more details
|
||||
|
||||
"maxerr" : 50, // {int} Maximum error before stopping
|
||||
|
||||
// Enforcing
|
||||
"bitwise" : true, // true: Prohibit bitwise operators (&, |, ^, etc.)
|
||||
"camelcase" : false, // true: Identifiers must be in camelCase
|
||||
"curly" : true, // true: Require {} for every new block or scope
|
||||
"eqeqeq" : true, // true: Require triple equals (===) for comparison
|
||||
"forin" : false, // true: Require filtering for..in loops with obj.hasOwnProperty()
|
||||
"immed" : false, // true: Require immediate invocations to be wrapped in parens e.g. `(function () { } ());`
|
||||
"indent" : false, // {int} Number of spaces to use for indentation
|
||||
"latedef" : false, // true: Require variables/functions to be defined before being used
|
||||
"newcap" : false, // true: Require capitalization of all constructor functions e.g. `new F()`
|
||||
"noarg" : true, // true: Prohibit use of `arguments.caller` and `arguments.callee`
|
||||
"noempty" : true, // true: Prohibit use of empty blocks
|
||||
"nonew" : false, // true: Prohibit use of constructors for side-effects (without assignment)
|
||||
"plusplus" : false, // true: Prohibit use of `++` & `--`
|
||||
"quotmark" : false, // Quotation mark consistency:
|
||||
// false : do nothing (default)
|
||||
// true : ensure whatever is used is consistent
|
||||
// "single" : require single quotes
|
||||
// "double" : require double quotes
|
||||
"undef" : true, // true: Require all non-global variables to be declared (prevents global leaks)
|
||||
"unused" : false, // true: Require all defined variables be used
|
||||
"strict" : true, // true: Requires all functions run in ES5 Strict Mode
|
||||
"trailing" : false, // true: Prohibit trailing whitespaces
|
||||
"maxparams" : false, // {int} Max number of formal params allowed per function
|
||||
"maxdepth" : false, // {int} Max depth of nested blocks (within functions)
|
||||
"maxstatements" : false, // {int} Max number statements per function
|
||||
"maxcomplexity" : false, // {int} Max cyclomatic complexity per function
|
||||
"maxlen" : false, // {int} Max number of characters per line
|
||||
|
||||
// Relaxing
|
||||
"asi" : false, // true: Tolerate Automatic Semicolon Insertion (no semicolons)
|
||||
"boss" : true, // true: Tolerate assignments where comparisons would be expected
|
||||
"debug" : false, // true: Allow debugger statements e.g. browser breakpoints.
|
||||
"eqnull" : false, // true: Tolerate use of `== null`
|
||||
"es5" : false, // true: Allow ES5 syntax (ex: getters and setters)
|
||||
"esnext" : true, // true: Allow ES.next (ES6) syntax (ex: `const`)
|
||||
"moz" : false, // true: Allow Mozilla specific syntax (extends and overrides esnext features)
|
||||
// (ex: `for each`, multiple try/catch, function expression…)
|
||||
"evil" : false, // true: Tolerate use of `eval` and `new Function()`
|
||||
"expr" : true, // true: Tolerate `ExpressionStatement` as Programs
|
||||
"funcscope" : false, // true: Tolerate defining variables inside control statements"
|
||||
"globalstrict" : false, // true: Allow global "use strict" (also enables 'strict')
|
||||
"iterator" : false, // true: Tolerate using the `__iterator__` property
|
||||
"lastsemic" : false, // true: Tolerate omitting a semicolon for the last statement of a 1-line block
|
||||
"laxbreak" : true, // true: Tolerate possibly unsafe line breakings
|
||||
"laxcomma" : false, // true: Tolerate comma-first style coding
|
||||
"loopfunc" : false, // true: Tolerate functions being defined in loops
|
||||
"multistr" : true, // true: Tolerate multi-line strings
|
||||
"proto" : false, // true: Tolerate using the `__proto__` property
|
||||
"scripturl" : false, // true: Tolerate script-targeted URLs
|
||||
"smarttabs" : false, // true: Tolerate mixed tabs/spaces when used for alignment
|
||||
"shadow" : true, // true: Allows re-define variables later in code e.g. `var x=1; x=2;`
|
||||
"sub" : false, // true: Tolerate using `[]` notation when it can still be expressed in dot notation
|
||||
"supernew" : false, // true: Tolerate `new function () { ... };` and `new Object;`
|
||||
"validthis" : false, // true: Tolerate using this in a non-constructor function
|
||||
|
||||
// Environments
|
||||
"browser" : true, // Web Browser (window, document, etc)
|
||||
"couch" : false, // CouchDB
|
||||
"devel" : true, // Development/debugging (alert, confirm, etc)
|
||||
"dojo" : false, // Dojo Toolkit
|
||||
"jquery" : false, // jQuery
|
||||
"mootools" : false, // MooTools
|
||||
"node" : true, // Node.js
|
||||
"nonstandard" : false, // Widely adopted globals (escape, unescape, etc)
|
||||
"prototypejs" : false, // Prototype and Scriptaculous
|
||||
"rhino" : false, // Rhino
|
||||
"worker" : false, // Web Workers
|
||||
"wsh" : false, // Windows Scripting Host
|
||||
"yui" : false, // Yahoo User Interface
|
||||
"noyield" : true, // allow generators without a yield
|
||||
|
||||
// Legacy
|
||||
"nomen" : false, // true: Prohibit dangling `_` in variables
|
||||
"onevar" : false, // true: Allow only one `var` statement per function
|
||||
"passfail" : false, // true: Stop on first error
|
||||
"white" : false, // true: Check against strict whitespace and indentation rules
|
||||
|
||||
// Custom Globals
|
||||
"globals" : { // additional predefined global variables
|
||||
// mocha
|
||||
"describe": true,
|
||||
"it": true,
|
||||
"before": true,
|
||||
"afterEach": true,
|
||||
"beforeEach": true,
|
||||
"after": true
|
||||
}
|
||||
}
|
||||
@@ -10,3 +10,6 @@ backup/*.json
|
||||
backup/*.gz
|
||||
view/web/_layout.html
|
||||
bin/mysql.js
|
||||
coverage/
|
||||
.jshintrc
|
||||
.jshintignore
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
language: node_js
|
||||
node_js:
|
||||
- '0.11'
|
||||
script: make test-coveralls
|
||||
|
||||
2
AUTHORS
2
AUTHORS
@@ -1,5 +1,5 @@
|
||||
# Ordered by date of first contribution.
|
||||
# Auto-generated by 'contributors' on Fri, 24 Jan 2014 08:35:59 GMT.
|
||||
# Auto-generated by 'contributors' on Mon, 03 Mar 2014 13:01:28 GMT.
|
||||
# https://github.com/xingrz/node-contributors
|
||||
|
||||
fengmk2 <fengmk2@gmail.com> (https://github.com/fengmk2)
|
||||
|
||||
65
History.md
65
History.md
@@ -1,4 +1,69 @@
|
||||
|
||||
0.3.8 / 2014-03-11
|
||||
==================
|
||||
|
||||
* update middlewares, fixed missing charset bug #264
|
||||
|
||||
0.3.7 / 2014-03-11
|
||||
==================
|
||||
|
||||
* show worker die date time
|
||||
* update to koa@0.5.1
|
||||
* hotfix for star user
|
||||
* fix yield gather, sync missing deps even no missing versions
|
||||
* fix return versions
|
||||
* fix makefile, remove eventproxy
|
||||
* refactor sync_module_worker
|
||||
* add make test-dev, fixed #259
|
||||
* change npm.js to generator
|
||||
* update urllib, proxy/npm.js use generator
|
||||
* sync_all and sync_exist to generator
|
||||
* change function to generator
|
||||
* need node >= v0.11.9
|
||||
|
||||
0.3.6 / 2014-03-06
|
||||
==================
|
||||
|
||||
* install missing package should sync it from source npm. fixed #252
|
||||
* npm publish dont contains .jshint*
|
||||
* npm test run jshint
|
||||
* Add jshint check: $ make jshint
|
||||
* use `yield* next` instead of `yield next`
|
||||
* replace dist.u.qiniudn.com with cnpmjs.org/dist
|
||||
|
||||
0.3.5 / 2014-03-05
|
||||
==================
|
||||
|
||||
* redirect /dist/xxx.tgz => http://dist.u.qiniudn.com/xxx.tgz fixed #249
|
||||
* redirect /name to /package/name when /name is 404. fixed #245
|
||||
* Add missing properies and sync missing star users. fixed #235
|
||||
|
||||
0.3.4 / 2014-03-04
|
||||
==================
|
||||
|
||||
* add cov
|
||||
* use istanbul run test coverage
|
||||
* gzip support. fix #241
|
||||
* readme spelling patch (@stanzheng)
|
||||
* default readme to null, fixed #233
|
||||
* remove readme in versions
|
||||
|
||||
0.3.3 / 2014-02-28
|
||||
==================
|
||||
|
||||
* Merge pull request #232 from cnpm/host-hotfix
|
||||
* get request host from request.headers
|
||||
* Merge pull request #231 from cnpm/bug-fix
|
||||
* fix deps display bug#230 and nsf.url TypeError#229
|
||||
|
||||
0.3.2 / 2014-02-28
|
||||
==================
|
||||
|
||||
* update koa-sess and koa-redis
|
||||
* fix sync all test
|
||||
* remove nfs.downloadStream first, fix tmppath error
|
||||
* fix fengmk2/giturl#1 bug
|
||||
|
||||
0.3.1 / 2014-02-27
|
||||
==================
|
||||
|
||||
|
||||
43
Makefile
43
Makefile
@@ -4,9 +4,13 @@ TIMEOUT = 30000
|
||||
MOCHA_OPTS =
|
||||
|
||||
install:
|
||||
@npm install --registry=http://registry.cnpmjs.org --cache=${HOME}/.npm/.cache/cnpm --disturl=http://dist.u.qiniudn.com
|
||||
@npm install --registry=http://registry.cnpmjs.org \
|
||||
--disturl=http://cnpmjs.org/dist
|
||||
|
||||
test: install
|
||||
jshint:
|
||||
@-./node_modules/.bin/jshint ./
|
||||
|
||||
test:
|
||||
@NODE_ENV=test ./node_modules/mocha/bin/mocha \
|
||||
--harmony-generators \
|
||||
--reporter $(REPORTER) \
|
||||
@@ -15,25 +19,32 @@ test: install
|
||||
$(MOCHA_OPTS) \
|
||||
$(TESTS)
|
||||
|
||||
|
||||
test-cov:
|
||||
@$(MAKE) test MOCHA_OPTS='--require blanket' REPORTER=travis-cov
|
||||
@NODE_ENV=test node --harmony \
|
||||
node_modules/.bin/istanbul cover ./node_modules/.bin/_mocha \
|
||||
-- -u exports \
|
||||
--reporter $(REPORTER) \
|
||||
--timeout $(TIMEOUT) \
|
||||
$(MOCHA_OPTS) \
|
||||
$(TESTS)
|
||||
@-$(MAKE) check-coverage
|
||||
|
||||
test-cov-html:
|
||||
@rm -f coverage.html
|
||||
@$(MAKE) test MOCHA_OPTS='--require blanket' REPORTER=html-cov > coverage.html
|
||||
@ls -lh coverage.html
|
||||
check-coverage:
|
||||
@./node_modules/.bin/istanbul check-coverage \
|
||||
--statements 100 \
|
||||
--functions 100 \
|
||||
--branches 100 \
|
||||
--lines 100
|
||||
|
||||
test-coveralls: test
|
||||
@echo TRAVIS_JOB_ID $(TRAVIS_JOB_ID)
|
||||
@-$(MAKE) test MOCHA_OPTS='--require blanket' REPORTER=mocha-lcov-reporter | ./node_modules/coveralls/bin/coveralls.js
|
||||
cov:
|
||||
@./node_modules/.bin/cov coverage
|
||||
|
||||
test-all: test test-cov
|
||||
contributors:
|
||||
@./node_modules/.bin/contributors -f plain -o AUTHORS
|
||||
|
||||
contributors: install
|
||||
@./node_modules/contributors/bin/contributors -f plain -o AUTHORS
|
||||
|
||||
autod: install
|
||||
@./node_modules/.bin/autod -w -e public,view,docs,backup
|
||||
autod:
|
||||
@./node_modules/.bin/autod -w -e public,view,docs,backup,coverage
|
||||
@$(MAKE) install
|
||||
|
||||
.PHONY: test
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
cnpmjs.org
|
||||
=======
|
||||
|
||||
[](http://travis-ci.org/cnpm/cnpmjs.org) [](https://coveralls.io/r/cnpm/cnpmjs.org) [](https://gemnasium.com/cnpm/cnpmjs.org)
|
||||
[](http://travis-ci.org/cnpm/cnpmjs.org) [](https://gemnasium.com/cnpm/cnpmjs.org)
|
||||
|
||||
[](https://nodei.co/npm/cnpmjs.org/)
|
||||
|
||||
@@ -11,7 +11,8 @@ cnpmjs.org
|
||||
|
||||
Private npm registry and web for Enterprise, base on [koa](http://koajs.com/), MySQL and [Simple Store Service](https://github.com/cnpm/cnpmjs.org/wiki/NFS-Guide).
|
||||
|
||||
@[JacksonTian](https://github.com/JacksonTian/) had a talk about [private npm](https://speakerdeck.com/jacksontian/qi-ye-ji-node-dot-jskai-fa).
|
||||
* @[dead-horse](https://github.com/dead-horse): [What is cnpm?](http://deadhorse.me/slides/cnpmjs.html)
|
||||
* @[JacksonTian](https://github.com/JacksonTian/) had a talk about [private npm](https://speakerdeck.com/jacksontian/qi-ye-ji-node-dot-jskai-fa).
|
||||
|
||||

|
||||
|
||||
@@ -19,7 +20,7 @@ Private npm registry and web for Enterprise, base on [koa](http://koajs.com/), M
|
||||
## Install
|
||||
|
||||
```bash
|
||||
$ npm install --registry=http://r.cnpmjs.org --disturl=http://dist.u.qiniudn.com
|
||||
$ npm install --registry=http://r.cnpmjs.org --disturl=http://cnpmjs.org/dist
|
||||
```
|
||||
|
||||
## Usage
|
||||
@@ -28,6 +29,8 @@ $ npm install --registry=http://r.cnpmjs.org --disturl=http://dist.u.qiniudn.com
|
||||
$ node --harmony-generators dispatch.js
|
||||
```
|
||||
|
||||
**Notice**: need node version >=0.11.9
|
||||
|
||||
## Guide
|
||||
|
||||
* [How to deploy cnpmjs.org](https://github.com/cnpm/cnpmjs.org/wiki/Deploy)
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var thunkify = require('thunkify-wrap');
|
||||
var ready = require('ready');
|
||||
var mysql = require('mysql');
|
||||
var config = require('../config');
|
||||
@@ -35,6 +36,10 @@ var pool = mysql.createPool({
|
||||
exports.pool = pool;
|
||||
|
||||
exports.query = function (sql, values, cb) {
|
||||
if (typeof values === 'function') {
|
||||
cb = values;
|
||||
values = null;
|
||||
}
|
||||
pool.query(sql, values, function (err, rows) {
|
||||
cb(err, rows);
|
||||
});
|
||||
@@ -59,6 +64,8 @@ exports.escape = function (val) {
|
||||
|
||||
ready(exports);
|
||||
|
||||
thunkify(exports);
|
||||
|
||||
function init() {
|
||||
exports.query('show tables', function (err, rows) {
|
||||
if (err) {
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
|
||||
var path = require('path');
|
||||
var fs = require('fs');
|
||||
var os = require('os');
|
||||
var mkdirp = require('mkdirp');
|
||||
|
||||
fs.existsSync = fs.existsSync || path.existsSync;
|
||||
@@ -29,6 +30,7 @@ var config = {
|
||||
registryPort: 7001,
|
||||
webPort: 7002,
|
||||
enableCluster: false,
|
||||
numCPUs: os.cpus().length,
|
||||
debug: true, // if debug
|
||||
logdir: path.join(root, '.tmp', 'logs'),
|
||||
viewCache: false,
|
||||
@@ -72,6 +74,7 @@ var config = {
|
||||
debug: false
|
||||
},
|
||||
|
||||
disturl: 'http://dist.u.qiniudn.com',
|
||||
logoURL: 'http://ww4.sinaimg.cn/large/69c1d4acgw1ebfly5kjlij208202oglr.jpg',
|
||||
registryHost: 'r.cnpmjs.org',
|
||||
customFooter: '', // you can add copyright and site total script html here
|
||||
|
||||
@@ -31,11 +31,11 @@ var Module = require('../../proxy/module');
|
||||
var Total = require('../../proxy/total');
|
||||
var nfs = require('../../common/nfs');
|
||||
var common = require('../../lib/common');
|
||||
var Log = require('../../proxy/module_log');
|
||||
var DownloadTotal = require('../../proxy/download');
|
||||
var SyncModuleWorker = require('../../proxy/sync_module_worker');
|
||||
var logger = require('../../common/logger');
|
||||
var ModuleDeps = require('../../proxy/module_deps');
|
||||
var ModuleStar = require('../../proxy/module_star');
|
||||
|
||||
/**
|
||||
* show all version of a module
|
||||
@@ -43,9 +43,19 @@ var ModuleDeps = require('../../proxy/module_deps');
|
||||
exports.show = function *(next) {
|
||||
var name = this.params.name;
|
||||
|
||||
var r = yield [Module.listTags(name), Module.listByName(name)];
|
||||
var r = yield [
|
||||
Module.listTags(name),
|
||||
Module.listByName(name),
|
||||
ModuleStar.listUsers(name)
|
||||
];
|
||||
var tags = r[0];
|
||||
var rows = r[1];
|
||||
var users = r[2];
|
||||
var userMap = {};
|
||||
for (var i = 0; i < users.length; i++) {
|
||||
userMap[users[i]] = true;
|
||||
}
|
||||
users = userMap;
|
||||
|
||||
debug('show module, user: %s, allowSync: %s, isAdmin: %s',
|
||||
this.session.name, this.session.allowSync, this.session.isAdmin);
|
||||
@@ -69,7 +79,7 @@ exports.show = function *(next) {
|
||||
|
||||
var nextMod = null;
|
||||
var latestMod = null;
|
||||
|
||||
var readme = null;
|
||||
// set tags
|
||||
var distTags = {};
|
||||
for (var i = 0; i < tags.length; i++) {
|
||||
@@ -81,6 +91,8 @@ exports.show = function *(next) {
|
||||
var versions = {};
|
||||
var times = {};
|
||||
var attachments = {};
|
||||
var createdTime = null;
|
||||
var modifiedTime = null;
|
||||
for (var i = 0; i < rows.length; i++) {
|
||||
var row = rows[i];
|
||||
if (row.version === 'next') {
|
||||
@@ -91,10 +103,30 @@ exports.show = function *(next) {
|
||||
common.setDownloadURL(pkg, this);
|
||||
pkg._cnpm_publish_time = row.publish_time;
|
||||
versions[pkg.version] = pkg;
|
||||
times[pkg.version] = row.publish_time ? new Date(row.publish_time) : row.gmt_modified;
|
||||
var t = times[pkg.version] = row.publish_time ? new Date(row.publish_time) : row.gmt_modified;
|
||||
if ((!distTags.latest && !latestMod) || distTags.latest === row.version) {
|
||||
latestMod = row;
|
||||
readme = pkg.readme;
|
||||
}
|
||||
delete pkg.readme;
|
||||
|
||||
if (!createdTime || t < createdTime) {
|
||||
createdTime = t;
|
||||
}
|
||||
if (!modifiedTime || t > modifiedTime) {
|
||||
modifiedTime = t;
|
||||
}
|
||||
}
|
||||
|
||||
if (modifiedTime && createdTime) {
|
||||
var ts = {
|
||||
modified: modifiedTime,
|
||||
created: createdTime,
|
||||
};
|
||||
for (var t in times) {
|
||||
ts[t] = times[t];
|
||||
}
|
||||
times = ts;
|
||||
}
|
||||
|
||||
if (!latestMod) {
|
||||
@@ -110,21 +142,29 @@ exports.show = function *(next) {
|
||||
rev = String(nextMod.id);
|
||||
}
|
||||
|
||||
var pkg = latestMod.package;
|
||||
|
||||
var info = {
|
||||
_id: name,
|
||||
_rev: rev,
|
||||
name: name,
|
||||
description: latestMod.package.description,
|
||||
description: pkg.description,
|
||||
"dist-tags": distTags,
|
||||
maintainers: latestMod.package.maintainers,
|
||||
maintainers: pkg.maintainers,
|
||||
time: times,
|
||||
author: latestMod.package.author,
|
||||
repository: latestMod.package.repository,
|
||||
users: users,
|
||||
author: pkg.author,
|
||||
repository: pkg.repository,
|
||||
versions: versions,
|
||||
readme: latestMod.package.readme,
|
||||
readme: readme,
|
||||
_attachments: attachments,
|
||||
};
|
||||
|
||||
info.readmeFilename = pkg.readmeFilename;
|
||||
info.homepage = pkg.homepage;
|
||||
info.bugs = pkg.bugs;
|
||||
info.license = pkg.license;
|
||||
|
||||
debug('show module %s: %s, latest: %s', name, rev, latestMod.version);
|
||||
|
||||
this.body = info;
|
||||
@@ -182,17 +222,22 @@ exports.download = function *(next) {
|
||||
var version = filename.slice(name.length + 1, -4);
|
||||
var row = yield Module.get(name, version);
|
||||
// can not get dist
|
||||
var url = nfs.url(common.getCDNKey(name, filename));
|
||||
var url = null;
|
||||
|
||||
if (typeof nfs.url === 'function') {
|
||||
url = nfs.url(common.getCDNKey(name, filename));
|
||||
}
|
||||
|
||||
if (!row || !row.package || !row.package.dist) {
|
||||
if (!nfs.url) {
|
||||
return yield next;
|
||||
if (!url) {
|
||||
return yield* next;
|
||||
}
|
||||
this.status = 302;
|
||||
this.set('Location', url);
|
||||
_downloads[name] = (_downloads[name] || 0) + 1;
|
||||
return;
|
||||
}
|
||||
|
||||
var dist = row.package.dist;
|
||||
if (!dist.key) {
|
||||
debug('get tarball by 302');
|
||||
@@ -203,8 +248,8 @@ exports.download = function *(next) {
|
||||
}
|
||||
|
||||
// else use `dist.key` to get tarball from nfs
|
||||
if (!nfs.downloadStream && !nfs.download) {
|
||||
return yield next;
|
||||
if (!nfs.download) {
|
||||
return yield* next;
|
||||
}
|
||||
|
||||
_downloads[name] = (_downloads[name] || 0) + 1;
|
||||
@@ -216,13 +261,9 @@ exports.download = function *(next) {
|
||||
this.set('Content-Disposition', 'attachment; filename="' + filename + '"');
|
||||
this.set('ETag', dist.shasum);
|
||||
|
||||
if (nfs.downloadStream) {
|
||||
yield nfs.downloadStream(dist.key, this.res, {timeout: DOWNLOAD_TIMEOUT});
|
||||
return;
|
||||
}
|
||||
|
||||
// use download file api
|
||||
var tmpPath = path.join(config.uploadDir, utility.randomString() + dist.key);
|
||||
var tmpPath = path.join(config.uploadDir,
|
||||
utility.randomString() + dist.key.replace(/\//g, '-'));
|
||||
function cleanup() {
|
||||
fs.unlink(tmpPath, utility.noop);
|
||||
}
|
||||
@@ -233,8 +274,8 @@ exports.download = function *(next) {
|
||||
this.throw(err);
|
||||
}
|
||||
var tarball = fs.createReadStream(tmpPath);
|
||||
tarball.on('error', cleanup);
|
||||
tarball.on('end', cleanup);
|
||||
tarball.once('error', cleanup);
|
||||
tarball.once('end', cleanup);
|
||||
this.body = tarball;
|
||||
};
|
||||
|
||||
@@ -286,7 +327,7 @@ exports.upload = function *(next) {
|
||||
var length = Number(this.get('content-length')) || 0;
|
||||
if (!length || !this.is('application/octet-stream')) {
|
||||
debug('request length or type error');
|
||||
return yield next;
|
||||
return yield* next;
|
||||
}
|
||||
|
||||
var username = this.session.name;
|
||||
@@ -301,7 +342,7 @@ exports.upload = function *(next) {
|
||||
var mod = yield Module.getById(id);
|
||||
if (!mod) {
|
||||
debug('can not get this module');
|
||||
return yield next;
|
||||
return yield* next;
|
||||
}
|
||||
if (!common.isMaintainer(this, mod.package.maintainers) || mod.name !== name) {
|
||||
this.status = 403;
|
||||
@@ -327,7 +368,7 @@ exports.upload = function *(next) {
|
||||
var dataSize = 0;
|
||||
|
||||
var buf;
|
||||
while(buf = yield coRead(this.req)) {
|
||||
while (buf = yield coRead(this.req)) {
|
||||
shasum.update(buf);
|
||||
dataSize += buf.length;
|
||||
yield coWrite(ws, buf);
|
||||
@@ -409,7 +450,7 @@ exports.updateLatest = function *(next) {
|
||||
var nextMod = yield Module.get(name, 'next');
|
||||
if (!nextMod) {
|
||||
debug('can not get nextMod');
|
||||
return yield next;
|
||||
return yield* next;
|
||||
}
|
||||
var match = nextMod.package.maintainers.filter(function (item) {
|
||||
return item.name === username;
|
||||
@@ -657,7 +698,7 @@ exports.removeWithVersions = function *(next) {
|
||||
// step1: list all the versions
|
||||
var mods = yield Module.listByName(name);
|
||||
if (!mods || !mods.length) {
|
||||
return yield next;
|
||||
return yield* next;
|
||||
}
|
||||
|
||||
// step2: check permission
|
||||
@@ -740,7 +781,7 @@ exports.removeTar = function *(next) {
|
||||
|
||||
var mod = yield Module.getById(id);
|
||||
if (!mod) {
|
||||
return yield next;
|
||||
return yield* next;
|
||||
}
|
||||
|
||||
if (!common.isMaintainer(this, mod.package.maintainers) || mod.name !== name) {
|
||||
@@ -759,20 +800,20 @@ exports.removeTar = function *(next) {
|
||||
|
||||
exports.removeAll = function *(next) {
|
||||
debug('remove all the module with name: %s, id: %s', this.params.name, this.params.rev);
|
||||
var id = Number(this.params.rev);
|
||||
// var id = Number(this.params.rev);
|
||||
var name = this.params.name;
|
||||
var username = this.session.name;
|
||||
// var username = this.session.name;
|
||||
|
||||
var mods = yield Module.listByName(name);
|
||||
debug('removeAll module %s: %d', name, mods.length);
|
||||
var mod = mods[0];
|
||||
if (!mod) {
|
||||
return yield next;
|
||||
return yield* next;
|
||||
}
|
||||
|
||||
if (!common.isMaintainer(this, mod.package.maintainers) || mod.name !== name) {
|
||||
res.status = 403;
|
||||
res.body = {
|
||||
this.status = 403;
|
||||
this.body = {
|
||||
error: 'no_perms',
|
||||
reason: 'Current user can not delete this tarball'
|
||||
};
|
||||
@@ -818,13 +859,13 @@ function parseModsForList(updated, mods, ctx) {
|
||||
return results;
|
||||
}
|
||||
|
||||
exports.listAllModules = function *(next) {
|
||||
exports.listAllModules = function *() {
|
||||
var updated = Date.now();
|
||||
var mods = yield Module.listSince(0);
|
||||
this.body = parseModsForList(updated, mods, this);
|
||||
};
|
||||
|
||||
exports.listAllModulesSince = function *(next) {
|
||||
exports.listAllModulesSince = function *() {
|
||||
var query = this.query || {};
|
||||
if (query.stale !== 'update_after') {
|
||||
this.status = 400;
|
||||
@@ -842,7 +883,7 @@ exports.listAllModulesSince = function *(next) {
|
||||
this.body = parseModsForList(updated, mods, this);
|
||||
};
|
||||
|
||||
exports.listAllModuleNames = function *(next) {
|
||||
exports.listAllModuleNames = function *() {
|
||||
this.body = (yield Module.listShort()).map(function (m) {
|
||||
return m.name;
|
||||
});
|
||||
|
||||
@@ -16,14 +16,13 @@
|
||||
*/
|
||||
|
||||
var debug = require('debug')('cnpmjs.org:controllers:registry');
|
||||
var logger = require('../../common/logger');
|
||||
var User = require('../../proxy/user');
|
||||
|
||||
exports.show = function *(next) {
|
||||
var name = this.params.name;
|
||||
var user = yield User.get(name);
|
||||
if (!user) {
|
||||
return yield next;
|
||||
return yield* next;
|
||||
}
|
||||
this.etag = '"' + user.rev + '"';
|
||||
var data = {
|
||||
@@ -111,7 +110,7 @@ exports.update = function *(next) {
|
||||
var name = this.params.name;
|
||||
var rev = this.params.rev;
|
||||
if (!name || !rev) {
|
||||
return yield next;
|
||||
return yield* next;
|
||||
}
|
||||
|
||||
debug('update: %s, rev: %s, session.name: %s', name, rev, this.session.name);
|
||||
|
||||
@@ -61,11 +61,10 @@ exports.sync = function *() {
|
||||
|
||||
exports.getSyncLog = function *(next) {
|
||||
var logId = this.params.id;
|
||||
var name = this.params.name;
|
||||
var offset = Number(this.query.offset) || 0;
|
||||
var row = yield Log.get(logId);
|
||||
if (!row) {
|
||||
return yield next;
|
||||
return yield* next;
|
||||
}
|
||||
|
||||
var log = row.log.trim();
|
||||
|
||||
23
controllers/web/dist.js
Normal file
23
controllers/web/dist.js
Normal file
@@ -0,0 +1,23 @@
|
||||
/**!
|
||||
* cnpmjs.org - controllers/web/dist.js
|
||||
*
|
||||
* Copyright(c) cnpmjs.org and other contributors.
|
||||
* MIT Licensed
|
||||
*
|
||||
* Authors:
|
||||
* fengmk2 <fengmk2@gmail.com> (http://fengmk2.github.com)
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var config = require('../../config');
|
||||
|
||||
exports.redirect = function *(next) {
|
||||
var params = this.params;
|
||||
var url = config.disturl + (params[0] || '/');
|
||||
this.redirect(url);
|
||||
};
|
||||
@@ -28,6 +28,7 @@ var sync = require('../sync');
|
||||
var Log = require('../../proxy/module_log');
|
||||
var ModuleDeps = require('../../proxy/module_deps');
|
||||
var setDownloadURL = require('../../lib/common').setDownloadURL;
|
||||
var ModuleStar = require('../../proxy/module_star');
|
||||
|
||||
exports.display = function *(next) {
|
||||
var params = this.params;
|
||||
@@ -47,18 +48,23 @@ exports.display = function *(next) {
|
||||
var r = yield [
|
||||
Module[getPackageMethod].apply(Module, getPackageArgs),
|
||||
down.total(name),
|
||||
ModuleDeps.list(name)
|
||||
ModuleDeps.list(name),
|
||||
ModuleStar.listUsers(name),
|
||||
];
|
||||
var pkg = r[0];
|
||||
var download = r[1];
|
||||
var dependents = r[2];
|
||||
var dependents = (r[2] || []).map(function (item) {
|
||||
return item.deps;
|
||||
});
|
||||
var users = r[3];
|
||||
|
||||
if (!pkg || !pkg.package) {
|
||||
return yield next;
|
||||
return yield* next;
|
||||
}
|
||||
|
||||
pkg.package.fromNow = moment(pkg.publish_time).fromNow();
|
||||
pkg = pkg.package;
|
||||
pkg.users = users;
|
||||
pkg.readme = marked(pkg.readme || '');
|
||||
if (!pkg.readme) {
|
||||
pkg.readme = pkg.description || '';
|
||||
@@ -90,7 +96,7 @@ exports.display = function *(next) {
|
||||
}
|
||||
|
||||
if (pkg.repository && pkg.repository.url) {
|
||||
pkg.repository.weburl = giturl.parse(pkg.repository.url);
|
||||
pkg.repository.weburl = giturl.parse(pkg.repository.url) || pkg.repository.url;
|
||||
}
|
||||
|
||||
setLicense(pkg);
|
||||
@@ -120,7 +126,7 @@ exports.search = function *(next) {
|
||||
packages: result.searchMatchs,
|
||||
keywords: result.keywordMatchs
|
||||
};
|
||||
this.charset = 'utf-8';
|
||||
this.type = 'application/json; charset=utf-8';
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@ exports.display = function *(next) {
|
||||
var packages = r[0];
|
||||
var user = r[1];
|
||||
if (!user && !packages.length) {
|
||||
return yield next;
|
||||
return yield* next;
|
||||
}
|
||||
user = {
|
||||
name: name,
|
||||
|
||||
17
dispatch.js
17
dispatch.js
@@ -1,4 +1,4 @@
|
||||
/*!
|
||||
/**!
|
||||
* cnpmjs.org - dispatch.js
|
||||
*
|
||||
* Copyright(c) cnpmjs.org and other contributors.
|
||||
@@ -17,7 +17,6 @@
|
||||
|
||||
var path = require('path');
|
||||
var util = require('util');
|
||||
var fs = require('fs');
|
||||
var cluster = require('cluster');
|
||||
var config = require('./config');
|
||||
var workerPath = path.join(__dirname, 'worker.js');
|
||||
@@ -30,25 +29,25 @@ if (config.enableCluster) {
|
||||
});
|
||||
|
||||
cluster.on('fork', function (worker) {
|
||||
console.log('[%s] [worker:%d] new worker start', new Date(), worker.process.pid);
|
||||
console.log('[%s] [worker:%d] new worker start', Date(), worker.process.pid);
|
||||
});
|
||||
|
||||
cluster.on('disconnect', function (worker) {
|
||||
var w = cluster.fork();
|
||||
console.error('[%s] [master:%s] wroker:%s disconnect! new worker:%s fork',
|
||||
new Date(), process.pid, worker.process.pid, w.process.pid);
|
||||
console.error('[%s] [master:%s] wroker:%s disconnect, suicide: %s, state: %s. New worker:%s fork',
|
||||
Date(), process.pid, worker.process.pid, worker.suicide, worker.state, w.process.pid);
|
||||
});
|
||||
|
||||
cluster.on('exit', function (worker, code, signal) {
|
||||
var exitCode = worker.process.exitCode;
|
||||
var err = new Error(util.format('worker %s died (code: %s, signal: %s)', worker.process.pid, exitCode, signal));
|
||||
var err = new Error(util.format('worker %s died (code: %s, signal: %s, suicide: %s, state: %s)',
|
||||
worker.process.pid, exitCode, signal, worker.suicide, worker.state));
|
||||
err.name = 'WorkerDiedError';
|
||||
console.error(err);
|
||||
console.error('[%s] [master:%s] wroker exit: %s', Date(), process.pid, err.stack);
|
||||
});
|
||||
|
||||
var numCPUs = require('os').cpus().length;
|
||||
// Fork workers.
|
||||
for (var i = 0; i < numCPUs; i++) {
|
||||
for (var i = 0; i < config.numCPUs; i++) {
|
||||
cluster.fork();
|
||||
}
|
||||
|
||||
|
||||
10
docs/db.sql
10
docs/db.sql
@@ -25,6 +25,16 @@ CREATE TABLE `module_keyword` (
|
||||
KEY `name` (`name`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='module keyword';
|
||||
|
||||
CREATE TABLE `module_star` (
|
||||
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT 'primary key',
|
||||
`gmt_create` datetime NOT NULL COMMENT 'create time',
|
||||
`user` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT 'user name',
|
||||
`name` varchar(100) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL COMMENT 'module name',
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `user_module_name` (`user`,`name`),
|
||||
KEY `name` (`name`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='module star';
|
||||
|
||||
CREATE TABLE `module` (
|
||||
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT 'primary key',
|
||||
`gmt_create` datetime NOT NULL COMMENT 'create time',
|
||||
|
||||
@@ -103,13 +103,13 @@ npm install -g cnpm
|
||||
alias lnpm='cnpm --registry=http://localhost:7001\
|
||||
--registryweb=http://localhost:7002\
|
||||
--cache=$HOME/.npm/.cache/lnpm\
|
||||
--disturl=http://dist.u.qiniudn.com\
|
||||
--disturl=http://cnpmjs.org/dist\
|
||||
--userconfig=$HOME/.lnpmrc'
|
||||
|
||||
#or put this in .zshrc or .bashrc
|
||||
echo "#lnpm alias\nalias lnpm='cnpm --registry=http://localhost:7001\
|
||||
--registryweb=http://localhost:7002\
|
||||
--cache=$HOME/.npm/.cache/lnpm\
|
||||
--disturl=http://dist.u.qiniudn.com\
|
||||
--disturl=http://cnpmjs.org/dist\
|
||||
--userconfig=$HOME/.lnpmrc'" >> $HOME/.zshrc && source $HOME/.zshrc
|
||||
```
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# cnpmjs.org: Private npm registry and web for Enterprise
|
||||
|
||||
[](http://travis-ci.org/cnpm/cnpmjs.org) [](https://coveralls.io/r/cnpm/cnpmjs.org) [](https://gemnasium.com/cnpm/cnpmjs.org)
|
||||
[](http://travis-ci.org/cnpm/cnpmjs.org) [](https://gemnasium.com/cnpm/cnpmjs.org)
|
||||
|
||||
[](https://nodei.co/npm/cnpmjs.org/)
|
||||
|
||||
@@ -8,7 +8,8 @@
|
||||
|
||||
> Private npm registry and web for Enterprise, base on [koa](http://koajs.com/), MySQL and [Simple Store Service](https://github.com/cnpm/cnpmjs.org/wiki/NFS-Guide).
|
||||
|
||||
@[JacksonTian](https://github.com/JacksonTian/) had a talk about [private npm](https://speakerdeck.com/jacksontian/qi-ye-ji-node-dot-jskai-fa).
|
||||
* @[dead-horse](https://github.com/dead-horse): [What is cnpm?](http://deadhorse.me/slides/cnpmjs.html)
|
||||
* @[JacksonTian](https://github.com/JacksonTian/) had a talk about [private npm](https://speakerdeck.com/jacksontian/qi-ye-ji-node-dot-jskai-fa).
|
||||
|
||||
## Install your private npm registry
|
||||
|
||||
@@ -121,13 +122,13 @@ alias it:
|
||||
```bash
|
||||
alias cnpm="npm --registry=http://r.cnpmjs.org \
|
||||
--cache=$HOME/.npm/.cache/cnpm \
|
||||
--disturl=http://dist.u.qiniudn.com \
|
||||
--disturl=http://cnpmjs.org/dist \
|
||||
--userconfig=$HOME/.cnpmrc"
|
||||
|
||||
#Or alias it in .bashrc or .zshrc
|
||||
$ echo '\n#alias for cnpm\nalias cnpm="npm --registry=http://r.cnpmjs.org \
|
||||
--cache=$HOME/.npm/.cache/cnpm \
|
||||
--disturl=http://dist.u.qiniudn.com \
|
||||
--disturl=http://cnpmjs.org/dist \
|
||||
--userconfig=$HOME/.cnpmrc"' >> ~/.zshrc && source ~/.zshrc
|
||||
```
|
||||
|
||||
@@ -139,7 +140,7 @@ $ npm install cnpm -g
|
||||
|
||||
### install
|
||||
|
||||
Install package from [r.cnpmjs.org](http://r.cnpmjs.org). When isntall a package or version not exist, it will try to install from official registry([registry.npmjs.org](http://registry.npmjs.org)), and sync this package to cnpm in the backend.
|
||||
Install package from [r.cnpmjs.org](http://r.cnpmjs.org). When installing a package or version does not exist, it will try to install from the official registry([registry.npmjs.org](http://registry.npmjs.org)), and sync this package to cnpm in the backend.
|
||||
|
||||
```
|
||||
$ cnpm install [name]
|
||||
|
||||
2
index.js
2
index.js
@@ -1,4 +1,4 @@
|
||||
/*!
|
||||
/**!
|
||||
* cnpmjs.org - index.js
|
||||
*
|
||||
* Copyright(c) cnpmjs.org and other contributors.
|
||||
|
||||
@@ -25,24 +25,24 @@ module.exports = function (options) {
|
||||
if (!this.session) {
|
||||
// redis crash
|
||||
this.session = {};
|
||||
return yield next;
|
||||
return yield *next;
|
||||
}
|
||||
this.session.onlySync = config.enablePrivate ? true : false;
|
||||
if (this.session.name) {
|
||||
this.session.isAdmin = common.isAdmin(this.session.name);
|
||||
debug('auth exists user: %s, onlySync: %s, isAdmin: %s, headers: %j',
|
||||
this.session.name, this.session.onlySync, this.session.isAdmin, this.header);
|
||||
return yield next;
|
||||
return yield *next;
|
||||
}
|
||||
var authorization = (this.get('authorization') || '').split(' ')[1] || '';
|
||||
authorization = authorization.trim();
|
||||
if (!authorization) {
|
||||
return yield next;
|
||||
return yield *next;
|
||||
}
|
||||
|
||||
authorization = new Buffer(authorization, 'base64').toString().split(':');
|
||||
if (authorization.length !== 2) {
|
||||
return yield next;
|
||||
return yield *next;
|
||||
}
|
||||
|
||||
var username = authorization[0];
|
||||
@@ -53,13 +53,13 @@ module.exports = function (options) {
|
||||
debug('auth fail user: %j, headers: %j', row, this.header);
|
||||
this.session.name = null;
|
||||
this.session.isAdmin = false;
|
||||
return yield next;
|
||||
return yield *next;
|
||||
}
|
||||
|
||||
this.session.name = row.name;
|
||||
this.session.isAdmin = common.isAdmin(this.session.name);
|
||||
debug('auth pass user: %j, onlySync: %s, isAdmin: %s, headers: %j',
|
||||
row, this.session.onlySync, this.session.isAdmin, this.header);
|
||||
yield next;
|
||||
yield *next;
|
||||
};
|
||||
};
|
||||
|
||||
@@ -23,5 +23,5 @@ module.exports = function *login(next) {
|
||||
};
|
||||
return;
|
||||
}
|
||||
yield next;
|
||||
yield *next;
|
||||
};
|
||||
|
||||
@@ -30,5 +30,5 @@ module.exports = function *publishable(next) {
|
||||
this.charset = 'utf-8';
|
||||
this.body = template.replace('${host}', this.host);
|
||||
}
|
||||
yield next;
|
||||
yield *next;
|
||||
};
|
||||
|
||||
@@ -24,5 +24,5 @@ module.exports = function *publishable(next) {
|
||||
};
|
||||
return;
|
||||
}
|
||||
yield next;
|
||||
yield *next;
|
||||
};
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
*/
|
||||
|
||||
module.exports = function *notFound(next) {
|
||||
yield next;
|
||||
yield *next;
|
||||
|
||||
if (this.status) {
|
||||
return;
|
||||
|
||||
@@ -24,11 +24,11 @@ var config = require('../config');
|
||||
module.exports = function *(next) {
|
||||
if (!config.syncByInstall || !config.enablePrivate) {
|
||||
// only config.enablePrivate should enable sync on install
|
||||
return yield next;
|
||||
return yield *next;
|
||||
}
|
||||
// request not by node, consider it request from web
|
||||
if (this.get('user-agent') && this.get('user-agent').indexOf('node') !== 0) {
|
||||
return yield next;
|
||||
return yield *next;
|
||||
}
|
||||
|
||||
this.session.allowSync = true;
|
||||
@@ -37,9 +37,6 @@ module.exports = function *(next) {
|
||||
this.session.allowSync = false;
|
||||
}
|
||||
|
||||
// TODO: allow sync will let publish sync package...
|
||||
this.session.allowSync = false;
|
||||
|
||||
debug('%s allowSync: %s', this.session.name, this.session.allowSync);
|
||||
yield next;
|
||||
yield *next;
|
||||
};
|
||||
|
||||
@@ -15,11 +15,17 @@
|
||||
*/
|
||||
|
||||
module.exports = function *notFound(next) {
|
||||
yield next;
|
||||
yield *next;
|
||||
|
||||
if (this.status) {
|
||||
return;
|
||||
}
|
||||
|
||||
var m = /^\/([\w\-\_\.]+)\/?$/.exec(this.url);
|
||||
if (m) {
|
||||
return this.redirect('/package/' + m[1]);
|
||||
}
|
||||
|
||||
this.status = 404;
|
||||
this.type = 'text/html';
|
||||
this.charset = 'utf-8';
|
||||
|
||||
41
package.json
41
package.json
@@ -1,37 +1,35 @@
|
||||
{
|
||||
"name": "cnpmjs.org",
|
||||
"version": "0.3.1",
|
||||
"version": "0.3.8",
|
||||
"description": "Private npm registry and web for Enterprise, base on MySQL and Simple Store Service",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"test": "make test-all",
|
||||
"test": "make install && make jshint && make test",
|
||||
"start": "./bin/nodejsctl start && cp History.md docs/web/history.md",
|
||||
"status": "./bin/nodejsctl status",
|
||||
"stop": "./bin/nodejsctl stop"
|
||||
},
|
||||
"config": {
|
||||
"blanket": {
|
||||
"pattern": "//^((?!(node_modules|test|common)).)*$/"
|
||||
},
|
||||
"travis-cov": {
|
||||
"threshold": 90
|
||||
"cov": {
|
||||
"threshold": 83
|
||||
}
|
||||
},
|
||||
"dependencies": {
|
||||
"co": "3.0.4",
|
||||
"co-gather": "0.0.1",
|
||||
"co-read": "0.0.1",
|
||||
"co-write": "0.3.0",
|
||||
"debug": "0.7.4",
|
||||
"eventproxy": "0.2.6",
|
||||
"forward": "0.0.4",
|
||||
"giturl": "0.0.1",
|
||||
"eventproxy": "0.3.0",
|
||||
"giturl": "0.0.2",
|
||||
"graceful": "0.0.6",
|
||||
"gravatar": "1.0.6",
|
||||
"humanize-number": "0.0.2",
|
||||
"koa": "0.5.0",
|
||||
"koa-markdown": "0.0.2",
|
||||
"koa-middlewares": "0.0.5",
|
||||
"koa": "0.5.1",
|
||||
"koa-markdown": "0.0.3",
|
||||
"koa-middlewares": "0.0.9",
|
||||
"logfilestream": "0.1.0",
|
||||
"marked": "0.3.1",
|
||||
"marked": "0.3.2",
|
||||
"microtime": "0.5.1",
|
||||
"mime": "1.2.11",
|
||||
"mkdirp": "0.3.5",
|
||||
@@ -39,25 +37,24 @@
|
||||
"ms": "0.6.2",
|
||||
"mysql": "2.1.0",
|
||||
"nodemailer": "0.6.1",
|
||||
"qn": "0.2.0",
|
||||
"qn": "0.2.1",
|
||||
"ready": "0.1.1",
|
||||
"semver": "2.2.1",
|
||||
"thunkify-wrap": "0.0.1",
|
||||
"urllib": "0.5.5",
|
||||
"thunkify-wrap": "0.0.5",
|
||||
"urllib": "0.5.10",
|
||||
"utility": "0.1.10"
|
||||
},
|
||||
"devDependencies": {
|
||||
"autod": ">=0.0.13",
|
||||
"blanket": "*",
|
||||
"contributors": "*",
|
||||
"coveralls": "*",
|
||||
"cov": "*",
|
||||
"istanbul": "git://github.com/gotwarlost/istanbul.git#harmony",
|
||||
"jshint": "*",
|
||||
"mm": "0.2.0",
|
||||
"mocha": "*",
|
||||
"mocha-lcov-reporter": "*",
|
||||
"pedding": "0.0.3",
|
||||
"should": "3.1.3",
|
||||
"supertest": "0.9.0",
|
||||
"travis-cov": "*"
|
||||
"supertest": "0.9.0"
|
||||
},
|
||||
"homepage": "https://github.com/cnpm/cnpmjs.org",
|
||||
"repository": {
|
||||
|
||||
48
proxy/module_star.js
Normal file
48
proxy/module_star.js
Normal file
@@ -0,0 +1,48 @@
|
||||
/**!
|
||||
* cnpmjs.org - proxy/module_star.js
|
||||
*
|
||||
* Copyright(c) cnpmjs.org and other contributors.
|
||||
* MIT Licensed
|
||||
*
|
||||
* Authors:
|
||||
* fengmk2 <fengmk2@gmail.com> (http://fengmk2.github.com)
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var mysql = require('../common/mysql');
|
||||
|
||||
exports.add = function *add(name, user) {
|
||||
var sql = 'INSERT INTO module_star(name, user) VALUES(?, ?);';
|
||||
try {
|
||||
yield mysql.query(sql, [name, user]);
|
||||
} catch (err) {
|
||||
if (err.code !== 'ER_DUP_ENTRY') {
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
exports.remove = function *(name, user) {
|
||||
var sql = 'DELETE FROM module_star WHERE name = ? AND user = ?;';
|
||||
return yield mysql.query(sql, [name, user]);
|
||||
};
|
||||
|
||||
exports.listUsers = function *(name) {
|
||||
var sql = 'SELECT user FROM module_star WHERE name = ?;';
|
||||
var rows = yield mysql.query(sql, [name]);
|
||||
return rows.map(function (r) {
|
||||
return r.user;
|
||||
});
|
||||
};
|
||||
|
||||
exports.listUserModules = function *(user) {
|
||||
var sql = 'SELECT name FROM module_star WHERE user = ?;';
|
||||
return (yield mysql.query(sql, [user])).map(function (r) {
|
||||
return r.name;
|
||||
});
|
||||
};
|
||||
69
proxy/npm.js
69
proxy/npm.js
@@ -17,53 +17,50 @@
|
||||
var thunkify = require('thunkify-wrap');
|
||||
var urllib = require('urllib');
|
||||
var config = require('../config');
|
||||
thunkify(urllib, ['request']);
|
||||
|
||||
function request(url, options, callback) {
|
||||
if (typeof options === 'function') {
|
||||
callback = options;
|
||||
options = null;
|
||||
}
|
||||
function *request (url, options) {
|
||||
options = options || {};
|
||||
options.dataType = options.dataType || 'json';
|
||||
options.timeout = options.timeout || 120000;
|
||||
url = config.sourceNpmRegistry + url;
|
||||
urllib.request(url, options, function (err, data, res) {
|
||||
if (err) {
|
||||
var statusCode = res && res.statusCode || -1;
|
||||
if (err.name === 'JSONResponseFormatError' && statusCode >= 500) {
|
||||
err.name = 'NPMServerError';
|
||||
err.message = 'Status ' + statusCode + ', ' + (data && data.toString() || 'empty body');
|
||||
}
|
||||
var r;
|
||||
try {
|
||||
r = yield urllib.request(url, options);
|
||||
} catch (err) {
|
||||
var statusCode = err.res ? err.res.statusCode : 200;
|
||||
var data = err.data || '[empty]';
|
||||
if (err.name === 'JSONResponseFormatError' && statusCode >= 500) {
|
||||
err.name = 'NPMServerError';
|
||||
err.message = 'Status ' + statusCode + ', ' + data.toString();
|
||||
}
|
||||
callback(err, data, res);
|
||||
});
|
||||
throw err;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
exports.get = function (name, callback) {
|
||||
request('/' + name, function (err, data, res) {
|
||||
if (err) {
|
||||
return callback(err);
|
||||
}
|
||||
res = res || {};
|
||||
if (res.statusCode === 404) {
|
||||
data = null;
|
||||
}
|
||||
callback(null, data, res);
|
||||
exports.get = function *(name) {
|
||||
var r = yield request('/' + name);
|
||||
var data = r[0];
|
||||
var res = r[1];
|
||||
if (res && res.statusCode === 404) {
|
||||
data = null;
|
||||
}
|
||||
return data;
|
||||
};
|
||||
|
||||
exports.getAllSince = function *(startkey) {
|
||||
var r = yield request('/-/all/since?stale=update_after&startkey=' + startkey, {
|
||||
dataType: 'json',
|
||||
timeout: 300000
|
||||
});
|
||||
return r[0];
|
||||
};
|
||||
|
||||
exports.getAllSince = function (startkey, callback) {
|
||||
request('/-/all/since?stale=update_after&startkey=' + startkey, {
|
||||
exports.getShort = function *() {
|
||||
var r = yield request('/-/short', {
|
||||
dataType: 'json',
|
||||
timeout: 300000
|
||||
}, callback);
|
||||
});
|
||||
return r[0];
|
||||
};
|
||||
|
||||
exports.getShort = function (callback) {
|
||||
request('/-/short', {
|
||||
dataType: 'json',
|
||||
timeout: 300000
|
||||
}, callback);
|
||||
};
|
||||
|
||||
thunkify(exports);
|
||||
|
||||
@@ -15,6 +15,8 @@
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var co = require('co');
|
||||
var gather = require('co-gather');
|
||||
var thunkify = require('thunkify-wrap');
|
||||
var debug = require('debug')('cnpmjs.org:proxy:sync_module_worker');
|
||||
var EventEmitter = require('events').EventEmitter;
|
||||
@@ -22,7 +24,6 @@ var util = require('util');
|
||||
var fs = require('fs');
|
||||
var path = require('path');
|
||||
var crypto = require('crypto');
|
||||
var eventproxy = require('eventproxy');
|
||||
var urllib = require('urllib');
|
||||
var utility = require('utility');
|
||||
var ms = require('ms');
|
||||
@@ -33,6 +34,9 @@ var Module = require('./module');
|
||||
var ModuleDeps = require('./module_deps');
|
||||
var Log = require('./module_log');
|
||||
var config = require('../config');
|
||||
var ModuleStar = require('./module_star');
|
||||
|
||||
var request = thunkify(urllib.request);
|
||||
|
||||
function SyncModuleWorker(options) {
|
||||
EventEmitter.call(this);
|
||||
@@ -89,9 +93,24 @@ SyncModuleWorker.prototype.log = function (format, arg1, arg2) {
|
||||
SyncModuleWorker.prototype.start = function () {
|
||||
this.log('user: %s, sync %s worker start, %d concurrency, nodeps: %s, publish: %s',
|
||||
this.username, this.names[0], this.concurrency, this.noDep, this._publish);
|
||||
for (var i = 0; i < this.concurrency; i++) {
|
||||
this.next(i);
|
||||
}
|
||||
var self = this;
|
||||
co(function *() {
|
||||
var arr = [];
|
||||
for (var i = 0; i < self.concurrency; i++) {
|
||||
arr.push(self.next(i));
|
||||
}
|
||||
yield arr;
|
||||
})();
|
||||
};
|
||||
|
||||
SyncModuleWorker.prototype.pushSuccess = function (name) {
|
||||
this.successes.push(name);
|
||||
this.emit('success', name);
|
||||
};
|
||||
|
||||
SyncModuleWorker.prototype.pushFail = function (name) {
|
||||
this.fails.push(name);
|
||||
this.emit('fail', name);
|
||||
};
|
||||
|
||||
SyncModuleWorker.prototype.add = function (name) {
|
||||
@@ -100,10 +119,11 @@ SyncModuleWorker.prototype.add = function (name) {
|
||||
}
|
||||
this.nameMap[name] = true;
|
||||
this.names.push(name);
|
||||
this.emit('add', name);
|
||||
this.log(' add dependencies: %s', name);
|
||||
};
|
||||
|
||||
SyncModuleWorker.prototype.next = function (concurrencyId) {
|
||||
SyncModuleWorker.prototype.next = function *(concurrencyId) {
|
||||
var name = this.names.shift();
|
||||
if (!name) {
|
||||
return process.nextTick(this.finish.bind(this));
|
||||
@@ -111,311 +131,363 @@ SyncModuleWorker.prototype.next = function (concurrencyId) {
|
||||
|
||||
var that = this;
|
||||
that.syncingNames[name] = true;
|
||||
npm.get(name, function (err, pkg, response) {
|
||||
var statusCode = response && response.statusCode || -1;
|
||||
if (!err && !pkg) {
|
||||
err = new Error('Module ' + name + ' not exists, http status ' + statusCode);
|
||||
err.name = 'NpmModuleNotExsitsError';
|
||||
}
|
||||
if (err) {
|
||||
if (statusCode === 404) {
|
||||
that.successes.push(name);
|
||||
} else {
|
||||
that.fails.push(name);
|
||||
}
|
||||
that.log('[error] [%s] get package error: %s', name, err.stack);
|
||||
delete that.syncingNames[name];
|
||||
return that.next(concurrencyId);
|
||||
var pkg;
|
||||
// get from npm
|
||||
try {
|
||||
pkg = yield npm.get(name);
|
||||
} catch (err) {
|
||||
// if 404
|
||||
if (err.res && err.res.statusCode === 404) {
|
||||
that.pushSuccess(name);
|
||||
} else {
|
||||
that.pushFail(name);
|
||||
}
|
||||
that.log('[error] [%s] get package error: %s', name, err.stack);
|
||||
delete that.syncingNames[name];
|
||||
yield *that.next(concurrencyId);
|
||||
return;
|
||||
}
|
||||
if (!pkg) {
|
||||
that.log('[error] [%s] get package error: package not exist', name);
|
||||
delete that.syncingNames[name];
|
||||
yield that.next(concurrencyId);
|
||||
return;
|
||||
}
|
||||
|
||||
that.log('[c#%d] [%s] start...', concurrencyId, name);
|
||||
that._sync(name, pkg, function (err, versions) {
|
||||
delete that.syncingNames[name];
|
||||
if (err) {
|
||||
that.fails.push(name);
|
||||
that.log('[error] [%s] sync error: %s', name, err.stack);
|
||||
return that.next(concurrencyId);
|
||||
}
|
||||
that.log('[%s] synced success, %d versions: %s',
|
||||
name, versions.length, versions.join(', '));
|
||||
that.successes.push(name);
|
||||
that.emit('success', name);
|
||||
that.next(concurrencyId);
|
||||
});
|
||||
});
|
||||
that.log('[c#%d] [%s] start...', concurrencyId, name);
|
||||
var versions;
|
||||
try {
|
||||
versions = yield that._sync(name, pkg);
|
||||
} catch (err) {
|
||||
that.pushFail(name);
|
||||
that.log('[error] [%s] sync error: %s', name, err.stack);
|
||||
delete that.syncingNames[name];
|
||||
yield *that.next(concurrencyId);
|
||||
return;
|
||||
}
|
||||
that.log('[%s] synced success, %d versions: %s',
|
||||
name, versions.length, versions.join(', '));
|
||||
that.pushSuccess(name);
|
||||
delete that.syncingNames[name];
|
||||
yield that.next(concurrencyId);
|
||||
};
|
||||
|
||||
SyncModuleWorker.prototype._sync = function (name, pkg, callback) {
|
||||
function *_listStarUsers(modName) {
|
||||
var users = yield ModuleStar.listUsers(modName);
|
||||
var userMap = {};
|
||||
users.forEach(function (user) {
|
||||
userMap[user] = true;
|
||||
});
|
||||
return userMap;
|
||||
}
|
||||
|
||||
function *_addStar(modName, username) {
|
||||
yield ModuleStar.add(modName, username);
|
||||
}
|
||||
|
||||
SyncModuleWorker.prototype._sync = function *(name, pkg) {
|
||||
var username = this.username;
|
||||
var that = this;
|
||||
var ep = eventproxy.create();
|
||||
ep.fail(callback);
|
||||
|
||||
var hasModules = false;
|
||||
Module.listByName(name, ep.done(function (rows) {
|
||||
hasModules = rows.length > 0;
|
||||
var map = {};
|
||||
for (var i = 0; i < rows.length; i++) {
|
||||
var r = rows[i];
|
||||
if (!r.package || !r.package.dist) {
|
||||
// package json parse error
|
||||
continue;
|
||||
}
|
||||
var result = yield [
|
||||
Module.listByName(name),
|
||||
Module.listTags(name),
|
||||
_listStarUsers(name)
|
||||
];
|
||||
var moduleRows = result[0];
|
||||
var tagRows = result[1];
|
||||
var existsStarUsers = result[2];
|
||||
|
||||
if (r.package && r.package._publish_on_cnpm) {
|
||||
// publish on cnpm, dont sync this version package
|
||||
that.log(' [%s] publish on local cnpm, don\'t sync', name);
|
||||
ep.unbind();
|
||||
callback(null, []);
|
||||
return;
|
||||
}
|
||||
|
||||
if (r.version === 'next') {
|
||||
continue;
|
||||
}
|
||||
if (!map.latest) {
|
||||
map.latest = r;
|
||||
}
|
||||
map[r.version] = r;
|
||||
hasModules = moduleRows.length > 0;
|
||||
var map = {};
|
||||
for (var i = 0; i < moduleRows.length; i++) {
|
||||
var r = moduleRows[i];
|
||||
if (!r.package || !r.package.dist) {
|
||||
// package json parse error
|
||||
continue;
|
||||
}
|
||||
ep.emit('existsMap', map);
|
||||
}));
|
||||
|
||||
Module.listTags(name, ep.done(function (rows) {
|
||||
var tags = {};
|
||||
for (var i = 0; i < rows.length; i++) {
|
||||
var r = rows[i];
|
||||
if (!r.module_id) {
|
||||
// no module_id, need to sync tags
|
||||
continue;
|
||||
}
|
||||
tags[r.tag] = r.version;
|
||||
if (r.package && r.package._publish_on_cnpm) {
|
||||
// publish on cnpm, dont sync this version package
|
||||
that.log(' [%s] publish on local cnpm, don\'t sync', name);
|
||||
return [];
|
||||
}
|
||||
ep.emit('existsTags', tags);
|
||||
}));
|
||||
|
||||
if (r.version === 'next') {
|
||||
continue;
|
||||
}
|
||||
if (!map.latest) {
|
||||
map.latest = r;
|
||||
}
|
||||
map[r.version] = r;
|
||||
}
|
||||
|
||||
var tags = {};
|
||||
for (var i = 0; i < tagRows.length; i++) {
|
||||
var r = tagRows[i];
|
||||
if (!r.module_id) {
|
||||
// no module_id, need to sync tags
|
||||
continue;
|
||||
}
|
||||
tags[r.tag] = r.version;
|
||||
}
|
||||
|
||||
var missingVersions = [];
|
||||
var missingTags = [];
|
||||
var missingDescriptions = [];
|
||||
var missingReadmes = [];
|
||||
var missingStarUsers = [];
|
||||
|
||||
ep.all('existsMap', 'existsTags', function (map, tags) {
|
||||
var times = pkg.time || {};
|
||||
pkg.versions = pkg.versions || {};
|
||||
var versionNames = Object.keys(times);
|
||||
if (versionNames.length === 0) {
|
||||
versionNames = Object.keys(pkg.versions);
|
||||
// get the missing star users
|
||||
var starUsers = pkg.users || {};
|
||||
for (var k in starUsers) {
|
||||
if (!existsStarUsers[k]) {
|
||||
missingStarUsers.push(k);
|
||||
}
|
||||
if (versionNames.length === 0) {
|
||||
that.log(' [%s] no times and no versions, hasModules: %s', name, hasModules);
|
||||
if (!hasModules) {
|
||||
// save a next module
|
||||
var maintainer = pkg.maintainers && pkg.maintainers[0];
|
||||
if (maintainer && maintainer.name) {
|
||||
maintainer = maintainer.name;
|
||||
}
|
||||
if (!maintainer) {
|
||||
maintainer = '-';
|
||||
}
|
||||
var nextMod = {
|
||||
}
|
||||
that.log(' [%s] found %d missing star users', name, missingStarUsers.length);
|
||||
|
||||
|
||||
var times = pkg.time || {};
|
||||
pkg.versions = pkg.versions || {};
|
||||
var versionNames = Object.keys(times);
|
||||
if (versionNames.length === 0) {
|
||||
versionNames = Object.keys(pkg.versions);
|
||||
}
|
||||
if (versionNames.length === 0) {
|
||||
that.log(' [%s] no times and no versions, hasModules: %s', name, hasModules);
|
||||
if (!hasModules) {
|
||||
// save a next module
|
||||
var maintainer = pkg.maintainers && pkg.maintainers[0];
|
||||
if (maintainer && maintainer.name) {
|
||||
maintainer = maintainer.name;
|
||||
}
|
||||
if (!maintainer) {
|
||||
maintainer = '-';
|
||||
}
|
||||
var nextMod = {
|
||||
name: name,
|
||||
version: 'next',
|
||||
author: maintainer,
|
||||
package: {
|
||||
name: name,
|
||||
version: 'next',
|
||||
author: maintainer,
|
||||
package: {
|
||||
name: name,
|
||||
version: 'next',
|
||||
description: pkg.description || '',
|
||||
readme: pkg.readme || '',
|
||||
maintainers: pkg.maintainers || {
|
||||
name: maintainer
|
||||
},
|
||||
description: pkg.description || '',
|
||||
readme: pkg.readme || '',
|
||||
maintainers: pkg.maintainers || {
|
||||
name: maintainer
|
||||
},
|
||||
};
|
||||
Module.add(nextMod, function (err, result) {
|
||||
that.log(' [%s] save next module, %j, error: %s', name, result, err);
|
||||
});
|
||||
},
|
||||
};
|
||||
try {
|
||||
var result = yield Module.add(nextMod);
|
||||
that.log(' [%s] save next module, %j', name, result);
|
||||
} catch (err) {
|
||||
that.log(' [%s] save next module error %s', err.message);
|
||||
}
|
||||
}
|
||||
var versions = [];
|
||||
for (var i = 0; i < versionNames.length; i++) {
|
||||
var v = versionNames[i];
|
||||
var exists = map[v] || {};
|
||||
var version = pkg.versions[v];
|
||||
if (!version || !version.dist) {
|
||||
}
|
||||
|
||||
var versions = [];
|
||||
for (var i = 0; i < versionNames.length; i++) {
|
||||
var v = versionNames[i];
|
||||
var exists = map[v] || {};
|
||||
var version = pkg.versions[v];
|
||||
if (!version || !version.dist || !version.dist.tarball) {
|
||||
continue;
|
||||
}
|
||||
//patch for readme
|
||||
if (!version.readme) {
|
||||
version.readme = pkg.readme;
|
||||
}
|
||||
var publish_time = times[v];
|
||||
version.publish_time = publish_time ? Date.parse(publish_time) : null;
|
||||
if (!version.maintainers || !version.maintainers[0]) {
|
||||
version.maintainers = pkg.maintainers;
|
||||
}
|
||||
var sourceAuthor = version.maintainers && version.maintainers[0] &&
|
||||
version.maintainers[0].name || exists.author;
|
||||
|
||||
if (exists.package && exists.package.dist.shasum === version.dist.shasum &&
|
||||
exists.author === sourceAuthor) {
|
||||
// * author make sure equal
|
||||
// * shasum make sure equal
|
||||
if ((version.publish_time === exists.publish_time) ||
|
||||
(!version.publish_time && exists.publish_time)) {
|
||||
// debug(' [%s] %s publish_time equal: %s, %s',
|
||||
// name, version.version, version.publish_time, exists.publish_time);
|
||||
// * publish_time make sure equal
|
||||
if (exists.description === null && version.description) {
|
||||
// * make sure description exists
|
||||
missingDescriptions.push({
|
||||
id: exists.id,
|
||||
description: version.description
|
||||
});
|
||||
}
|
||||
|
||||
if (!exists.package.readme && version.readme) {
|
||||
// * make sure readme exists
|
||||
missingReadmes.push({
|
||||
id: exists.id,
|
||||
readme: version.readme
|
||||
});
|
||||
}
|
||||
continue;
|
||||
}
|
||||
//patch for readme
|
||||
if (!version.readme) {
|
||||
version.readme = pkg.readme;
|
||||
}
|
||||
var publish_time = times[v];
|
||||
version.publish_time = publish_time ? Date.parse(publish_time) : null;
|
||||
if (!version.maintainers || !version.maintainers[0]) {
|
||||
version.maintainers = pkg.maintainers;
|
||||
}
|
||||
var sourceAuthor = version.maintainers && version.maintainers[0] && version.maintainers[0].name || exists.author;
|
||||
|
||||
if (exists.package && exists.package.dist.shasum === version.dist.shasum && exists.author === sourceAuthor) {
|
||||
// * author make sure equal
|
||||
// * shasum make sure equal
|
||||
if ((version.publish_time === exists.publish_time) || (!version.publish_time && exists.publish_time)) {
|
||||
debug(' [%s] %s publish_time equal: %s, %s',
|
||||
name, version.version, version.publish_time, exists.publish_time);
|
||||
// * publish_time make sure equal
|
||||
if (exists.description === null && version.description) {
|
||||
// * make sure description exists
|
||||
missingDescriptions.push({
|
||||
id: exists.id,
|
||||
description: version.description
|
||||
});
|
||||
}
|
||||
|
||||
if (!exists.package.readme && version.readme) {
|
||||
// * make sure readme exists
|
||||
missingReadmes.push({
|
||||
id: exists.id,
|
||||
readme: version.readme
|
||||
});
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
versions.push(version);
|
||||
}
|
||||
versions.push(version);
|
||||
}
|
||||
|
||||
var sourceTags = pkg['dist-tags'] || {};
|
||||
for (var t in sourceTags) {
|
||||
var sourceTagVersion = sourceTags[t];
|
||||
if (sourceTagVersion && tags[t] !== sourceTagVersion) {
|
||||
missingTags.push([t, sourceTagVersion]);
|
||||
}
|
||||
}
|
||||
|
||||
if (versions.length === 0) {
|
||||
that.log(' [%s] all versions are exists', name);
|
||||
return ep.emit('syncDone');
|
||||
var sourceTags = pkg['dist-tags'] || {};
|
||||
for (var t in sourceTags) {
|
||||
var sourceTagVersion = sourceTags[t];
|
||||
if (sourceTagVersion && tags[t] !== sourceTagVersion) {
|
||||
missingTags.push([t, sourceTagVersion]);
|
||||
}
|
||||
}
|
||||
|
||||
if (versions.length === 0) {
|
||||
that.log(' [%s] all versions are exists', name);
|
||||
} else {
|
||||
versions.sort(function (a, b) {
|
||||
return a.publish_time - b.publish_time;
|
||||
});
|
||||
missingVersions = versions;
|
||||
that.log(' [%s] %d versions', name, versions.length);
|
||||
ep.emit('syncModule', missingVersions.shift());
|
||||
});
|
||||
that.log(' [%s] %d versions need to sync', name, versions.length);
|
||||
}
|
||||
|
||||
missingVersions = versions;
|
||||
var versionNames = [];
|
||||
var syncIndex = 0;
|
||||
ep.on('syncModule', function (syncModule) {
|
||||
|
||||
// sync missing versions
|
||||
while (missingVersions.length) {
|
||||
var index = syncIndex++;
|
||||
that._syncOneVersion(index, syncModule, function (err, result) {
|
||||
if (err) {
|
||||
that.log(' [%s:%d] error, version: %s, %s: %s',
|
||||
syncModule.name, index, syncModule.version, err.name, err.message);
|
||||
} else {
|
||||
versionNames.push(syncModule.version);
|
||||
}
|
||||
var syncModule = missingVersions.shift();
|
||||
if (!syncModule.dist.tarball) {
|
||||
continue;
|
||||
}
|
||||
try {
|
||||
var result = yield that._syncOneVersion(index, syncModule);
|
||||
versionNames.push(syncModule.version);
|
||||
} catch (err) {
|
||||
that.log(' [%s:%d] error, version: %s, %s: %s',
|
||||
syncModule.name, index, syncModule.version, err.name, err.message);
|
||||
}
|
||||
}
|
||||
|
||||
var nextVersion = missingVersions.shift();
|
||||
if (!nextVersion) {
|
||||
return ep.emit('syncDone', result);
|
||||
}
|
||||
ep.emit('syncModule', nextVersion);
|
||||
});
|
||||
});
|
||||
|
||||
ep.on('syncDone', function () {
|
||||
// sync missing descriptions
|
||||
function *syncDes() {
|
||||
if (missingDescriptions.length === 0) {
|
||||
return ep.emit('descriptionDone');
|
||||
return;
|
||||
}
|
||||
|
||||
that.log(' [%s] saving %d descriptions', name, missingDescriptions.length);
|
||||
missingDescriptions.forEach(function (item) {
|
||||
Module.updateDescription(item.id, item.description, function (err, result) {
|
||||
if (err) {
|
||||
that.log(' save error, id: %s, description: %s, error: %s', item.id, item.description, err);
|
||||
} else {
|
||||
that.log(' saved, id: %s, description length: %d', item.id, item.description.length);
|
||||
}
|
||||
ep.emitLater('saveDescription');
|
||||
});
|
||||
});
|
||||
var res = yield gather(missingDescriptions.map(function (item) {
|
||||
return Module.updateDescription(item.id, item.description);
|
||||
}));
|
||||
|
||||
ep.after('saveDescription', missingDescriptions.length, function () {
|
||||
ep.emit('descriptionDone');
|
||||
});
|
||||
});
|
||||
|
||||
ep.on('syncDone', function () {
|
||||
if (missingTags.length === 0) {
|
||||
return ep.emit('tagDone');
|
||||
for (var i = 0; i < res.length; i++) {
|
||||
var item = missingDescriptions[i];
|
||||
var r = res[i];
|
||||
if (r.error) {
|
||||
that.log(' save error, id: %s, description: %s, error: %s',
|
||||
item.id, item.description, r.error.message);
|
||||
} else {
|
||||
that.log(' saved, id: %s, description length: %d',
|
||||
item.id, item.description.length);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// sync missing tags
|
||||
function *syncTag() {
|
||||
if (missingTags.length === 0) {
|
||||
return;
|
||||
}
|
||||
that.log(' [%s] adding %d tags', name, missingTags.length);
|
||||
// sync tags
|
||||
missingTags.forEach(function (item) {
|
||||
Module.addTag(name, item[0], item[1], ep.done(function (result) {
|
||||
that.log(' added tag %s:%s, module_id: %s', item[0], item[1], result && result.module_id);
|
||||
ep.emitLater('addTag');
|
||||
}));
|
||||
});
|
||||
|
||||
ep.after('addTag', missingTags.length, function () {
|
||||
ep.emit('tagDone');
|
||||
});
|
||||
});
|
||||
var res = yield gather(missingTags.map(function (item) {
|
||||
return Module.addTag(name, item[0], item[1]);
|
||||
}));
|
||||
|
||||
ep.once('syncDone', function () {
|
||||
for (var i = 0; i < res.length; i++) {
|
||||
var item = missingTags[i];
|
||||
var r = res[i];
|
||||
if (r.error) {
|
||||
that.log(' add tag %s:%s error, error: %s',
|
||||
item.id, item.description, r.error.message);
|
||||
} else {
|
||||
that.log(' added tag %s:%s, module_id: %s',
|
||||
item[0], item[1], r.value && r.value.module_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// sycn missing readme
|
||||
function *syncReadme() {
|
||||
if (missingReadmes.length === 0) {
|
||||
return ep.emit('readmeDone');
|
||||
return;
|
||||
}
|
||||
that.log(' [%s] saving %d readmes', name, missingReadmes.length);
|
||||
|
||||
var res = yield gather(missingReadmes.map(function (item) {
|
||||
return Module.updateReadme(item.id, item.readme);
|
||||
}));
|
||||
|
||||
for (var i = 0; i < res.length; i++) {
|
||||
var item = missingReadmes[i];
|
||||
var r = res[i];
|
||||
if (r.error) {
|
||||
that.log(' save error, id: %s, error: %s', item.id, r.error.message);
|
||||
} else {
|
||||
that.log(' saved, id: %s', item.id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// sync missing star users
|
||||
function *syncUser() {
|
||||
if (missingStarUsers.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
that.log(' [%s] saving %d readmes', name, missingReadmes.length);
|
||||
missingReadmes.forEach(function (item) {
|
||||
Module.updateReadme(item.id, item.readme, function (err, result) {
|
||||
if (err) {
|
||||
that.log(' save error, id: %s, error: %s', item.id, err);
|
||||
} else {
|
||||
that.log(' saved, id: %s', item.id);
|
||||
}
|
||||
ep.emitLater('saveReadme');
|
||||
});
|
||||
});
|
||||
that.log(' [%s] saving %d star users', name, missingStarUsers.length);
|
||||
var res = yield gather(missingStarUsers.map(function (username) {
|
||||
return _addStar(name, username);
|
||||
}));
|
||||
|
||||
ep.after('saveReadme', missingReadmes.length, function () {
|
||||
ep.emit('readmeDone');
|
||||
});
|
||||
});
|
||||
for (var i = 0; i < res.length; i++) {
|
||||
var r = res[i];
|
||||
if (r.error) {
|
||||
that.log(' add star user error, %s', r.error.message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ep.all('tagDone', 'descriptionDone', 'readmeDone', function () {
|
||||
// TODO: set latest version
|
||||
callback(null, versionNames);
|
||||
});
|
||||
yield [syncDes(), syncTag(), syncReadme(), syncUser()];
|
||||
return versionNames;
|
||||
};
|
||||
|
||||
SyncModuleWorker.prototype._syncOneVersion = function (versionIndex, sourcePackage, callback) {
|
||||
SyncModuleWorker.prototype._syncOneVersion = function *(versionIndex, sourcePackage) {
|
||||
var that = this;
|
||||
var username = this.username;
|
||||
var downurl = sourcePackage.dist.tarball;
|
||||
var filename = path.basename(downurl);
|
||||
var filepath = common.getTarballFilepath(filename);
|
||||
var ws = fs.createWriteStream(filepath);
|
||||
|
||||
var options = {
|
||||
writeStream: ws,
|
||||
followRedirect: true,
|
||||
timeout: 600000, // 10 minutes download
|
||||
};
|
||||
var ep = eventproxy.create();
|
||||
ep.fail(function (err) {
|
||||
// remove tmp file whatever
|
||||
fs.unlink(filepath, utility.noop);
|
||||
callback(err);
|
||||
});
|
||||
|
||||
var dependencies = Object.keys(sourcePackage.dependencies || {});
|
||||
var devDependencies = Object.keys(sourcePackage.devDependencies || {});
|
||||
|
||||
that.log(' [%s:%d] syncing, version: %s, dist: %j, no deps: %s, publish on cnpm: %s, dependencies: %d, devDependencies: %d',
|
||||
that.log(' [%s:%d] syncing, version: %s, dist: %j, no deps: %s, ' +
|
||||
'publish on cnpm: %s, dependencies: %d, devDependencies: %d',
|
||||
sourcePackage.name, versionIndex, sourcePackage.version,
|
||||
sourcePackage.dist, that.noDep, that._publish,
|
||||
dependencies.length, devDependencies.length);
|
||||
@@ -438,60 +510,68 @@ SyncModuleWorker.prototype._syncOneVersion = function (versionIndex, sourcePacka
|
||||
}
|
||||
}
|
||||
|
||||
// add deps relations
|
||||
dependencies.forEach(function (depName) {
|
||||
ModuleDeps.add(depName, sourcePackage.name, utility.noop);
|
||||
});
|
||||
// add module dependence
|
||||
try {
|
||||
yield dependencies.map(function (depName) {
|
||||
return ModuleDeps.add(depName, sourcePackage.name);
|
||||
});
|
||||
} catch (err) {
|
||||
// ignore
|
||||
}
|
||||
|
||||
var shasum = crypto.createHash('sha1');
|
||||
var dataSize = 0;
|
||||
urllib.request(downurl, options, ep.done(function (_, response) {
|
||||
|
||||
try {
|
||||
// get tarball
|
||||
var r = yield request(downurl, options);
|
||||
var response = r[1];
|
||||
var statusCode = response && response.statusCode || -1;
|
||||
if (statusCode === 404) {
|
||||
// just copy source dist
|
||||
shasum = sourcePackage.dist.shasum;
|
||||
return ep.emit('uploadResult', {
|
||||
return yield afterUpload({
|
||||
url: downurl
|
||||
});
|
||||
}
|
||||
|
||||
if (statusCode !== 200) {
|
||||
var err = new Error('Download ' + downurl + ' fail, status: ' + statusCode);
|
||||
err.name = 'DownloadTarballError';
|
||||
err.data = sourcePackage;
|
||||
return ep.emit('error', err);
|
||||
throw err;
|
||||
}
|
||||
|
||||
// read and check
|
||||
var rs = fs.createReadStream(filepath);
|
||||
rs.once('error', function (err) {
|
||||
ep.emit('error', err);
|
||||
});
|
||||
rs.on('data', function (data) {
|
||||
shasum.update(data);
|
||||
dataSize += data.length;
|
||||
});
|
||||
rs.on('end', function () {
|
||||
shasum = shasum.digest('hex');
|
||||
if (shasum !== sourcePackage.dist.shasum) {
|
||||
var err = new Error('Download ' + downurl + ' shasum:' + shasum + ' not match ' + sourcePackage.dist.shasum);
|
||||
err.name = 'DownloadTarballShasumError';
|
||||
err.data = sourcePackage;
|
||||
return ep.emit('error', err);
|
||||
}
|
||||
yield thunkify(rs)(); // after end event emit
|
||||
|
||||
var options = {
|
||||
key: common.getCDNKey(sourcePackage.name, filename),
|
||||
size: dataSize,
|
||||
shasum: shasum
|
||||
};
|
||||
nfs.upload(filepath, options, ep.done('uploadResult'));
|
||||
});
|
||||
}));
|
||||
// check shasum
|
||||
shasum = shasum.digest('hex');
|
||||
if (shasum !== sourcePackage.dist.shasum) {
|
||||
var err = new Error('Download ' + downurl + ' shasum:' + shasum +
|
||||
' not match ' + sourcePackage.dist.shasum);
|
||||
err.name = 'DownloadTarballShasumError';
|
||||
err.data = sourcePackage;
|
||||
throw err;
|
||||
}
|
||||
|
||||
ep.on('uploadResult', function (result) {
|
||||
options = {
|
||||
key: common.getCDNKey(sourcePackage.name, filename),
|
||||
size: dataSize,
|
||||
shasum: shasum
|
||||
};
|
||||
// upload to NFS
|
||||
var result = yield nfs.upload(filepath, options);
|
||||
return yield afterUpload(result);
|
||||
} finally {
|
||||
// remove tmp file whatever
|
||||
fs.unlink(filepath, utility.noop);
|
||||
}
|
||||
|
||||
function *afterUpload(result) {
|
||||
//make sure sync module have the correct author info
|
||||
//only if can not get maintainers, use the username
|
||||
var author = username;
|
||||
@@ -526,54 +606,41 @@ SyncModuleWorker.prototype._syncOneVersion = function (versionIndex, sourcePacka
|
||||
}
|
||||
|
||||
mod.package.dist = dist;
|
||||
Module.add(mod, ep.done(function (result) {
|
||||
that.log(' [%s:%s] done, insertId: %s, author: %s, version: %s, size: %d, publish_time: %j, publish on cnpm: %s',
|
||||
sourcePackage.name, versionIndex,
|
||||
result.id,
|
||||
author, mod.version, dataSize,
|
||||
new Date(mod.publish_time),
|
||||
that._publish);
|
||||
callback(null, result);
|
||||
}));
|
||||
});
|
||||
};
|
||||
var r = yield Module.add(mod);
|
||||
|
||||
SyncModuleWorker.sync = function (name, username, options, callback) {
|
||||
if (typeof options === 'function') {
|
||||
callback = options;
|
||||
options = null;
|
||||
that.log(' [%s:%s] done, insertId: %s, author: %s, version: %s, ' +
|
||||
'size: %d, publish_time: %j, publish on cnpm: %s',
|
||||
sourcePackage.name, versionIndex,
|
||||
r.id,
|
||||
author, mod.version, dataSize,
|
||||
new Date(mod.publish_time),
|
||||
that._publish);
|
||||
|
||||
return r;
|
||||
}
|
||||
options = options || {};
|
||||
npm.get(name, function (err, pkg, response) {
|
||||
if (err) {
|
||||
return callback(err);
|
||||
}
|
||||
if (!pkg || !pkg._rev) {
|
||||
return callback(null, {
|
||||
ok: false,
|
||||
statusCode: response.statusCode,
|
||||
pkg: pkg
|
||||
});
|
||||
}
|
||||
Log.create({name: name, username: username}, function (err, result) {
|
||||
if (err) {
|
||||
return callback(err);
|
||||
}
|
||||
var worker = new SyncModuleWorker({
|
||||
logId: result.id,
|
||||
name: name,
|
||||
username: username,
|
||||
noDep: options.noDep,
|
||||
publish: options.publish,
|
||||
});
|
||||
worker.start();
|
||||
callback(null, {
|
||||
ok: true,
|
||||
logId: result.id,
|
||||
pkg: pkg
|
||||
});
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
SyncModuleWorker.sync = thunkify(SyncModuleWorker.sync);
|
||||
SyncModuleWorker.sync = function *(name, username, options) {
|
||||
options = options || {};
|
||||
var pkg = yield npm.get(name);
|
||||
if (!pkg || !pkg._rev) {
|
||||
return {
|
||||
ok: false,
|
||||
pkg: pkg
|
||||
};
|
||||
}
|
||||
var result = yield Log.create({name: name, username: username});
|
||||
var worker = new SyncModuleWorker({
|
||||
logId: result.id,
|
||||
name: name,
|
||||
username: username,
|
||||
noDep: options.noDep,
|
||||
publish: options.publish,
|
||||
});
|
||||
worker.start();
|
||||
return {
|
||||
ok: true,
|
||||
logId: result.id,
|
||||
pkg: pkg
|
||||
};
|
||||
};
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/*!
|
||||
/**!
|
||||
* cnpmjs.org - routes/web.js
|
||||
*
|
||||
* Copyright(c) cnpmjs.org and other contributors.
|
||||
@@ -19,6 +19,7 @@ var pkg = require('../controllers/web/package');
|
||||
var user = require('../controllers/web/user');
|
||||
var sync = require('../controllers/sync');
|
||||
var total = require('../controllers/total');
|
||||
var dist = require('../controllers/web/dist');
|
||||
|
||||
function routes(app) {
|
||||
app.get('/total', total.show);
|
||||
@@ -34,6 +35,8 @@ function routes(app) {
|
||||
app.get('/sync', pkg.displaySync);
|
||||
|
||||
app.get('/_list/search/search', pkg.rangeSearch);
|
||||
|
||||
app.get(/^\/dist(\/.+)?/, dist.redirect);
|
||||
}
|
||||
|
||||
module.exports = routes;
|
||||
|
||||
@@ -18,8 +18,7 @@
|
||||
var koa = require('koa');
|
||||
var app = module.exports = koa();
|
||||
var http = require('http');
|
||||
var forward = require('forward');
|
||||
var path = require('path');
|
||||
var microtime = require('microtime');
|
||||
var middlewares = require('koa-middlewares');
|
||||
var routes = require('../routes/registry');
|
||||
var logger = require('../common/logger');
|
||||
@@ -27,9 +26,8 @@ var config = require('../config');
|
||||
var session = require('../common/session');
|
||||
var auth = require('../middleware/auth');
|
||||
var notFound = require('../middleware/registry_not_found');
|
||||
var rootdir = path.dirname(__dirname);
|
||||
|
||||
app.use(middlewares.rt({headerName: 'X-ReadTime'}));
|
||||
app.use(middlewares.rt({headerName: 'X-ReadTime', timer: microtime}));
|
||||
|
||||
app.use(middlewares.rewrite('/favicon.ico', '/public/favicon.ico'));
|
||||
|
||||
@@ -40,6 +38,7 @@ app.use(middlewares.bodyParser({jsonLimit: config.jsonLimit}));
|
||||
app.use(auth());
|
||||
app.use(notFound);
|
||||
|
||||
app.use(middlewares.gzip());
|
||||
app.use(middlewares.fresh());
|
||||
app.use(middlewares.etag());
|
||||
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
var path = require('path');
|
||||
var http = require('http');
|
||||
var fs = require('fs');
|
||||
var microtime = require('microtime');
|
||||
var koa = require('koa');
|
||||
var middlewares = require('koa-middlewares');
|
||||
var markdown = require('koa-markdown');
|
||||
@@ -32,7 +33,7 @@ var app = koa();
|
||||
|
||||
var rootdir = path.dirname(__dirname);
|
||||
|
||||
app.use(middlewares.rt({headerName: 'X-ReadTime'}));
|
||||
app.use(middlewares.rt({headerName: 'X-ReadTime', timer: microtime}));
|
||||
app.use(middlewares.staticCache(path.join(__dirname, '..', 'public'), {
|
||||
buffer: !config.debug,
|
||||
maxAge: config.debug ? 0 : 60 * 60 * 24 * 7,
|
||||
@@ -45,6 +46,10 @@ app.use(session);
|
||||
app.use(middlewares.bodyParser());
|
||||
app.use(notFound);
|
||||
|
||||
app.use(middlewares.gzip());
|
||||
app.use(middlewares.fresh());
|
||||
app.use(middlewares.etag());
|
||||
|
||||
var viewDir = path.join(rootdir, 'view', 'web');
|
||||
var docDir = path.join(rootdir, 'docs', 'web');
|
||||
|
||||
|
||||
@@ -22,8 +22,9 @@ var utility = require('utility');
|
||||
var debug = require('debug')('cnpmjs.org:sync:index');
|
||||
var Total = require('../proxy/total');
|
||||
var logger = require('../common/logger');
|
||||
var co = require('co');
|
||||
|
||||
var sync;
|
||||
var sync = null;
|
||||
|
||||
switch (config.syncModel) {
|
||||
case 'all':
|
||||
@@ -34,28 +35,41 @@ case 'exist':
|
||||
break;
|
||||
}
|
||||
|
||||
if (!sync && config.enableCluster) {
|
||||
console.log('[%s] [sync_worker:%s] no need to sync, exit now', Date(), process.pid);
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
console.log('[%s] [sync_worker:%s] syncing with %s mode',
|
||||
Date(), process.pid, config.syncModel);
|
||||
|
||||
//set sync_status = 0 at first
|
||||
Total.updateSyncStatus(0, utility.noop);
|
||||
|
||||
// the same time only sync once
|
||||
var syncing = false;
|
||||
|
||||
function handleSync() {
|
||||
var handleSync = co(function *() {
|
||||
debug('mode: %s, syncing: %s', config.syncModel, syncing);
|
||||
// check sync every one 30 minutes
|
||||
if (!syncing) {
|
||||
syncing = true;
|
||||
debug('start syncing');
|
||||
sync(function (err, data) {
|
||||
if (config.debug) {
|
||||
console.log(err, data);
|
||||
} else {
|
||||
sendMailToAdmin(err, data, new Date());
|
||||
}
|
||||
syncing = false;
|
||||
});
|
||||
var data;
|
||||
var error;
|
||||
try {
|
||||
var data = yield *sync();
|
||||
} catch (err) {
|
||||
error = err;
|
||||
}
|
||||
if (config.debug) {
|
||||
error && console.error(error.stack);
|
||||
data && console.log(data);
|
||||
} else {
|
||||
sendMailToAdmin(error, data, new Date());
|
||||
}
|
||||
syncing = false;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (sync) {
|
||||
handleSync();
|
||||
|
||||
@@ -19,18 +19,20 @@ var utility = require('utility');
|
||||
var Total = require('../proxy/total');
|
||||
|
||||
function Status(options) {
|
||||
this.worker = options.worker;
|
||||
this.need = options.need;
|
||||
this.lastSyncModule = '';
|
||||
this.successes = 0;
|
||||
this.fails = 0;
|
||||
this.left = options.need;
|
||||
}
|
||||
|
||||
Status.prototype.log = function (syncDone) {
|
||||
var params = {
|
||||
syncStatus: syncDone ? 0 : 1,
|
||||
need: this.need,
|
||||
success: this.worker.successes.length,
|
||||
fail: this.worker.fails.length,
|
||||
left: this.worker.names.length,
|
||||
success: this.successes,
|
||||
fail: this.fails,
|
||||
left: this.left,
|
||||
lastSyncModule: this.lastSyncModule,
|
||||
};
|
||||
Total.updateSyncNum(params, utility.noop);
|
||||
@@ -43,19 +45,30 @@ Status.prototype.start = function () {
|
||||
this.started = true;
|
||||
//every 30s log it into mysql
|
||||
this.timer = setInterval(this.log.bind(this), 30000);
|
||||
this.worker.on('success', function (moduleName) {
|
||||
debug('sync [%s] success', moduleName);
|
||||
this.lastSyncModule = moduleName;
|
||||
}.bind(this));
|
||||
this.worker.on('end', function () {
|
||||
this.started = false;
|
||||
this.log(true);
|
||||
clearInterval(this.timer);
|
||||
}.bind(this));
|
||||
};
|
||||
|
||||
Status.init = function (options) {
|
||||
return new Status(options);
|
||||
Status.init = function (options, worker) {
|
||||
var status = new Status(options);
|
||||
status.start();
|
||||
worker.on('success', function (moduleName) {
|
||||
debug('sync [%s] success', moduleName);
|
||||
status.lastSyncModule = moduleName;
|
||||
status.successes++;
|
||||
status.left--;
|
||||
});
|
||||
worker.on('fail', function () {
|
||||
status.fails++;
|
||||
status.left--;
|
||||
});
|
||||
worker.on('add', function () {
|
||||
status.left++;
|
||||
});
|
||||
|
||||
worker.on('end', function () {
|
||||
status.started = false;
|
||||
status.log(true);
|
||||
clearInterval(status.timer);
|
||||
});
|
||||
};
|
||||
|
||||
module.exports = Status;
|
||||
|
||||
149
sync/sync_all.js
149
sync/sync_all.js
@@ -24,6 +24,8 @@ var Npm = require('../proxy/npm');
|
||||
var Total = require('../proxy/total');
|
||||
var SyncModuleWorker = require('../proxy/sync_module_worker');
|
||||
var Module = require('../proxy/module');
|
||||
var co = require('co');
|
||||
var thunkify = require('thunkify-wrap');
|
||||
|
||||
function subtract(subtracter, minuend) {
|
||||
subtracter = subtracter || [];
|
||||
@@ -55,109 +57,86 @@ function union(arrOne, arrTwo) {
|
||||
* when sync from official at the first time
|
||||
* get all packages by short and restart from last synced module
|
||||
* @param {String} lastSyncModule
|
||||
* @param {Function} callback
|
||||
*/
|
||||
function getFirstSyncPackages(lastSyncModule, callback) {
|
||||
Npm.getShort(function (err, pkgs) {
|
||||
if (err || !lastSyncModule) {
|
||||
return callback(err, pkgs);
|
||||
}
|
||||
// start from last success
|
||||
var lastIndex = pkgs.indexOf(lastSyncModule);
|
||||
if (lastIndex > 0) {
|
||||
pkgs = pkgs.slice(lastIndex);
|
||||
}
|
||||
return callback(null, pkgs);
|
||||
});
|
||||
function *getFirstSyncPackages(lastSyncModule) {
|
||||
var pkgs = yield Npm.getShort();
|
||||
if (!lastSyncModule) {
|
||||
return pkgs;
|
||||
}
|
||||
// start from last success
|
||||
var lastIndex = pkgs.indexOf(lastSyncModule);
|
||||
if (lastIndex > 0) {
|
||||
return pkgs.slice(lastIndex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* get all the packages that update time > lastSyncTime
|
||||
* @param {Number} lastSyncTime
|
||||
* @param {Function} callback
|
||||
*/
|
||||
function getCommonSyncPackages(lastSyncTime, callback) {
|
||||
Npm.getAllSince(lastSyncTime, function (err, data) {
|
||||
if (err || !data) {
|
||||
return callback(err, []);
|
||||
}
|
||||
delete data._updated;
|
||||
return callback(null, Object.keys(data));
|
||||
});
|
||||
function *getCommonSyncPackages(lastSyncTime) {
|
||||
var data = yield Npm.getAllSince(lastSyncTime);
|
||||
if (!data) {
|
||||
return [];
|
||||
}
|
||||
delete data._updated;
|
||||
return Object.keys(data);
|
||||
}
|
||||
|
||||
/**
|
||||
* get all the missing packages
|
||||
* @param {Function} callback
|
||||
*/
|
||||
function getMissPackages(callback) {
|
||||
var ep = eventproxy.create();
|
||||
ep.fail(callback);
|
||||
Npm.getShort(ep.doneLater('allPackages'));
|
||||
Module.listAllModuleNames(ep.doneLater(function (rows) {
|
||||
var existPackages = rows.map(function (row) {
|
||||
return row.name;
|
||||
});
|
||||
ep.emit('existPackages', existPackages);
|
||||
}));
|
||||
ep.all('allPackages', 'existPackages', function (allPackages, existPackages) {
|
||||
callback(null, subtract(allPackages, existPackages));
|
||||
function *getMissPackages(callback) {
|
||||
var r = yield [Npm.getShort(), Module.listAllModuleNames];
|
||||
var allPackages = r[0];
|
||||
var existPackages = r[1].map(function (row) {
|
||||
return row.name;
|
||||
});
|
||||
return subtract(allPackages, existPackages);
|
||||
}
|
||||
|
||||
//only sync not exist once
|
||||
var syncNotExist = false;
|
||||
module.exports = function sync(callback) {
|
||||
var ep = eventproxy.create();
|
||||
ep.fail(callback);
|
||||
module.exports = function *sync() {
|
||||
var syncTime = Date.now();
|
||||
Total.getTotalInfo(ep.doneLater('totalInfo'));
|
||||
var info = yield Total.getTotalInfo();
|
||||
if (!info) {
|
||||
throw new Error('can not found total info');
|
||||
}
|
||||
|
||||
ep.once('totalInfo', function (info) {
|
||||
if (!info) {
|
||||
return callback(new Error('can not found total info'));
|
||||
}
|
||||
debug('Last sync time %s', new Date(info.last_sync_time));
|
||||
// TODO: 记录上次同步的最后一个模块名称
|
||||
if (!info.last_sync_time) {
|
||||
debug('First time sync all packages from official registry');
|
||||
return getFirstSyncPackages(info.last_sync_module, ep.done('syncPackages'));
|
||||
}
|
||||
if (syncNotExist) {
|
||||
getMissPackages(ep.done('missPackages'));
|
||||
syncNotExist = false;
|
||||
} else {
|
||||
ep.emitLater('missPackages', []);
|
||||
}
|
||||
getCommonSyncPackages(info.last_sync_time - ms('10m'), ep.doneLater('newestPackages'));
|
||||
ep.all('missPackages', 'newestPackages', function (missPackages, newestPackages) {
|
||||
ep.emit('syncPackages', union(missPackages, newestPackages));
|
||||
});
|
||||
});
|
||||
var packages;
|
||||
debug('Last sync time %s', new Date(info.last_sync_time));
|
||||
if (!info.last_sync_time) {
|
||||
debug('First time sync all packages from official registry');
|
||||
packages = yield getFirstSyncPackages(info.last_sync_module);
|
||||
} else {
|
||||
packages = yield getCommonSyncPackages(info.last_sync_time - ms('10m'));
|
||||
}
|
||||
|
||||
ep.once('syncPackages', function (packages) {
|
||||
packages = packages || [];
|
||||
debug('Total %d packages to sync', packages.length);
|
||||
var worker = new SyncModuleWorker({
|
||||
username: 'admin',
|
||||
name: packages,
|
||||
noDep: true,
|
||||
concurrency: config.syncConcurrency,
|
||||
});
|
||||
Status.init({
|
||||
worker: worker,
|
||||
need: packages.length
|
||||
}).start();
|
||||
worker.start();
|
||||
worker.once('end', function () {
|
||||
debug('All packages sync done, successes %d, fails %d',
|
||||
worker.successes.length, worker.fails.length);
|
||||
//only when all succss, set last sync time
|
||||
!worker.fails.length && Total.setLastSyncTime(syncTime, utility.noop);
|
||||
callback(null, {
|
||||
successes: worker.successes,
|
||||
fails: worker.fails
|
||||
});
|
||||
});
|
||||
packages = packages || [];
|
||||
if (!packages.length) {
|
||||
debug('no packages need be sync');
|
||||
return;
|
||||
}
|
||||
debug('Total %d packages to sync', packages.length);
|
||||
|
||||
var worker = new SyncModuleWorker({
|
||||
username: 'admin',
|
||||
name: packages,
|
||||
noDep: true,
|
||||
concurrency: config.syncConcurrency,
|
||||
});
|
||||
Status.init({need: packages.length}, worker);
|
||||
worker.start();
|
||||
yield thunkify(worker)();
|
||||
|
||||
debug('All packages sync done, successes %d, fails %d',
|
||||
worker.successes.length, worker.fails.length);
|
||||
//only when all succss, set last sync time
|
||||
if (!worker.fails.length) {
|
||||
Total.setLastSyncTime(syncTime, utility.noop);
|
||||
}
|
||||
return {
|
||||
successes: worker.successes,
|
||||
fails: worker.fails
|
||||
};
|
||||
};
|
||||
|
||||
@@ -24,6 +24,7 @@ var debug = require('debug')('cnpmjs.org:sync:sync_hot');
|
||||
var utility = require('utility');
|
||||
var Status = require('./status');
|
||||
var ms = require('ms');
|
||||
var thunkify = require('thunkify-wrap');
|
||||
|
||||
function intersection(arrOne, arrTwo) {
|
||||
arrOne = arrOne || [];
|
||||
@@ -39,71 +40,66 @@ function intersection(arrOne, arrTwo) {
|
||||
return results;
|
||||
}
|
||||
|
||||
module.exports = function sync(callback) {
|
||||
var ep = eventproxy.create();
|
||||
ep.fail(callback);
|
||||
module.exports = function *sync() {
|
||||
var syncTime = Date.now();
|
||||
|
||||
Module.listShort(ep.doneLater(function (packages) {
|
||||
packages = packages.map(function (p) {
|
||||
return p.name;
|
||||
});
|
||||
ep.emit('existPackages', packages);
|
||||
}));
|
||||
Total.getTotalInfo(ep.doneLater('totalInfo'));
|
||||
|
||||
ep.once('totalInfo', function (info) {
|
||||
if (!info) {
|
||||
return callback(new Error('can not found total info'));
|
||||
}
|
||||
if (!info.last_exist_sync_time) {
|
||||
debug('First time sync all packages from official registry');
|
||||
return Npm.getShort(ep.done(function (pkgs) {
|
||||
if (!info.last_sync_module) {
|
||||
return ep.emit('allPackages', pkgs);
|
||||
}
|
||||
// start from last success
|
||||
var lastIndex = pkgs.indexOf(info.last_sync_module);
|
||||
if (lastIndex > 0) {
|
||||
pkgs = pkgs.slice(lastIndex);
|
||||
}
|
||||
ep.emit('allPackages', pkgs);
|
||||
}));
|
||||
}
|
||||
Npm.getAllSince(info.last_exist_sync_time - ms('10m'), ep.done(function (data) {
|
||||
if (!data) {
|
||||
return ep.emit('allPackages', []);
|
||||
}
|
||||
if (data._updated) {
|
||||
syncTime = data._updated;
|
||||
delete data._updated;
|
||||
}
|
||||
|
||||
return ep.emit('allPackages', Object.keys(data));
|
||||
}));
|
||||
var r = yield [Module.listShort(), Total.getTotalInfo()];
|
||||
var existPackages = r[0].map(function (p) {
|
||||
return p.name;
|
||||
});
|
||||
var info = r[1];
|
||||
if (!info) {
|
||||
throw new Error('can not found total info');
|
||||
}
|
||||
|
||||
ep.all('existPackages', 'allPackages', function (existPackages, allPackages) {
|
||||
var packages = intersection(existPackages, allPackages);
|
||||
debug('Total %d packages to sync', packages.length);
|
||||
var worker = new SyncModuleWorker({
|
||||
username: 'admin',
|
||||
name: packages,
|
||||
concurrency: config.syncConcurrency,
|
||||
});
|
||||
Status.init({
|
||||
worker: worker,
|
||||
need: packages.length
|
||||
}).start();
|
||||
worker.start();
|
||||
worker.once('end', function () {
|
||||
debug('All packages sync done, successes %d, fails %d',
|
||||
worker.successes.length, worker.fails.length);
|
||||
Total.setLastExistSyncTime(syncTime, utility.noop);
|
||||
callback(null, {
|
||||
successes: worker.successes,
|
||||
fails: worker.fails
|
||||
});
|
||||
});
|
||||
var allPackages;
|
||||
if (!info.last_exist_sync_time) {
|
||||
debug('First time sync all packages from official registry');
|
||||
var pkgs = yield Npm.getShort();
|
||||
|
||||
if (info.last_sync_module) {
|
||||
// start from last success
|
||||
var lastIndex = pkgs.indexOf(info.last_sync_module);
|
||||
if (lastIndex > 0) {
|
||||
pkgs = pkgs.slice(lastIndex);
|
||||
}
|
||||
}
|
||||
allPackages = pkgs;
|
||||
} else {
|
||||
debug('sync new module from last exist sync time: %s', info.last_sync_time);
|
||||
var data = yield Npm.getAllSince(info.last_exist_sync_time - ms('10m'));
|
||||
if (!data) {
|
||||
allPackages = [];
|
||||
}
|
||||
if (data._updated) {
|
||||
syncTime = data._updated;
|
||||
delete data._updated;
|
||||
}
|
||||
allPackages = Object.keys(data);
|
||||
}
|
||||
|
||||
var packages = intersection(existPackages, allPackages);
|
||||
if (!packages.length) {
|
||||
debug('no packages need be sync');
|
||||
return;
|
||||
}
|
||||
debug('Total %d packages to sync', packages.length);
|
||||
|
||||
var worker = new SyncModuleWorker({
|
||||
username: 'admin',
|
||||
name: packages,
|
||||
concurrency: config.syncConcurrency
|
||||
});
|
||||
Status.init({need: packages.length}, worker);
|
||||
worker.start();
|
||||
yield thunkify(worker)();
|
||||
|
||||
debug('All packages sync done, successes %d, fails %d',
|
||||
worker.successes.length, worker.fails.length);
|
||||
|
||||
Total.setLastExistSyncTime(syncTime, utility.noop);
|
||||
return {
|
||||
successes: worker.successes,
|
||||
fails: worker.fails
|
||||
};
|
||||
};
|
||||
|
||||
@@ -72,6 +72,7 @@ describe('controllers/registry/module.test.js', function () {
|
||||
it('should return module info and etag', function (done) {
|
||||
request(app)
|
||||
.get('/cnpmjs.org')
|
||||
.expect('content-type', 'application/json')
|
||||
.expect(200, function (err, res) {
|
||||
should.not.exist(err);
|
||||
// should have etag
|
||||
@@ -79,7 +80,34 @@ describe('controllers/registry/module.test.js', function () {
|
||||
etag = res.headers.etag;
|
||||
res.body.should.have.keys('_id', '_rev', 'name', 'description',
|
||||
'versions', 'dist-tags', 'readme', 'maintainers',
|
||||
'time', 'author', 'repository', '_attachments');
|
||||
'time', 'author', 'repository', '_attachments',
|
||||
'users', 'readmeFilename', 'homepage', 'bugs', 'license');
|
||||
res.body.name.should.equal('cnpmjs.org');
|
||||
res.body.versions[Object.keys(res.body.versions)[0]]
|
||||
.dist.tarball.should.include('/cnpmjs.org/download');
|
||||
res.body.time.should.have.property('modified');
|
||||
res.body.time.modified.should.be.a.String;
|
||||
res.body.time.should.have.property('created');
|
||||
res.body.time.created.should.be.a.String;
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should return module info and gzip when accept-encoding=gzip', function (done) {
|
||||
request(app)
|
||||
.get('/cnpmjs.org')
|
||||
.set('accept-encoding', 'gzip')
|
||||
.expect('content-encoding', 'gzip')
|
||||
.expect(200, function (err, res) {
|
||||
// console.log(res.headers)
|
||||
should.not.exist(err);
|
||||
// should have etag
|
||||
res.headers.should.have.property('etag');
|
||||
etag = res.headers.etag;
|
||||
res.body.should.have.keys('_id', '_rev', 'name', 'description',
|
||||
'versions', 'dist-tags', 'readme', 'maintainers',
|
||||
'time', 'author', 'repository', '_attachments',
|
||||
'users', 'readmeFilename', 'homepage', 'bugs', 'license');
|
||||
res.body.name.should.equal('cnpmjs.org');
|
||||
res.body.versions[Object.keys(res.body.versions)[0]].dist.tarball.should.include('/cnpmjs.org/download');
|
||||
done();
|
||||
@@ -90,7 +118,7 @@ describe('controllers/registry/module.test.js', function () {
|
||||
request(app)
|
||||
.get('/cnpmjs.org')
|
||||
.set('If-None-Match', etag)
|
||||
.expect(304, done)
|
||||
.expect(304, done);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -217,7 +245,7 @@ describe('controllers/registry/module.test.js', function () {
|
||||
.expect(200, function (err, res) {
|
||||
should.not.exist(err);
|
||||
res.body.should.have.keys('_id', '_rev', 'name', 'description', 'versions', 'dist-tags',
|
||||
'readme', 'maintainers', 'time', '_attachments');
|
||||
'readme', 'maintainers', 'time', '_attachments', 'users');
|
||||
res.body.versions.should.eql({});
|
||||
res.body.time.should.eql({});
|
||||
res.body['dist-tags'].should.eql({});
|
||||
@@ -535,35 +563,7 @@ describe('controllers/registry/module.test.js', function () {
|
||||
request(app)
|
||||
.get('/cutter/download/cutter-0.0.2.tgz')
|
||||
.expect('Location', 'http://qtestbucket.qiniudn.com/cutter/-/cutter-0.0.2.tgz')
|
||||
.expect(302, done)
|
||||
});
|
||||
|
||||
it('should download a file direct from nfs stream', function (done) {
|
||||
var nfs = require('../../../common/nfs');
|
||||
mm(nfs, 'downloadStream', thunkify(function (key, writeStream, options, callback) {
|
||||
options.timeout.should.equal(600000);
|
||||
nfs._client.download(key, {writeStream: writeStream, timeout: options.timeout}, callback);
|
||||
}));
|
||||
Module.__get__ = Module.get;
|
||||
mm(Module, 'get', thunkify(function (name, version, callback) {
|
||||
Module.__get__(name, version, function (err, info) {
|
||||
info.package.dist.key = 'cutter/-/cutter-0.0.2.tgz';
|
||||
callback(err, info);
|
||||
});
|
||||
}));
|
||||
request(app)
|
||||
.get('/cutter/download/cutter-0.0.2.tgz')
|
||||
.expect('ETag', 'c61fde5e8c26d053574d0c722097029fd1bc963a')
|
||||
.expect('Content-Type', 'application/octet-stream')
|
||||
.expect('Content-Length', '3139')
|
||||
.expect('Content-Disposition', 'attachment; filename="cutter-0.0.2.tgz"')
|
||||
.expect(200)
|
||||
.end(function (err, res) {
|
||||
should.not.exist(err);
|
||||
// TODO: why supertest change buffer to text?
|
||||
// res.text.length.should.equal(3139);
|
||||
done();
|
||||
});
|
||||
.expect(302, done);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
37
test/controllers/web/dist.test.js
Normal file
37
test/controllers/web/dist.test.js
Normal file
@@ -0,0 +1,37 @@
|
||||
/**!
|
||||
* cnpmjs.org - test/controllers/web/dist.test.js
|
||||
*
|
||||
* Copyright(c) cnpmjs.org and other contributors.
|
||||
* MIT Licensed
|
||||
*
|
||||
* Authors:
|
||||
* fengmk2 <fengmk2@gmail.com> (http://fengmk2.cnpmjs.org)
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var should = require('should');
|
||||
var request = require('supertest');
|
||||
var app = require('../../../servers/web');
|
||||
|
||||
describe('controllers/web/dist.test.js', function () {
|
||||
before(function (done) {
|
||||
app.listen(0, done);
|
||||
});
|
||||
after(function (done) {
|
||||
app.close(done);
|
||||
});
|
||||
|
||||
describe('GET /dist', function (done) {
|
||||
it('should 302 to config.disturl', function (done) {
|
||||
request(app)
|
||||
.get('/dist')
|
||||
.expect('Location', 'http://dist.u.qiniudn.com/')
|
||||
.expect(302, done);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -35,6 +35,7 @@ describe('controllers/web/package.test.js', function () {
|
||||
it('should search with "c"', function (done) {
|
||||
request(app)
|
||||
.get('/_list/search/search?startkey="c"&limit=2')
|
||||
.expect('content-type', 'application/json')
|
||||
.expect(200, function (err, res) {
|
||||
should.not.exist(err);
|
||||
res.body.should.have.keys('rows');
|
||||
@@ -78,9 +79,16 @@ describe('controllers/web/package.test.js', function () {
|
||||
request(app)
|
||||
.get('/package/cutter')
|
||||
.expect(200)
|
||||
.expect('content-encoding', 'gzip')
|
||||
.expect('content-type', 'text/html; charset=utf-8')
|
||||
.expect(/<div id="package">/)
|
||||
.expect(/<th>Maintainers<\/th>/)
|
||||
.expect(/<th>Version<\/th>/, done);
|
||||
.expect(/<th>Version<\/th>/, function (err, res) {
|
||||
should.not.exist(err);
|
||||
res.should.have.header('etag');
|
||||
res.text.should.include('<meta charset="utf-8">');
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should get 404', function (done) {
|
||||
@@ -162,7 +170,7 @@ describe('controllers/web/package.test.js', function () {
|
||||
url: 'http://opensource.org/licenses/MIT'
|
||||
});
|
||||
|
||||
var p = {license: ['http://foo/MIT']};
|
||||
p = {license: ['http://foo/MIT']};
|
||||
pkg.setLicense(p);
|
||||
p.license.should.have.keys('name', 'url');
|
||||
p.license.should.eql({
|
||||
@@ -170,7 +178,7 @@ describe('controllers/web/package.test.js', function () {
|
||||
url: 'http://foo/MIT'
|
||||
});
|
||||
|
||||
var p = {license: {name: 'mit', url: 'http://foo/mit'}};
|
||||
p = {license: {name: 'mit', url: 'http://foo/mit'}};
|
||||
pkg.setLicense(p);
|
||||
p.license.should.have.keys('name', 'url');
|
||||
p.license.should.eql({
|
||||
|
||||
@@ -31,6 +31,7 @@ describe('controllers/web/user.test.js', function () {
|
||||
request(app)
|
||||
.get('/~dead_horse')
|
||||
.expect(200)
|
||||
.expect('content-type', 'text/html; charset=utf-8')
|
||||
.expect(/<div id="profile">/)
|
||||
.expect(/Packages by /, done);
|
||||
});
|
||||
|
||||
63
test/middleware/web_not_found.test.js
Normal file
63
test/middleware/web_not_found.test.js
Normal file
@@ -0,0 +1,63 @@
|
||||
/**!
|
||||
* cnpmjs.org - test/middleware/web_not_found.test.js
|
||||
*
|
||||
* Copyright(c) cnpmjs.org and other contributors.
|
||||
* MIT Licensed
|
||||
*
|
||||
* Authors:
|
||||
* fengmk2 <fengmk2@gmail.com> (http://fengmk2.github.com)
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var should = require('should');
|
||||
var request = require('supertest');
|
||||
var app = require('../../servers/web');
|
||||
|
||||
describe('middleware/web_not_found.test.js', function () {
|
||||
before(function (done) {
|
||||
app.listen(0, done);
|
||||
});
|
||||
|
||||
after(function (done) {
|
||||
app.close(done);
|
||||
});
|
||||
|
||||
describe('web_not_found()', function () {
|
||||
it('should redirect /byte to /package/byte', function (done) {
|
||||
request(app)
|
||||
.get('/byte')
|
||||
.expect('Location', '/package/byte')
|
||||
.expect(302, done);
|
||||
});
|
||||
|
||||
it('should redirect /byte/ to /package/byte', function (done) {
|
||||
request(app)
|
||||
.get('/byte/')
|
||||
.expect('Location', '/package/byte')
|
||||
.expect(302, done);
|
||||
});
|
||||
|
||||
it('should 404 /~byte', function (done) {
|
||||
request(app)
|
||||
.get('/~byte')
|
||||
.expect(404, done);
|
||||
});
|
||||
|
||||
it('should 200 /package/byte', function (done) {
|
||||
request(app)
|
||||
.get('/package/byte')
|
||||
.expect(200, done);
|
||||
});
|
||||
|
||||
it('should 404 /package/byte404', function (done) {
|
||||
request(app)
|
||||
.get('/package/byte404')
|
||||
.expect(404, done);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -158,7 +158,7 @@ describe('proxy/module.test.js', function () {
|
||||
should.not.exist(err);
|
||||
data.package.readme.should.equal('test');
|
||||
done();
|
||||
})
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
64
test/proxy/module_star.test.js
Normal file
64
test/proxy/module_star.test.js
Normal file
@@ -0,0 +1,64 @@
|
||||
/**!
|
||||
* cnpmjs.org - test/proxy/module_star.test.js
|
||||
*
|
||||
* Copyright(c) cnpmjs.org and other contributors.
|
||||
* MIT Licensed
|
||||
*
|
||||
* Authors:
|
||||
* fengmk2 <fengmk2@gmail.com> (http://fengmk2.github.com)
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var should = require('should');
|
||||
var co = require('co');
|
||||
var Star = require('../../proxy/module_star');
|
||||
|
||||
describe('proxy/module_star.test.js', function () {
|
||||
before(function (done) {
|
||||
co(function *() {
|
||||
yield Star.remove('testmodule', 'fengmk2');
|
||||
yield Star.remove('testmodule', 'mk1');
|
||||
yield Star.remove('testmodule', 'mk2');
|
||||
done();
|
||||
})();
|
||||
});
|
||||
|
||||
it('should add a star', function (done) {
|
||||
co(function *() {
|
||||
yield Star.add('testmodule', 'fengmk2');
|
||||
// again should be ok
|
||||
yield Star.add('testmodule', 'fengmk2');
|
||||
yield Star.add('testmodule', 'fengmk2');
|
||||
done();
|
||||
})();
|
||||
});
|
||||
|
||||
it('should get all star users', function (done) {
|
||||
co(function *() {
|
||||
yield Star.add('testmodule', 'fengmk2');
|
||||
yield Star.add('testmodule', 'mk1');
|
||||
yield Star.add('testmodule', 'mk2');
|
||||
|
||||
var rows = yield Star.listUsers('testmodule');
|
||||
rows.should.containDeep(['fengmk2', 'mk1', 'mk2']);
|
||||
done();
|
||||
})();
|
||||
});
|
||||
|
||||
it('should get user all star modules', function (done) {
|
||||
co(function *() {
|
||||
yield Star.add('testmodule', 'fengmk2');
|
||||
yield Star.add('testmodule1', 'fengmk2');
|
||||
yield Star.add('testmodule2', 'fengmk2');
|
||||
|
||||
var rows = yield Star.listUserModules('fengmk2');
|
||||
rows.should.containDeep(['testmodule', 'testmodule1', 'testmodule2']);
|
||||
done();
|
||||
})();
|
||||
});
|
||||
});
|
||||
@@ -19,6 +19,7 @@ var mm = require('mm');
|
||||
var fs = require('fs');
|
||||
var path = require('path');
|
||||
var npm = require('../../proxy/npm');
|
||||
var co = require('co');
|
||||
|
||||
var fixtures = path.join(path.dirname(__dirname), 'fixtures');
|
||||
|
||||
@@ -26,41 +27,45 @@ describe('proxy/npm.test.js', function () {
|
||||
afterEach(mm.restore);
|
||||
|
||||
it('should return a module info from source npm', function (done) {
|
||||
npm.get('pedding', function (err, data) {
|
||||
should.not.exist(err);
|
||||
should.exist(data);
|
||||
co(function *() {
|
||||
var data = yield npm.get('pedding');
|
||||
data.name.should.equal('pedding');
|
||||
done();
|
||||
});
|
||||
})();
|
||||
});
|
||||
|
||||
it('should return null when module not exist', function (done) {
|
||||
npm.get('pedding-not-exists', function (err, data) {
|
||||
should.not.exist(err);
|
||||
co(function *() {
|
||||
var data = yield npm.get('pedding-not-exists');
|
||||
should.not.exist(data);
|
||||
done();
|
||||
});
|
||||
})();
|
||||
});
|
||||
|
||||
it('should return error when http error', function (done) {
|
||||
mm.http.request(/\//, '{');
|
||||
npm.get('pedding-not-exists', function (err, data) {
|
||||
should.exist(err);
|
||||
err.name.should.equal('JSONResponseFormatError');
|
||||
should.not.exist(data);
|
||||
done();
|
||||
});
|
||||
co(function *() {
|
||||
try {
|
||||
var data = yield npm.get('pedding-not-exists');
|
||||
} catch (err) {
|
||||
err.name.should.equal('JSONResponseFormatError');
|
||||
done();
|
||||
}
|
||||
})();
|
||||
});
|
||||
|
||||
it('should return ServerError when http 500 response', function (done) {
|
||||
var content = fs.readFileSync(path.join(fixtures, '500.txt'), 'utf8');
|
||||
mm.http.request(/\//, content, { statusCode: 500 });
|
||||
// http://registry.npmjs.org/octopie
|
||||
npm.get('octopie', function (err, data) {
|
||||
should.exist(err);
|
||||
err.name.should.equal('NPMServerError');
|
||||
err.message.should.equal('Status 500, ' + content);
|
||||
done();
|
||||
});
|
||||
co(function *() {
|
||||
try {
|
||||
var data = yield npm.get('octopie');
|
||||
} catch (err) {
|
||||
err.name.should.equal('NPMServerError');
|
||||
err.message.should.equal('Status 500, ' + content);
|
||||
done();
|
||||
}
|
||||
})();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -18,8 +18,8 @@ var SyncModuleWorker = require('../proxy/sync_module_worker');
|
||||
var mysql = require('../common/mysql');
|
||||
var Log = require('../proxy/module_log');
|
||||
|
||||
var name = process.argv[2] || 'address,pedding';
|
||||
var names = name.split(',');
|
||||
var names = process.argv[2] || 'byte';
|
||||
names = names.split(',');
|
||||
|
||||
Log.create({
|
||||
name: names[0],
|
||||
@@ -30,8 +30,8 @@ Log.create({
|
||||
name: names,
|
||||
username: 'fengmk2',
|
||||
concurrency: names.length,
|
||||
noDep: true,
|
||||
publish: true,
|
||||
// noDep: true,
|
||||
// publish: true,
|
||||
});
|
||||
|
||||
worker.start();
|
||||
|
||||
@@ -19,6 +19,7 @@ var Npm = require('../../proxy/npm');
|
||||
var Total = require('../../proxy/total');
|
||||
var should = require('should');
|
||||
var Module = require('../../proxy/module');
|
||||
var co = require('co');
|
||||
|
||||
describe('sync/sync_all.js', function () {
|
||||
describe('sync()', function () {
|
||||
@@ -27,16 +28,14 @@ describe('sync/sync_all.js', function () {
|
||||
it('should sync first time ok', function (done) {
|
||||
mm.data(Npm, 'getShort', ['cnpmjs.org', 'cutter']);
|
||||
mm.data(Total, 'getTotalInfo', {last_sync_time: 0});
|
||||
sync(function (err, data) {
|
||||
should.not.exist(err);
|
||||
co(function *() {
|
||||
var data = yield sync;
|
||||
data.successes.should.eql(['cnpmjs.org', 'cutter']);
|
||||
mm.restore();
|
||||
Total.getTotalInfo(function (err, result) {
|
||||
should.not.exist(err);
|
||||
result.last_sync_module.should.equal('cutter');
|
||||
done();
|
||||
});
|
||||
});
|
||||
var result = yield Total.getTotalInfo();
|
||||
result.last_sync_module.should.equal('cutter');
|
||||
done();
|
||||
})();
|
||||
});
|
||||
|
||||
it('should sync common ok', function (done) {
|
||||
@@ -48,11 +47,12 @@ describe('sync/sync_all.js', function () {
|
||||
mm.data(Npm, 'getShort', ['cnpmjs.org', 'cutter', 'cnpm']);
|
||||
mm.data(Total, 'getTotalInfo', {last_sync_time: Date.now()});
|
||||
mm.data(Module, 'listAllModuleNames', [{name: 'cnpmjs.org'}, {name: 'cutter'}]);
|
||||
sync(function (err, data) {
|
||||
should.not.exist(err);
|
||||
data.successes.should.eql(['cnpm', 'cnpmjs.org', 'cutter']);
|
||||
co(function *() {
|
||||
var data = yield sync;
|
||||
data.successes.should.eql(['cnpmjs.org', 'cutter']);
|
||||
mm.restore();
|
||||
done();
|
||||
});
|
||||
})();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -18,6 +18,7 @@ var mm = require('mm');
|
||||
var Npm = require('../../proxy/npm');
|
||||
var Total = require('../../proxy/total');
|
||||
var should = require('should');
|
||||
var co = require('co');
|
||||
|
||||
describe('sync/sync_exist.js', function () {
|
||||
describe('sync()', function () {
|
||||
@@ -26,11 +27,11 @@ describe('sync/sync_exist.js', function () {
|
||||
it('should sync first time ok', function (done) {
|
||||
mm.data(Npm, 'getShort', ['cnpmjs.org', 'cutter']);
|
||||
mm.data(Total, 'getTotalInfo', {last_exist_sync_time: 0});
|
||||
sync(function (err, data) {
|
||||
should.not.exist(err);
|
||||
co(function *() {
|
||||
var data = yield sync();
|
||||
data.successes.should.eql(['cnpmjs.org', 'cutter']);
|
||||
done();
|
||||
});
|
||||
})();
|
||||
});
|
||||
|
||||
it('should sync common ok', function (done) {
|
||||
@@ -40,11 +41,11 @@ describe('sync/sync_exist.js', function () {
|
||||
cutter: {}
|
||||
});
|
||||
mm.data(Total, 'getTotalInfo', {last_exist_sync_time: Date.now()});
|
||||
sync(function (err, data) {
|
||||
should.not.exist(err);
|
||||
co(function *() {
|
||||
var data = yield sync();
|
||||
data.successes.should.eql(['cnpmjs.org', 'cutter']);
|
||||
done();
|
||||
});
|
||||
})();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title><%- locals.title %></title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<link rel="shortcut icon" href="/public/favicon.png">
|
||||
|
||||
@@ -188,27 +188,27 @@
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<% if (package.users) {
|
||||
var starredBy = package.starredBy
|
||||
var l = starredBy.length
|
||||
<% if (package.users.length > 0) {
|
||||
var users = package.users
|
||||
var l = users.length
|
||||
%>
|
||||
<tr>
|
||||
<th>Starred by<%= l > 0 ? ' (' + l + ')' : '' %></th>
|
||||
<th>Starred by (<%= l %>)</th>
|
||||
<td>
|
||||
<%
|
||||
var max = 20
|
||||
if (l > max) {
|
||||
starredBy = starredBy.sort(function (a, b) {
|
||||
users = users.sort(function (a, b) {
|
||||
return Math.random() * 2 - 1
|
||||
}).slice(0, max)
|
||||
}
|
||||
starredBy.forEach(function (user, i) {
|
||||
users.forEach(function (user, i) {
|
||||
if (i > 0) { %>, <% }
|
||||
%><a href="/~<%= user %>"><%= user %></a><%
|
||||
})
|
||||
if (l > max) {
|
||||
%><br><a href="/browse/star/<%= package.name %>">and
|
||||
<%= (l-max) %> more</a><%
|
||||
<%= (l - max) %> more</a><%
|
||||
}
|
||||
%>
|
||||
</td>
|
||||
|
||||
Reference in New Issue
Block a user