Skip to content

Instantly share code, notes, and snippets.

@Filirom1
Created September 23, 2011 23:39
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Filirom1/1238724 to your computer and use it in GitHub Desktop.
Save Filirom1/1238724 to your computer and use it in GitHub Desktop.
Choose the package to sync in npm
request = require 'request'
semver = require 'semver'
colors = require 'colors'
prompt = require 'prompt'
nopt = require 'nopt'
{EventEmitter} = require 'events'
# TODO: handle latest
# TODO: interactive mode
# Usage : coffee npm-sync.coffee -d express:1.7.1
showUsage = ->
console.error "Please specify a package:version"
# optional parameters
knownOpts =
dependencies: Boolean
host: String
port: Number
shortHands =
d: ['--dependencies']
h: ['--host']
p: ['--port']
options = nopt(knownOpts, shortHands, process.argv, 2)
# Default values
options.host || (options.host = 'localhost')
options.port || (options.port = 5984)
# URL of the public NPM registry
publicUrl = (package, version = "") ->
"http://isaacs.ic.ht/registry/_design/app/_rewrite/#{package}/#{version}"
# URL of your private NPM registry
privateUrl = (package, version = "") ->
"http://#{options.host}:#{options.port}/registry/_design/app/_rewrite/#{package}/#{version}"
# resolve NPM semantic version, i.e. '1.x || >=2.5.0 || 5.0.0 - 7.2.3'
resolveSemVer = (package, semVersion, callback) ->
# Fisrt read all versions
_get package, null, (err, data) ->
return callback err if err
# Filter the satisfying versions
satisfyingVersions = (version for version of data.versions when semver.satisfies(version, semVersion))
return callback new Error("Unable to resolve version '#{semVersion}' for #{package}") unless satisfyingVersions
# By default choose the last one
satisfyingVersion = satisfyingVersions[satisfyingVersions.length-1]
callback null, satisfyingVersion
# Sync also the package dependencies
getPackageAndDeps = (package, version, callback) ->
_get package, version, (err, data) ->
callback(err, data)
for depName, depVersion of data.dependencies
syncPackage depName, depVersion
# HTTP GET to the public NPM registry
_get = (package, version, callback) ->
uri = publicUrl package, version
console.log "GET #{uri}".grey
request
method: 'GET'
uri: uri
'content-type': 'application/json'
(err, resp, body) ->
return callback err if err
return callback (statusCode: resp.statusCode, body: body) if resp.statusCode is not 200
json = JSON.parse body
return callback (json.error) if json && json.error
# Clean the json of private fields
delete json[key] for key of json when key.indexOf('_') != -1
callback null, json
# HTTP PUT to our private NPM registry
_put = (package, version, data, callback) ->
uri = privateUrl package, version
console.log "PUT #{uri}".grey
request
method: 'PUT'
uri: uri
'content-type': 'application/json'
body: JSON.stringify data
(err, resp, body) ->
return callback "Unable to PUT #{uri}", err if err
return callback (statusCode: resp.statusCode, body: body) if resp.statusCode is not 204
json = JSON.parse body
return callback json.error, body if json && json.error
callback null, body
# main method
# Sync a package from the NPM public registry to our private NPM registry
syncPackage = (package, semVersion, callback) ->
callback || callback = (err, data) ->
return console.error "✗ #{package}:#{semVersion} failed to synchronized: #{err} #{data or ''}".red if err
console.log "✔ #{package}:#{semVersion} successfully synchronized.".green.bold
resolveSemVer package, semVersion, (err, version) ->
return callback err if err
# can also sync the dependencies
get = if options.dependencies then getPackageAndDeps else _get
get package, version, (err, data) ->
return callback err if err
_put package, version, data, (err, data) ->
return callback err if err
callback null, data
return showUsage() unless process.argv.length >= 3
# Read stdin as a package:version argument
[package, version] = process.argv[process.argv.length-1].split(':')
return showUsage() unless package and version
# Go go synchronize now !!!
syncPackage package, version
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment