├── .npmrc ├── lib ├── utils │ ├── is-root.js │ ├── nm.js │ ├── node-gyp.js │ ├── drop-privilege.js │ ├── npmrc.js │ └── git.js ├── install │ ├── installer │ │ ├── local.js │ │ ├── git.js │ │ ├── remote.js │ │ ├── registry.js │ │ └── bin.js │ ├── resolver │ │ ├── fetchers │ │ │ ├── local.js │ │ │ ├── remote.js │ │ │ ├── registry.js │ │ │ └── git.js │ │ ├── fetcher.js │ │ └── tree.js │ ├── saver.js │ ├── resolver.js │ └── installer.js ├── run │ ├── list.js │ └── runner.js ├── lock │ ├── locker.js │ ├── resolver │ │ ├── fetchers │ │ │ ├── local.js │ │ │ ├── remote.js │ │ │ ├── registry.js │ │ │ └── git.js │ │ ├── fetcher.js │ │ └── tree.js │ └── resolver.js ├── run.js ├── lock.js └── install.js ├── test ├── deps │ ├── install-save │ │ └── package.json │ ├── registry │ │ └── package.json │ ├── file │ │ ├── package.json │ │ └── happy-birthday-0.6.0 │ │ │ ├── messages.txt │ │ │ ├── index.js │ │ │ ├── package.json │ │ │ ├── README.md │ │ │ ├── happy-birthday.js │ │ │ ├── .gitignore │ │ │ └── LICENSE │ ├── install-deprecated │ │ └── package.json │ ├── registry-native │ │ └── package.json │ ├── registry-scope │ │ └── package.json │ ├── git │ │ └── package.json │ ├── url │ │ └── package.json │ ├── git-committish │ │ └── package.json │ ├── registry-resolver │ │ └── package.json │ ├── git-committish-semver │ │ └── package.json │ ├── install-only │ │ └── package.json │ └── run │ │ └── package.json ├── 90-version.js ├── 01-chmod.js ├── 00-clean.js ├── zz-cleanup.js ├── 30-run.js ├── 90-help.js ├── 11-install-deprecated.js ├── 20-lock.js ├── 10-install.js ├── 11-install-only.js └── 11-install-save.js ├── .github ├── workflows │ └── nodejs.yml ├── ISSUE_TEMPLATE.md └── CONTRIBUTING.md ├── scripts ├── install.js └── uninstall.js ├── bin └── dep.js ├── LICENSE ├── .gitignore ├── package.json ├── CODE_OF_CONDUCT.md ├── README.md └── CHANGELOG.md /.npmrc: -------------------------------------------------------------------------------- 1 | package-lock=false 2 | -------------------------------------------------------------------------------- /lib/utils/is-root.js: -------------------------------------------------------------------------------- 1 | module.exports = () => { 2 | return process.getuid && process.getuid() === 0 3 | } 4 | -------------------------------------------------------------------------------- /lib/utils/nm.js: -------------------------------------------------------------------------------- 1 | const path = require('path') 2 | 3 | module.exports = path.join(process.cwd(), 'node_modules') 4 | -------------------------------------------------------------------------------- /test/deps/install-save/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "name": "install-save", 4 | "version": "1.0.0" 5 | } 6 | -------------------------------------------------------------------------------- /lib/install/installer/local.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs-extra') 2 | 3 | module.exports = (pkg, cwd) => { 4 | return fs.copy(pkg.url, cwd) 5 | } 6 | -------------------------------------------------------------------------------- /test/deps/registry/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "name": "registry", 4 | "version": "1.0.0", 5 | "dependencies": { 6 | "happy-birthday": "0.6.0" 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /test/deps/file/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "name": "file", 4 | "version": "1.0.0", 5 | "dependencies": { 6 | "happy-birthday": "./happy-birthday-0.6.0" 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /test/deps/install-deprecated/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "name": "install-deprecated", 4 | "version": "1.0.0", 5 | "dependencies": { 6 | "minimatch": "0.0.1" 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /test/deps/registry-native/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "name": "install-native", 4 | "version": "1.0.0", 5 | "dependencies": { 6 | "native-hello-world": "^1.0.0" 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /test/deps/registry-scope/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "name": "install-scope", 4 | "version": "1.0.0", 5 | "dependencies": { 6 | "@watilde/hello-scoped-package": "^1.0.1" 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /test/deps/git/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "name": "git", 4 | "version": "1.0.0", 5 | "dependencies": { 6 | "happy-birthday": "git+https://github.com/watilde/happy-birthday.git" 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /test/deps/url/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "name": "url", 4 | "version": "1.0.0", 5 | "dependencies": { 6 | "happy-birthday": "https://github.com/watilde/happy-birthday/archive/0.6.0.tar.gz" 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /test/deps/file/happy-birthday-0.6.0/messages.txt: -------------------------------------------------------------------------------- 1 | Happy birthday, $1! 2 | Feliz aniversário, $1! 3 | Joyeux anniversaire, $1! 4 | Feliz cumpleaños, $1! 5 | お誕生日おめでとう、$1! 6 | Alles Gute zum Geburtstag, $1! 7 | Per molts anys, $1! 8 | 생일 축하해, $1! 9 | -------------------------------------------------------------------------------- /test/deps/git-committish/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "name": "git-committish", 4 | "version": "1.0.0", 5 | "dependencies": { 6 | "happy-birthday": "git+https://github.com/watilde/happy-birthday.git#70e05f" 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /test/deps/registry-resolver/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "name": "registry-resolver", 4 | "version": "1.0.0", 5 | "dependencies": { 6 | "agreed-client": "^2.0.0", 7 | "agreed-server": "^2.0.0" 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /test/deps/git-committish-semver/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "name": "git-committish-semver", 4 | "version": "1.0.0", 5 | "dependencies": { 6 | "happy-birthday": "git+https://github.com/watilde/happy-birthday.git#semver:^0.5.0" 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /test/deps/install-only/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "name": "install-only", 4 | "version": "1.0.0", 5 | "dependencies": { 6 | "happy-birthday": "0.6.0" 7 | }, 8 | "devDependencies": { 9 | "quack-array": "0.0.1" 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /lib/utils/node-gyp.js: -------------------------------------------------------------------------------- 1 | const execFileSync = require('child_process').execFileSync 2 | const path = require('path') 3 | const bin = path.join(__dirname, '../../node_modules/node-gyp/bin/node-gyp.js') 4 | 5 | module.exports = (opts) => { 6 | execFileSync(bin, ['--silent', 'rebuild'], opts) 7 | } 8 | -------------------------------------------------------------------------------- /lib/run/list.js: -------------------------------------------------------------------------------- 1 | module.exports = (pkg) => { 2 | const scripts = pkg.scripts 3 | process.stdout.write( 4 | 'Available scripts via `dep run`\n\n' + 5 | Object.keys(scripts).map((key) => { 6 | return 'dep run ' + key + ':\n ' + scripts[key] 7 | }).join('\n') + '\n' 8 | ) 9 | } 10 | -------------------------------------------------------------------------------- /lib/lock/locker.js: -------------------------------------------------------------------------------- 1 | const writeFileSync = require('fs').writeFileSync 2 | const path = require('path') 3 | const pkgLockJSON = path.join(process.cwd(), 'package-lock.json') 4 | 5 | const locker = (pkg) => { 6 | writeFileSync(pkgLockJSON, JSON.stringify(pkg, 2, 2)) 7 | } 8 | 9 | module.exports = locker 10 | -------------------------------------------------------------------------------- /test/deps/run/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "name": "registry", 4 | "version": "1.0.0", 5 | "scripts": { 6 | "pretest": "happy-birthday --you=pretest", 7 | "test": "happy-birthday --you=test", 8 | "posttest": "happy-birthday --you=posttest" 9 | }, 10 | "dependencies": { 11 | "happy-birthday": "0.6.0" 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /test/90-version.js: -------------------------------------------------------------------------------- 1 | const path = require('path') 2 | const exec = require('child_process').exec 3 | const test = require('tap').test 4 | const bin = path.join(__dirname, '..', 'bin', 'dep.js') 5 | 6 | test((t) => { 7 | exec(`node ${bin} -v`, (err, stdout, stderr) => { 8 | t.ifError(err, 'version ran without error') 9 | t.ok(stdout, 'version displayed a message') 10 | t.end() 11 | }) 12 | }) 13 | -------------------------------------------------------------------------------- /test/deps/file/happy-birthday-0.6.0/index.js: -------------------------------------------------------------------------------- 1 | var fs = require('fs') 2 | var path = require('path') 3 | var messages = fs.readFileSync(path.join(__dirname, 'messages.txt'), 'utf8').split('\n') 4 | 5 | module.exports = function (name) { 6 | var num = Math.floor(Math.random() * (messages.length - 1)) 7 | var message = messages[num] 8 | message = message.replace('$1', name) 9 | return message 10 | } 11 | -------------------------------------------------------------------------------- /test/01-chmod.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs') 2 | const path = require('path') 3 | const test = require('tap').test 4 | const isRoot = require('../lib/utils/is-root') 5 | 6 | test((t) => { 7 | if (!isRoot()) return t.end() 8 | fs.chmodSync(path.join(__dirname, '../.nyc_output'), '0777') 9 | const files = fs.readdirSync(path.join(__dirname, '../.nyc_output')) 10 | files.forEach((file) => { 11 | fs.chmodSync(path.join(__dirname, `../.nyc_output/${file}`), '0777') 12 | }) 13 | t.end() 14 | }) 15 | -------------------------------------------------------------------------------- /test/deps/file/happy-birthday-0.6.0/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "happy-birthday", 3 | "version": "0.6.0", 4 | "description": "Happy birthday to you!", 5 | "main": "index.js", 6 | "bin": { 7 | "happy-birthday": "./happy-birthday.js" 8 | }, 9 | "dependencies": { 10 | "commander": "^2.9.0" 11 | }, 12 | "devDependencies": {}, 13 | "scripts": { 14 | "test": "echo \"Error: no test specified\" && exit 1" 15 | }, 16 | "author": "Daijiro Wachi", 17 | "license": "MIT" 18 | } 19 | -------------------------------------------------------------------------------- /test/deps/file/happy-birthday-0.6.0/README.md: -------------------------------------------------------------------------------- 1 | # happy-birthday 2 | to you! 3 | 4 | ## Usage 5 | ``` 6 | Usage: happy-birthday -u name 7 | 8 | Options: 9 | 10 | -h, --help output usage information 11 | -V, --version output the version number 12 | -u, --you [name] Name 13 | ``` 14 | 15 | ## Install 16 | ``` 17 | $ npm install -g happy-birthday 18 | $ happy-birthday --version 19 | 0.3.0 20 | ``` 21 | 22 | ## Patch welcome 23 | Add your message ;) 24 | https://github.com/watilde/happy-birthday/blob/master/messages.txt 25 | -------------------------------------------------------------------------------- /lib/install/resolver/fetchers/local.js: -------------------------------------------------------------------------------- 1 | const path = require('path') 2 | 3 | module.exports = (name, spec, result) => { 4 | const pkgJSON = spec.indexOf('package.json') !== -1 5 | ? spec 6 | : path.join(spec, 'package.json') 7 | return new Promise((resolve, reject) => { 8 | try { 9 | const pkg = require(pkgJSON) 10 | resolve({ 11 | type: 'local', 12 | version: pkg.version, 13 | dependencies: pkg.dependencies, 14 | url: spec 15 | }) 16 | } catch (e) { reject(e) } 17 | }) 18 | } 19 | -------------------------------------------------------------------------------- /lib/lock/resolver/fetchers/local.js: -------------------------------------------------------------------------------- 1 | const path = require('path') 2 | 3 | module.exports = (name, spec, result) => { 4 | const pkgJSON = spec.indexOf('package.json') !== -1 5 | ? spec 6 | : path.join(spec, 'package.json') 7 | return new Promise((resolve, reject) => { 8 | try { 9 | const pkg = require(pkgJSON) 10 | resolve({ 11 | type: 'local', 12 | version: pkg.version, 13 | dependencies: pkg.dependencies, 14 | url: spec 15 | }) 16 | } catch (e) { reject(e) } 17 | }) 18 | } 19 | -------------------------------------------------------------------------------- /.github/workflows/nodejs.yml: -------------------------------------------------------------------------------- 1 | name: Node.js CI 2 | 3 | on: [push, pull_request] 4 | 5 | jobs: 6 | build: 7 | strategy: 8 | matrix: 9 | node-version: [10.x, 12.x, 14.x] 10 | os: [ubuntu-latest, windows-latest, macOS-latest] 11 | runs-on: ${{ matrix.os }} 12 | 13 | steps: 14 | - uses: actions/checkout@v2 15 | - name: Use Node.js ${{ matrix.node-version }} 16 | uses: actions/setup-node@v1 17 | with: 18 | node-version: ${{ matrix.node-version }} 19 | - run: npm install 20 | - run: npm test -------------------------------------------------------------------------------- /test/00-clean.js: -------------------------------------------------------------------------------- 1 | const path = require('path') 2 | const test = require('tap').test 3 | const fs = require('fs-extra') 4 | const fixtures = fs.readdirSync(path.join(__dirname, 'deps')) 5 | 6 | test((t) => { 7 | var count = fixtures.length 8 | fixtures.forEach(fixture => { 9 | const modules = path.join(__dirname, 'deps', fixture, 'node_modules') 10 | const lock = path.join(__dirname, 'deps', fixture, 'node_modules.json') 11 | fs.removeSync(modules) 12 | fs.removeSync(lock) 13 | count -= 1 14 | if (count === 0) t.end() 15 | }) 16 | }) 17 | -------------------------------------------------------------------------------- /test/deps/file/happy-birthday-0.6.0/happy-birthday.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | var program = require('commander') 3 | var hb = require('./') 4 | var pkg = require('./package.json') 5 | var message = '' 6 | var you = '' 7 | 8 | program 9 | .version(pkg.version) 10 | .usage('-u name') 11 | .option('-u, --you [name]', 'Name') 12 | .parse(process.argv) 13 | 14 | if (!program.you) { 15 | program.help() 16 | } else { 17 | you = program.you 18 | message = hb(you) 19 | 20 | console.log('\n🎂') 21 | console.log(message) 22 | console.log('🎉') 23 | } 24 | -------------------------------------------------------------------------------- /test/zz-cleanup.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs-extra') 2 | const path = require('path') 3 | const test = require('tap').test 4 | const fixtures = fs.readdirSync(path.join(__dirname, 'deps')) 5 | 6 | test((t) => { 7 | var count = fixtures.length 8 | fixtures.forEach(fixture => { 9 | const modules = path.join(__dirname, 'deps', fixture, 'node_modules') 10 | const lock = path.join(__dirname, 'deps', fixture, 'node_modules.json') 11 | fs.removeSync(modules) 12 | fs.removeSync(lock) 13 | count -= 1 14 | if (count === 0) t.end() 15 | }) 16 | }) 17 | -------------------------------------------------------------------------------- /lib/run.js: -------------------------------------------------------------------------------- 1 | const path = require('path') 2 | const list = require('./run/list') 3 | const runner = require('./run/runner') 4 | 5 | const run = (argv) => { 6 | argv._handled = true 7 | const pkgJSON = require(path.join(process.cwd(), 'package.json')) 8 | if (!pkgJSON.scripts) return 9 | if (argv._.length === 1) { 10 | list(pkgJSON) 11 | } else { 12 | runner(argv._, pkgJSON) 13 | } 14 | } 15 | 16 | module.exports = { 17 | command: 'run', 18 | describe: 'Run an arbitrary command from scripts in package.json', 19 | handler: run, 20 | aliases: ['r'] 21 | } 22 | -------------------------------------------------------------------------------- /test/30-run.js: -------------------------------------------------------------------------------- 1 | const path = require('path') 2 | const exec = require('child_process').exec 3 | const test = require('tap').test 4 | const pkg = path.join(__dirname, 'deps', 'run') 5 | const bin = path.join(__dirname, '..', 'bin', 'dep.js') 6 | 7 | test((t) => { 8 | exec(`node ${bin} run`, { cwd: pkg }, (err, stdout, stderr) => { 9 | t.ifError(err, 'run without error') 10 | t.end() 11 | }) 12 | }) 13 | 14 | test((t) => { 15 | exec(`node ${bin} run test`, { cwd: pkg }, (err, stdout, stderr) => { 16 | t.ifError(err, 'run test without error') 17 | t.end() 18 | }) 19 | }) 20 | -------------------------------------------------------------------------------- /lib/install/installer/git.js: -------------------------------------------------------------------------------- 1 | const path = require('path') 2 | const fs = require('fs-extra') 3 | const git = require('../../utils/git') 4 | 5 | module.exports = (pkg, cwd) => { 6 | const url = pkg.url.split('#')[0] 7 | const hash = pkg.url.split('#')[1] 8 | 9 | git.sync(['clone', url, cwd, '--quiet']) 10 | if (!fs.pathExistsSync(path.join(cwd, '.gitmodules'))) { 11 | return git(['checkout', hash, '--quiet'], { cwd: cwd }) 12 | } 13 | git.sync(['checkout', hash, '--quiet'], { cwd: cwd }) 14 | return git(['submodule', 'update', '--init', '--recursive', '--quiet'], { cwd: cwd }) 15 | } 16 | -------------------------------------------------------------------------------- /test/90-help.js: -------------------------------------------------------------------------------- 1 | const path = require('path') 2 | const exec = require('child_process').exec 3 | const test = require('tap').test 4 | const bin = path.join(__dirname, '..', 'bin', 'dep.js') 5 | 6 | test((t) => { 7 | exec(`node ${bin} -h`, (err, stdout, stderr) => { 8 | t.ifError(err, 'help ran without error') 9 | t.ok(stdout, 'help displayed a message') 10 | t.end() 11 | }) 12 | }) 13 | 14 | test((t) => { 15 | exec(`node ${bin}`, (err, stdout, stderr) => { 16 | t.ifError(err, 'help ran without error') 17 | t.ok(stderr, 'help displayed a message') 18 | t.end() 19 | }) 20 | }) 21 | -------------------------------------------------------------------------------- /lib/install/installer/remote.js: -------------------------------------------------------------------------------- 1 | const request = require('request') 2 | const tar = require('tar-fs') 3 | const gunzip = require('gunzip-maybe') 4 | const npmrc = require('../../utils/npmrc') 5 | 6 | module.exports = (pkg, cwd) => { 7 | const options = { 8 | url: pkg.url, 9 | headers: { 10 | 'User-Agent': npmrc.userAgent 11 | } 12 | } 13 | return new Promise((resolve, reject) => { 14 | const extract = tar.extract(cwd, { strip: 1 }) 15 | extract.on('finish', () => { 16 | resolve() 17 | }) 18 | request.get(options) 19 | .pipe(gunzip()) 20 | .pipe(extract) 21 | .on('error', reject) 22 | }) 23 | } 24 | -------------------------------------------------------------------------------- /lib/install/installer/registry.js: -------------------------------------------------------------------------------- 1 | const request = require('request') 2 | const tar = require('tar-fs') 3 | const gunzip = require('gunzip-maybe') 4 | const npmrc = require('../../utils/npmrc') 5 | 6 | module.exports = (pkg, cwd) => { 7 | const options = { 8 | url: pkg.tarball, 9 | headers: { 10 | 'User-Agent': npmrc.userAgent 11 | } 12 | } 13 | return new Promise((resolve, reject) => { 14 | const extract = tar.extract(cwd, { strip: 1 }) 15 | extract.on('finish', () => { 16 | resolve() 17 | }) 18 | request.get(options) 19 | .pipe(gunzip()) 20 | .pipe(extract) 21 | .on('error', reject) 22 | }) 23 | } 24 | -------------------------------------------------------------------------------- /lib/utils/drop-privilege.js: -------------------------------------------------------------------------------- 1 | const isRoot = require('./is-root') 2 | const isEnable = process.getuid && process.setuid 3 | 4 | module.exports = () => { 5 | if (!isRoot()) return 6 | if (!isEnable) return 7 | var group = process.platform === 'win32' ? 0 8 | : process.env.SUDO_GID || 'nobody' 9 | if (!isNaN(group)) group = +group 10 | try { 11 | process.setgid(group) 12 | } catch (e) { 13 | throw new Error(e) 14 | } 15 | var user = process.platform === 'win32' ? 0 16 | : process.env.SUDO_UID || 'nobody' 17 | if (!isNaN(user)) user = +user 18 | try { 19 | process.setuid(user) 20 | } catch (e) { 21 | throw new Error(e) 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /test/deps/file/happy-birthday-0.6.0/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | 6 | # Runtime data 7 | pids 8 | *.pid 9 | *.seed 10 | 11 | # Directory for instrumented libs generated by jscoverage/JSCover 12 | lib-cov 13 | 14 | # Coverage directory used by tools like istanbul 15 | coverage 16 | 17 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 18 | .grunt 19 | 20 | # node-waf configuration 21 | .lock-wscript 22 | 23 | # Compiled binary addons (http://nodejs.org/api/addons.html) 24 | build/Release 25 | 26 | # Dependency directory 27 | node_modules 28 | 29 | # Optional npm cache directory 30 | .npm 31 | 32 | # Optional REPL history 33 | .node_repl_history 34 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | 18 | ### Summary 19 | Write here. 20 | 21 | ### Steps to reproduce behavior 22 | Write here. 23 | 24 | ### Expected behavior 25 | Write here. 26 | 27 | ### Actual behavior 28 | Write here. 29 | -------------------------------------------------------------------------------- /lib/utils/npmrc.js: -------------------------------------------------------------------------------- 1 | const path = require('path') 2 | const fs = require('fs') 3 | const version = require(path.join(__dirname, '../../package.json')).version 4 | const defaultrc = { 5 | userAgent: `dep/${version} node/${process.version}`, 6 | registry: 'https://registry.yarnpkg.com/', 7 | 'save-prefix': '^' 8 | } 9 | 10 | var npmrc = {} 11 | const npmrcPath = path.join(process.env.HOME, '.npmrc') 12 | const npmrcFile = fs.existsSync(npmrcPath) 13 | ? fs.readFileSync(npmrcPath, 'utf8') 14 | : '' 15 | 16 | npmrcFile.split('\n') 17 | .forEach((line) => { 18 | const list = line.split('=') 19 | npmrc[list[0]] = list[1] || true 20 | }) 21 | 22 | // for safer 23 | delete npmrc.AuthSession 24 | 25 | module.exports = Object.assign(defaultrc, npmrc) 26 | -------------------------------------------------------------------------------- /scripts/install.js: -------------------------------------------------------------------------------- 1 | const exec = require('child_process').exec 2 | const path = require('path') 3 | const fs = require('fs') 4 | const execPath = process.execPath 5 | const binPath = path.dirname(execPath) 6 | const dep = path.join(execPath, '../../lib/node_modules/dep') 7 | const repository = 'https://github.com/depjs/dep.git' 8 | const bin = path.join(dep, 'bin/dep.js') 9 | 10 | process.stdout.write( 11 | 'exec: git' + [' clone', repository, dep].join(' ') + '\n' 12 | ) 13 | exec('git clone ' + repository + ' ' + dep, (e) => { 14 | if (e) throw e 15 | process.stdout.write('link: ' + bin + '\n') 16 | process.stdout.write(' => ' + path.join(binPath, 'dep') + '\n') 17 | fs.symlink(bin, path.join(binPath, 'dep'), (e) => { 18 | if (e) throw e 19 | }) 20 | }) 21 | -------------------------------------------------------------------------------- /test/11-install-deprecated.js: -------------------------------------------------------------------------------- 1 | const path = require('path') 2 | const exec = require('child_process').exec 3 | const tree = require('strong-npm-ls') 4 | const test = require('tap').test 5 | const bin = path.join(__dirname, '..', 'bin', 'dep.js') 6 | const pkg = path.join(__dirname, 'deps/install-deprecated') 7 | const pkgJSON = require(path.join(pkg, 'package.json')) 8 | 9 | test((t) => { 10 | exec(`node ${bin} install`, { cwd: pkg }, (err, stdout, stderr) => { 11 | t.ifError(err, `${pkgJSON.name}: install ran without error`) 12 | t.has(stdout, 'minimatch@0.0.1') 13 | tree.read(pkg, (err, out) => { 14 | t.ifError(err, `${pkgJSON.name}: tree could be read`) 15 | const deps = out.dependencies 16 | t.ok(deps.minimatch, `${pkgJSON.name}: deps are installed`) 17 | t.end() 18 | }) 19 | }) 20 | }) 21 | -------------------------------------------------------------------------------- /scripts/uninstall.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs') 2 | const path = require('path') 3 | const execPath = process.execPath 4 | const binPath = path.dirname(execPath) 5 | const pkg = path.join(execPath, '../../lib/node_modules/dep') 6 | const bin = path.join(binPath, 'dep') 7 | 8 | const rmdir = p => { 9 | if (fs.existsSync(p)) { 10 | fs.readdirSync(p).forEach((file, index) => { 11 | const current = path.join(p, file) 12 | if (fs.lstatSync(current).isDirectory()) { 13 | rmdir(current) 14 | } else { 15 | fs.unlinkSync(current) 16 | } 17 | }) 18 | fs.rmdirSync(p) 19 | } 20 | } 21 | 22 | process.stdout.write('remove: ' + pkg + '\n') 23 | rmdir(pkg) 24 | 25 | process.stdout.write('remove: ' + bin + '\n') 26 | fs.unlink(bin, e => { 27 | if (e) throw e 28 | process.stdout.write('dep was uninstalled successfully\n') 29 | }) 30 | -------------------------------------------------------------------------------- /lib/utils/git.js: -------------------------------------------------------------------------------- 1 | const which = require('which') 2 | const execFile = require('child_process').execFile 3 | const execFileSync = require('child_process').execFileSync 4 | const prefix = process.platform === 'win32' ? ['-c', 'core.longpaths=true'] : [] 5 | 6 | module.exports = (cmds, opt) => { 7 | opt = Object.assign({ encoding: 'utf8' }, opt) 8 | return new Promise((resolve, reject) => { 9 | which('git', (e, git) => { 10 | if (e) return reject(e) 11 | const args = prefix.concat(cmds) 12 | execFile(git, args, opt, (e, stdout) => { 13 | if (e) return reject(e) 14 | resolve(stdout) 15 | }) 16 | }) 17 | }) 18 | } 19 | 20 | module.exports.sync = (cmds, opt) => { 21 | opt = Object.assign({ encoding: 'utf8' }, opt) 22 | const git = which.sync('git') 23 | const args = prefix.concat(cmds) 24 | return execFileSync(git, args, opt) 25 | } 26 | -------------------------------------------------------------------------------- /lib/lock/resolver/fetcher.js: -------------------------------------------------------------------------------- 1 | const npa = require('npm-package-arg') 2 | const git = require('./fetchers/git') 3 | const local = require('./fetchers/local') 4 | const remote = require('./fetchers/remote') 5 | const registry = require('./fetchers/registry') 6 | 7 | module.exports = (name, spec) => { 8 | const pkg = spec ? `${name}@${spec}` : name 9 | const result = npa(pkg, process.cwd()) 10 | 11 | switch (result.type) { 12 | // type git 13 | case 'git': 14 | return git(name, result.fetchSpec, result) 15 | // type remote 16 | case 'remote': 17 | return remote(name, result.fetchSpec, result) 18 | // type local 19 | case 'file': 20 | case 'directory': 21 | return local(name, result.fetchSpec, result) 22 | // type registry 23 | case 'tag': 24 | case 'range': 25 | case 'version': 26 | default: 27 | return registry(name, result.fetchSpec, result) 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /lib/install/resolver/fetcher.js: -------------------------------------------------------------------------------- 1 | const npa = require('npm-package-arg') 2 | const git = require('./fetchers/git') 3 | const local = require('./fetchers/local') 4 | const remote = require('./fetchers/remote') 5 | const registry = require('./fetchers/registry') 6 | 7 | module.exports = (name, spec) => { 8 | const pkg = spec ? `${name}@${spec}` : name 9 | const result = npa(pkg, process.cwd()) 10 | 11 | switch (result.type) { 12 | // type git 13 | case 'git': 14 | return git(name, result.fetchSpec, result) 15 | // type remote 16 | case 'remote': 17 | return remote(name, result.fetchSpec, result) 18 | // type local 19 | case 'file': 20 | case 'directory': 21 | return local(name, result.fetchSpec, result) 22 | // type registry 23 | case 'tag': 24 | case 'range': 25 | case 'version': 26 | default: 27 | return registry(name, result.fetchSpec, result) 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /test/20-lock.js: -------------------------------------------------------------------------------- 1 | // const fs = require('fs') 2 | // const path = require('path') 3 | // const exec = require('child_process').exec 4 | const test = require('tap').test 5 | // const fixtures = fs.readdirSync(path.join(__dirname, 'deps')) 6 | // const bin = path.join(__dirname, '..', 'bin', 'dep.js') 7 | 8 | test((t) => { 9 | // lock is not implemented yet 10 | t.end() 11 | /* 12 | var items = 2 13 | var count = fixtures.length * items 14 | t.plan(count) 15 | fixtures.forEach(fixture => { 16 | const pkg = path.join(__dirname, 'deps', fixture) 17 | const pkgJSON = require(path.join(pkg, 'package.json')) 18 | exec(`node ${bin} lock`, {cwd: pkg}, (err, stdout, stderr) => { 19 | t.ifError(err, `${pkgJSON.name}: lock ran without error`) 20 | const lock = require(path.join(pkg, 'node_modules.json')) 21 | const deps = lock.dependencies 22 | t.ok(Object.keys(deps).length, `${pkgJSON.name}: deps are locked`) 23 | if (count === 0) t.end() 24 | }) 25 | }) 26 | */ 27 | }) 28 | -------------------------------------------------------------------------------- /lib/install/saver.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs') 2 | const path = require('path') 3 | const npmrc = require('../utils/npmrc') 4 | 5 | module.exports = (pkgs, save) => { 6 | const pkgJSON = require(path.join(process.cwd(), 'package.json')) 7 | var saveDeps = {} 8 | pkgs.forEach((pkg) => { 9 | const key = pkg.split('@')[0] 10 | var value = pkg.split('@')[1] 11 | const dep = global.dependenciesTree[pkg] 12 | if (!value) { 13 | switch (dep.type) { 14 | case 'registry': 15 | value = npmrc['save-prefix'] + dep.version 16 | break 17 | default: 18 | value = dep.url 19 | break 20 | } 21 | } 22 | saveDeps[key] = value 23 | }) 24 | const field = save === 'dev' ? 'devDependencies' : 'dependencies' 25 | const oldDeps = pkgJSON[field] || {} 26 | const newDeps = Object.assign({}, oldDeps, saveDeps) 27 | pkgJSON[field] = newDeps 28 | fs.writeFileSync( 29 | path.join(process.cwd(), 'package.json'), 30 | JSON.stringify(pkgJSON, 2, 2) 31 | ) 32 | } 33 | -------------------------------------------------------------------------------- /lib/install/installer/bin.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs-extra') 2 | const path = require('path') 3 | const nm = require('../../utils/nm') 4 | 5 | const bin = (key, target) => { 6 | const pkgJSON = require(path.join(target, 'package.json')) 7 | if (!pkgJSON.bin) return 8 | fs.ensureDirSync(path.join(nm, '.bin')) 9 | if (typeof pkgJSON.bin === 'string') { 10 | try { 11 | fs.unlinkSync(path.join(nm, '.bin', key)) 12 | } catch (e) {} 13 | fs.symlinkSync( 14 | path.join(target, pkgJSON.bin), 15 | path.join(nm, '.bin', key) 16 | ) 17 | fs.chmodSync(path.join(target, pkgJSON.bin), '0755') 18 | } else if (typeof pkgJSON.bin === 'object') { 19 | Object.keys(pkgJSON.bin).forEach((cmd) => { 20 | try { 21 | fs.unlinkSync(path.join(nm, '.bin', cmd)) 22 | } catch (e) {} 23 | fs.symlinkSync( 24 | path.join(target, pkgJSON.bin[cmd]), 25 | path.join(nm, '.bin', cmd) 26 | ) 27 | fs.chmodSync(path.join(target, pkgJSON.bin[cmd]), '0755') 28 | }) 29 | } 30 | } 31 | 32 | module.exports = bin 33 | -------------------------------------------------------------------------------- /lib/lock.js: -------------------------------------------------------------------------------- 1 | const path = require('path') 2 | const resolver = require('./lock/resolver') 3 | const locker = require('./lock/locker') 4 | 5 | global.dependenciesTree = {} 6 | 7 | const lock = (argv) => { 8 | argv._handled = true 9 | const pkgJSON = require(path.join(process.cwd(), 'package.json')) 10 | const lock = { 11 | name: pkgJSON.name, 12 | version: pkgJSON.version, 13 | lockfileVersion: 1 14 | } 15 | var deps = Object.assign( 16 | {}, 17 | pkgJSON.optionalDependencies || {}, 18 | pkgJSON.devDependencies || {}, 19 | pkgJSON.dependencies || {} 20 | ) 21 | 22 | const list = resolver(deps) 23 | process.stdout.write('Resolving dependencies\n') 24 | Promise.all(list).then(() => { 25 | lock.dependencies = global.dependenciesTree 26 | locker(lock) 27 | process.stdout.write( 28 | 'created package-lock.json\n' 29 | ) 30 | }).catch((e) => { process.stderr.write(e.stack) }) 31 | } 32 | 33 | module.exports = { 34 | command: 'lock', 35 | describe: 'Lock dependencies installed in node_modules', 36 | handler: lock, 37 | aliases: ['l'] 38 | } 39 | -------------------------------------------------------------------------------- /bin/dep.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | const semver = require('semver') 4 | const yargs = require('yargs') 5 | const updateNotifier = require('update-notifier') 6 | const commands = { 7 | install: require('../lib/install'), 8 | lock: require('../lib/lock'), 9 | run: require('../lib/run') 10 | } 11 | const pkgJSON = require('../package.json') 12 | const notifier = updateNotifier({ pkg: pkgJSON }) 13 | 14 | if (!semver.satisfies(process.version, pkgJSON.engine.node)) { 15 | process.stderr.write('dep works only on Node.js LTS versions\n') 16 | process.stderr.write('See the schedule: https://github.com/nodejs/LTS#lts-schedule1\n') 17 | process.exit(1) 18 | } 19 | 20 | if (notifier.update) { 21 | notifier.notify() 22 | } 23 | 24 | yargs.usage(pkgJSON.description) 25 | 26 | yargs.help('help') 27 | .alias('help', 'h') 28 | 29 | yargs.version() 30 | .alias('version', 'v') 31 | .describe('version', 'Show version information') 32 | 33 | Object.keys(commands).forEach((i) => { 34 | yargs.command(commands[i]) 35 | }) 36 | 37 | const argv = yargs.argv 38 | 39 | if (!argv._handled) yargs.showHelp() 40 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Daijiro Wachi 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /lib/run/runner.js: -------------------------------------------------------------------------------- 1 | const spawn = require('child_process').spawn 2 | const npmPath = require('npm-path') 3 | const each = require('promise-each') 4 | 5 | module.exports = (_, pkg, cwd) => { 6 | cwd = cwd || process.cwd() 7 | const args = _.slice(1) 8 | const scripts = pkg.scripts 9 | const key = args.shift() 10 | var cmds = Object.keys(scripts).filter((script) => { 11 | return script === 'pre' + key || 12 | script === key || 13 | script === 'post' + key 14 | }).map((script) => { 15 | return scripts[script] 16 | }) 17 | var env = process.env 18 | var newPath = npmPath.getSync({}) 19 | env[npmPath.PATH] = newPath 20 | return Promise.resolve(cmds).then(each((cmd) => { 21 | return new Promise((resolve, reject) => { 22 | const script = spawn(cmd, args, { cwd: cwd, shell: true, env: env }) 23 | script.stdout.on('data', (data) => { 24 | process.stdout.write(data) 25 | }) 26 | script.stderr.on('data', (data) => { 27 | reject(data) 28 | }) 29 | script.on('close', (data) => { 30 | resolve() 31 | }) 32 | }) 33 | })).catch((e) => { 34 | throw new Error(e) 35 | }) 36 | } 37 | -------------------------------------------------------------------------------- /test/10-install.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs') 2 | const path = require('path') 3 | const exec = require('child_process').exec 4 | const tree = require('strong-npm-ls') 5 | const test = require('tap').test 6 | const skip = [ 7 | 'install-only', 8 | 'install-save' 9 | ] 10 | const bin = path.join(__dirname, '..', 'bin', 'dep.js') 11 | const fixtures = fs.readdirSync(path.join(__dirname, 'deps')) 12 | .filter((name) => { 13 | return skip.indexOf(name) === -1 14 | }) 15 | 16 | test((t) => { 17 | var items = 3 18 | var count = fixtures.length * items 19 | t.plan(count) 20 | fixtures.forEach(fixture => { 21 | const pkg = path.join(__dirname, 'deps', fixture) 22 | const pkgJSON = require(path.join(pkg, 'package.json')) 23 | exec(`node ${bin} install`, { cwd: pkg }, (err, stdout, stderr) => { 24 | t.ifError(err, `${pkgJSON.name}: install ran without error`) 25 | tree.read(pkg, (err, out) => { 26 | t.ifError(err, `${pkgJSON.name}: tree could be read`) 27 | const deps = out.dependencies 28 | t.ok(Object.keys(deps).length, `${pkgJSON.name}: deps are installed`) 29 | if (count === 0) t.end() 30 | }) 31 | }) 32 | }) 33 | }) 34 | -------------------------------------------------------------------------------- /test/deps/file/happy-birthday-0.6.0/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Daijiro Wachi 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /lib/lock/resolver/tree.js: -------------------------------------------------------------------------------- 1 | const getter = (list, keys) => { 2 | var ref = list 3 | while (keys.length) { 4 | var key = keys.shift() 5 | if (key in ref) { 6 | ref = ref[key] 7 | } else { 8 | return 9 | } 10 | } 11 | return ref 12 | } 13 | 14 | const setter = (list, key, value, walk) => { 15 | var i = 0 16 | var depth = 1 17 | var ref = list 18 | // optimize the shallowness as much as possible 19 | while (i < walk.length) { 20 | const words = walk[i].split('@') 21 | var name = words.length === 3 22 | ? '@' + walk[i].split('@')[0] + walk[i].split('@')[1] 23 | : walk[i].split('@')[0] 24 | var version = words.length === 3 25 | ? walk[i].split('@')[2] 26 | : walk[i].split('@')[1] 27 | var isDeps = name === 'dependencies' 28 | if (isDeps || (ref[name] && ref[name].version === version)) { 29 | if (isDeps && !ref[name]) ref[name] = {} 30 | ref = ref[name] 31 | i++ 32 | } else { 33 | ref = list 34 | i = 2 * depth 35 | depth++ 36 | } 37 | } 38 | 39 | if (!ref.dependencies) ref.dependencies = {} 40 | ref.dependencies[key] = value 41 | } 42 | 43 | module.exports = { 44 | getter, 45 | setter 46 | } 47 | -------------------------------------------------------------------------------- /lib/install/resolver/tree.js: -------------------------------------------------------------------------------- 1 | const getter = (list, keys) => { 2 | var ref = list 3 | while (keys.length) { 4 | var key = keys.shift() 5 | if (key in ref) { 6 | ref = ref[key] 7 | } else { 8 | return 9 | } 10 | } 11 | return ref 12 | } 13 | 14 | const setter = (list, key, value, walk) => { 15 | var i = 0 16 | var depth = 1 17 | var ref = list 18 | // optimize the shallowness as much as possible 19 | while (i < walk.length) { 20 | const words = walk[i].split('@') 21 | var name = words.length === 3 22 | ? '@' + walk[i].split('@')[0] + walk[i].split('@')[1] 23 | : walk[i].split('@')[0] 24 | var version = words.length === 3 25 | ? walk[i].split('@')[2] 26 | : walk[i].split('@')[1] 27 | var isDeps = name === 'dependencies' 28 | if (isDeps || (ref[name] && ref[name].version === version)) { 29 | if (isDeps && !ref[name]) ref[name] = {} 30 | ref = ref[name] 31 | i++ 32 | } else { 33 | ref = list 34 | i = 2 * depth 35 | depth++ 36 | } 37 | } 38 | 39 | if (!ref.dependencies) ref.dependencies = {} 40 | ref.dependencies[key] = value 41 | } 42 | 43 | module.exports = { 44 | getter, 45 | setter 46 | } 47 | -------------------------------------------------------------------------------- /test/11-install-only.js: -------------------------------------------------------------------------------- 1 | const path = require('path') 2 | const exec = require('child_process').exec 3 | const tree = require('strong-npm-ls') 4 | const test = require('tap').test 5 | const bin = path.join(__dirname, '..', 'bin', 'dep.js') 6 | const pkg = path.join(__dirname, 'deps/install-only') 7 | const pkgJSON = require(path.join(pkg, 'package.json')) 8 | 9 | test((t) => { 10 | exec(`node ${bin} install --only=prod`, { cwd: pkg }, (err, stdout, stderr) => { 11 | t.ifError(err, `${pkgJSON.name}: install ran without error`) 12 | tree.read(pkg, (err, out) => { 13 | t.ifError(err, `${pkgJSON.name}: tree could be read`) 14 | const deps = out.dependencies 15 | t.ok(deps['happy-birthday'], `${pkgJSON.name}: deps are installed`) 16 | t.end() 17 | }) 18 | }) 19 | }) 20 | 21 | test((t) => { 22 | exec(`node ${bin} install --only=dev`, { cwd: pkg }, (err, stdout, stderr) => { 23 | t.ifError(err, `${pkgJSON.name}: install ran without error`) 24 | tree.read(pkg, (err, out) => { 25 | t.ifError(err, `${pkgJSON.name}: tree could be read`) 26 | const deps = out.devDependencies 27 | t.ok(deps['quack-array'], `${pkgJSON.name}: deps are installed`) 28 | t.end() 29 | }) 30 | }) 31 | }) 32 | -------------------------------------------------------------------------------- /lib/lock/resolver/fetchers/remote.js: -------------------------------------------------------------------------------- 1 | const request = require('request') 2 | const tar = require('tar-stream') 3 | const gunzip = require('gunzip-maybe') 4 | const npmrc = require('../../../utils/npmrc') 5 | 6 | module.exports = (name, spec, result) => { 7 | const options = { 8 | url: spec, 9 | headers: { 10 | 'User-Agent': npmrc.userAgent 11 | } 12 | } 13 | return new Promise((resolve, reject) => { 14 | const extract = tar.extract() 15 | var data = '' 16 | extract.on('entry', (header, stream, cb) => { 17 | const file = header.name.split('/').pop() 18 | stream.on('data', (chunk) => { 19 | if (file === 'package.json') data += chunk 20 | }) 21 | stream.on('end', () => { 22 | if (data) { 23 | try { 24 | const pkgJSON = JSON.parse(data) 25 | resolve({ 26 | type: 'remote', 27 | version: pkgJSON.version, 28 | dependencies: pkgJSON.dependencies, 29 | url: spec 30 | }) 31 | } catch (e) { reject(e) } 32 | } else { 33 | cb() 34 | } 35 | }) 36 | stream.resume() 37 | }) 38 | request.get(options) 39 | .pipe(gunzip()) 40 | .pipe(extract) 41 | .on('error', reject) 42 | }) 43 | } 44 | -------------------------------------------------------------------------------- /lib/install/resolver/fetchers/remote.js: -------------------------------------------------------------------------------- 1 | const request = require('request') 2 | const tar = require('tar-stream') 3 | const gunzip = require('gunzip-maybe') 4 | const npmrc = require('../../../utils/npmrc') 5 | 6 | module.exports = (name, spec, result) => { 7 | const options = { 8 | url: spec, 9 | headers: { 10 | 'User-Agent': npmrc.userAgent 11 | } 12 | } 13 | return new Promise((resolve, reject) => { 14 | const extract = tar.extract() 15 | var data = '' 16 | extract.on('entry', (header, stream, cb) => { 17 | const file = header.name.split('/').pop() 18 | stream.on('data', (chunk) => { 19 | if (file === 'package.json') data += chunk 20 | }) 21 | stream.on('end', () => { 22 | if (data) { 23 | try { 24 | const pkgJSON = JSON.parse(data) 25 | resolve({ 26 | type: 'remote', 27 | version: pkgJSON.version, 28 | dependencies: pkgJSON.dependencies, 29 | url: spec 30 | }) 31 | } catch (e) { reject(e) } 32 | } else { 33 | cb() 34 | } 35 | }) 36 | stream.resume() 37 | }) 38 | request.get(options) 39 | .pipe(gunzip()) 40 | .pipe(extract) 41 | .on('error', reject) 42 | }) 43 | } 44 | -------------------------------------------------------------------------------- /lib/install/resolver/fetchers/registry.js: -------------------------------------------------------------------------------- 1 | const request = require('request') 2 | const semver = require('semver') 3 | const npmrc = require('../../../utils/npmrc') 4 | 5 | module.exports = (name, spec, result) => { 6 | return new Promise((resolve, reject) => { 7 | const options = { 8 | url: npmrc.registry + result.escapedName, 9 | headers: { 10 | 'User-Agent': npmrc.userAgent 11 | } 12 | } 13 | var body = '' 14 | request.get(options) 15 | .on('data', (chunk) => { body += chunk }) 16 | .on('end', () => { 17 | try { 18 | body = JSON.parse(body) 19 | const versions = Object.keys(body.versions) 20 | const version = versions.reduce((accumulator, currentValue) => { 21 | if (semver.satisfies(accumulator, spec)) return accumulator 22 | return currentValue 23 | }, '') 24 | const target = body.versions[version] 25 | if (target.deprecated) { 26 | process.stdout.write( 27 | `${target.name}@${target.version}: ${target.deprecated}\n\n` 28 | ) 29 | } 30 | resolve({ 31 | type: 'registry', 32 | version: target.version, 33 | dependencies: target.dependencies, 34 | tarball: target.dist.tarball, 35 | shasum: target.dist.shasum 36 | }) 37 | } catch (e) { return reject(e) } 38 | }) 39 | .on('error', reject) 40 | }) 41 | } 42 | -------------------------------------------------------------------------------- /lib/lock/resolver/fetchers/registry.js: -------------------------------------------------------------------------------- 1 | const request = require('request') 2 | const semver = require('semver') 3 | const npmrc = require('../../../utils/npmrc') 4 | 5 | module.exports = (name, spec, result) => { 6 | return new Promise((resolve, reject) => { 7 | const options = { 8 | url: npmrc.registry + result.escapedName, 9 | headers: { 10 | 'User-Agent': npmrc.userAgent 11 | } 12 | } 13 | var body = '' 14 | request.get(options) 15 | .on('data', (chunk) => { body += chunk }) 16 | .on('end', () => { 17 | try { 18 | body = JSON.parse(body) 19 | const versions = Object.keys(body.versions) 20 | const version = versions.reduce((accumulator, currentValue) => { 21 | if (semver.satisfies(accumulator, spec)) return accumulator 22 | return currentValue 23 | }, '') 24 | const target = body.versions[version] 25 | if (target.deprecated) { 26 | process.stdout.write( 27 | `${target.name}@${target.version}: ${target.deprecated}\n\n` 28 | ) 29 | } 30 | resolve({ 31 | type: 'registry', 32 | version: target.version, 33 | dependencies: target.dependencies, 34 | tarball: target.dist.tarball, 35 | shasum: target.dist.shasum 36 | }) 37 | } catch (e) { return reject(e) } 38 | }) 39 | .on('error', reject) 40 | }) 41 | } 42 | -------------------------------------------------------------------------------- /test/11-install-save.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs') 2 | const path = require('path') 3 | const exec = require('child_process').exec 4 | const tree = require('strong-npm-ls') 5 | const test = require('tap').test 6 | const bin = path.join(__dirname, '..', 'bin', 'dep.js') 7 | const pkg = path.join(__dirname, 'deps/install-save') 8 | const pkgJSON = require(path.join(pkg, 'package.json')) 9 | 10 | test((t) => { 11 | const file = 'happy-birthday@' + path.join(__dirname, 'deps/file/happy-birthday-0.6.0') 12 | exec(`node ${bin} install --save=prod ${file}`, { cwd: pkg }, (err, stdout, stderr) => { 13 | t.ifError(err, `${pkgJSON.name}: install ran without error`) 14 | tree.read(pkg, (err, out) => { 15 | t.ifError(err, `${pkgJSON.name}: tree could be read`) 16 | const deps = out.dependencies 17 | t.ok(deps['happy-birthday'], `${pkgJSON.name}: deps are installed`) 18 | t.end() 19 | }) 20 | }) 21 | }) 22 | 23 | test((t) => { 24 | exec(`node ${bin} install --save=dev text-table`, { cwd: pkg }, (err, stdout, stderr) => { 25 | t.ifError(err, `${pkgJSON.name}: install ran without error`) 26 | tree.read(pkg, (err, out) => { 27 | t.ifError(err, `${pkgJSON.name}: tree could be read`) 28 | const deps = out.devDependencies 29 | t.ok(deps['text-table'], `${pkgJSON.name}: deps are installed`) 30 | t.end() 31 | }) 32 | }) 33 | }) 34 | 35 | test((t) => { 36 | var data = pkgJSON 37 | delete data.dependencies 38 | delete data.devDependencies 39 | fs.writeFileSync(path.join(pkg, 'package.json'), JSON.stringify(data, 2, 2) + '\n') 40 | t.end() 41 | }) 42 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | 8 | # Runtime data 9 | pids 10 | *.pid 11 | *.seed 12 | *.pid.lock 13 | 14 | # Directory for instrumented libs generated by jscoverage/JSCover 15 | lib-cov 16 | 17 | # Coverage directory used by tools like istanbul 18 | coverage 19 | 20 | # nyc test coverage 21 | .nyc_output 22 | 23 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 24 | .grunt 25 | 26 | # Bower dependency directory (https://bower.io/) 27 | bower_components 28 | 29 | # node-waf configuration 30 | .lock-wscript 31 | 32 | # Compiled binary addons (http://nodejs.org/api/addons.html) 33 | build/Release 34 | 35 | # Dependency directories 36 | node_modules/* 37 | jspm_packages/* 38 | 39 | # Typescript v1 declaration files 40 | typings/ 41 | 42 | # Optional npm cache directory 43 | .npm 44 | 45 | # Optional eslint cache 46 | .eslintcache 47 | 48 | # Optional REPL history 49 | .node_repl_history 50 | 51 | # Output of 'npm pack' 52 | *.tgz 53 | 54 | # Yarn Integrity file 55 | .yarn-integrity 56 | 57 | # dotenv environment variables file 58 | .env 59 | 60 | # bundleDependencies 61 | !node_modules/fs-extra/* 62 | !node_modules/gunzip-maybe/* 63 | !node_modules/is-root/* 64 | !node_modules/node-gyp/* 65 | !node_modules/npm-package-arg/* 66 | !node_modules/npm-path/* 67 | !node_modules/promise-each/* 68 | !node_modules/request/* 69 | !node_modules/semver/* 70 | !node_modules/tar-fs/* 71 | !node_modules/tar-stream/* 72 | !node_modules/update-notifier/* 73 | !node_modules/which/* 74 | !node_modules/yargs/* 75 | 76 | # dep 77 | __pycache__ 78 | -------------------------------------------------------------------------------- /lib/lock/resolver.js: -------------------------------------------------------------------------------- 1 | const semver = require('semver') 2 | const tree = require('./resolver/tree') 3 | const fetcher = require('./resolver/fetcher') 4 | 5 | const resolver = (dep, deps, base, resolve, reject) => { 6 | // Search for all related module files referenced by require 7 | if (global.dependenciesTree[dep] && global.dependenciesTree[dep].version) { 8 | if (semver.satisfies(global.dependenciesTree[dep].version, deps[dep])) { 9 | return resolve() 10 | } 11 | } 12 | for (var i = 0; base.length > i; i += 2) { 13 | var target = tree.getter(global.dependenciesTree, base.slice(0, i)) 14 | if (target && target[dep] && target[dep].version) { 15 | if (semver.satisfies(target[dep].version, deps[dep])) { 16 | return resolve() 17 | } 18 | } 19 | } 20 | fetcher(dep, deps[dep]).then((pkg) => { 21 | const item = Object.assign({}, pkg) 22 | delete item.dependencies 23 | if (!global.dependenciesTree[dep]) { 24 | global.dependenciesTree[dep] = item 25 | } else { 26 | tree.setter(global.dependenciesTree, dep, item, base) 27 | } 28 | 29 | if (!pkg.dependencies) return resolve() 30 | 31 | const tasks = Object.keys(pkg.dependencies).map((item) => { 32 | const list = pkg.dependencies 33 | var keys = base.length === 0 34 | ? [].concat(`${dep}@${pkg.version}`) 35 | : [].concat(base, 'dependencies', `${dep}@${pkg.version}`) 36 | return new Promise((resolve, reject) => { 37 | resolver(item, list, keys, resolve, reject) 38 | }) 39 | }) 40 | Promise.all(tasks).then(() => { 41 | resolve() 42 | }).catch(reject) 43 | }).catch(reject) 44 | } 45 | 46 | module.exports = (deps) => { 47 | return Object.keys(deps).map((dep) => { 48 | return new Promise((resolve, reject) => resolver(dep, deps, [], resolve, reject)) 49 | }) 50 | } 51 | -------------------------------------------------------------------------------- /lib/install/resolver.js: -------------------------------------------------------------------------------- 1 | const semver = require('semver') 2 | const tree = require('./resolver/tree') 3 | const fetcher = require('./resolver/fetcher') 4 | 5 | const resolver = (dep, deps, base, resolve, reject) => { 6 | // Search for all related module files referenced by require 7 | if (global.dependenciesTree[dep] && global.dependenciesTree[dep].version) { 8 | if (semver.satisfies(global.dependenciesTree[dep].version, deps[dep])) { 9 | return resolve() 10 | } 11 | } 12 | for (var i = 0; base.length > i; i += 2) { 13 | var target = tree.getter(global.dependenciesTree, base.slice(0, i)) 14 | if (target && target[dep] && target[dep].version) { 15 | if (semver.satisfies(target[dep].version, deps[dep])) { 16 | return resolve() 17 | } 18 | } 19 | } 20 | fetcher(dep, deps[dep]).then((pkg) => { 21 | const item = Object.assign({}, pkg) 22 | delete item.dependencies 23 | if (!global.dependenciesTree[dep]) { 24 | global.dependenciesTree[dep] = item 25 | } else { 26 | tree.setter(global.dependenciesTree, dep, item, base) 27 | } 28 | 29 | if (!pkg.dependencies) return resolve() 30 | 31 | const tasks = Object.keys(pkg.dependencies).map((item) => { 32 | const list = pkg.dependencies 33 | var keys = base.length === 0 34 | ? [].concat(`${dep}@${pkg.version}`) 35 | : [].concat(base, 'dependencies', `${dep}@${pkg.version}`) 36 | return new Promise((resolve, reject) => { 37 | resolver(item, list, keys, resolve, reject) 38 | }) 39 | }) 40 | Promise.all(tasks).then(() => { 41 | resolve() 42 | }).catch(reject) 43 | }).catch(reject) 44 | } 45 | 46 | module.exports = (deps) => { 47 | return Object.keys(deps).map((dep) => { 48 | return new Promise((resolve, reject) => resolver(dep, deps, [], resolve, reject)) 49 | }) 50 | } 51 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "dep", 3 | "version": "0.18.3", 4 | "description": "A little Node.js dependency installer", 5 | "main": "index.js", 6 | "scripts": { 7 | "release": "standard-version", 8 | "pretest": "standard \"lib/**/*.js\" \"bin/*.js\" \"test/*js\" \"scripts/*.js\"", 9 | "test": "tap \"test/*.js\" --timeout 1000 --jobs=1", 10 | "test-ci": "tap --coverage \"test/*.js\" --timeout 1000 --jobs=1" 11 | }, 12 | "repository": { 13 | "type": "git", 14 | "url": "git+https://github.com/depjs/dep.git" 15 | }, 16 | "bin": { 17 | "dep": "./bin/dep.js", 18 | "depjs": "./bin/dep.js" 19 | }, 20 | "keywords": [ 21 | "npm" 22 | ], 23 | "author": "Daijiro Wachi", 24 | "license": "MIT", 25 | "bugs": { 26 | "url": "https://github.com/depjs/dep/issues" 27 | }, 28 | "homepage": "https://github.com/depjs/dep#readme", 29 | "bundleDependencies": [ 30 | "fs-extra", 31 | "gunzip-maybe", 32 | "node-gyp", 33 | "npm-package-arg", 34 | "npm-path", 35 | "promise-each", 36 | "request", 37 | "semver", 38 | "tar-fs", 39 | "tar-stream", 40 | "update-notifier", 41 | "which", 42 | "yargs" 43 | ], 44 | "dependencies": { 45 | "fs-extra": "^9.0.1", 46 | "gunzip-maybe": "^1.4.2", 47 | "node-gyp": "^7.1.0", 48 | "npm-package-arg": "^8.0.1", 49 | "npm-path": "^2.0.4", 50 | "promise-each": "^2.2.0", 51 | "request": "^2.88.2", 52 | "semver": "^7.3.2", 53 | "tar-fs": "^2.1.0", 54 | "tar-stream": "^2.1.4", 55 | "update-notifier": "^4.1.1", 56 | "which": "^2.0.2", 57 | "yargs": "^16.0.3" 58 | }, 59 | "devDependencies": { 60 | "standard": "^14.3.1", 61 | "standard-version": "^9.0.0", 62 | "strong-npm-ls": "^1.0.10", 63 | "tap": "^14.10.2" 64 | }, 65 | "engine": { 66 | "node": ">=10.0.0" 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /.github/CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contribute 2 | First, thank you for considering contributing to dep! Here is a guide to help you understand how dep has been developing by people. 3 | 4 | ## Bug report 5 | When you find issues, please report them: 6 | + https://github.com/depjs/dep/issues/new 7 | 8 | Be sure to follow the issue template. 9 | 10 | ## Feature request 11 | We're trying to find out the bare minimum features for end users. That means it is very reluctant to add new features, but having a discussion is useful for clarifying the minimum definitions. 12 | 13 | Feel free to ask us in #dep-js on https://package.community/ or on [twitter]. 14 | 15 | ## Make a patch 16 | 1. Development process: 17 | + if it's bug fix: making a patch first is great 18 | + if it's feature request: let's disscuss first 19 | 2. Be sure your patch passes `npm test` 20 | 3. Commit message should follow [standard-version][] 21 | 22 | ## Tips 23 | 24 | ### Your First Contribution 25 | 26 | Working on your first Pull Request? You can learn how from this *free* series, [How to Contribute to an Open Source Project on GitHub][]. 27 | 28 | 29 | ### Submitting code 30 | 31 | Any code change should be submitted as a pull request. The description should explain what the code does and give steps to execute it. The pull request should also contain tests. 32 | 33 | ### Code review process 34 | 35 | The bigger the pull request, the longer it will take to review and merge. Try to break down large pull requests in smaller chunks that are easier to review and merge. It is also always helpful to have some context for your pull request. What was the purpose? Why does it matter to you? 36 | 37 | [standard-version]: https://github.com/conventional-changelog/standard-version 38 | [How to Contribute to an Open Source Project on GitHub]: https://egghead.io/series/how-to-contribute-to-an-open-source-project-on-github 39 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Code of Conduct 2 | 3 | ### Table of Contents 4 | 1. Respect others. 5 | 2. Use positive words. 6 | 3. Enjoy this moment. 7 | 8 | ## The three things 9 | 10 | ### 1. Respect others 11 | Everyone has their good points beyond your imagination. It is rare that imagination protrudes its own experience. Let's respect the others by thinking that there is something that can be seen and not seen. There may be people who can not respect, but you do not know it. 12 | 13 | ### 2. Use positive words 14 | It's better not to prattle on about meaningless things. 15 | 16 | We have a passion for the same field, but our backgrounds where we were born and raised are disjointed. There is a culture that says straight. There is a culture that beats around the bush. There is a culture compares an opinion to something. There is a culture that makes sarcastic to tell something. I think of the differences as an impossible thing to bridge the difference. So let's use a positive word at least. Let's say thank you to people who took their time for making improvements. 17 | 18 | 19 | Also in the case of opposing opinions, let's use positive expressions too. That's true sometimes your opinion does not pass, but there is nothing to be pessimistic about. The scope of this project is small and the code base is also small. At such 20 | times, your can fork and modify by yourself. There is a MIT lisence for you. 21 | 22 | ### 3. Enjoy this moment 23 | If you get bored with working on this project, let's go away. As long as you do something in this project, let's enjoy with all people in the project. We spend our spare time and are moving forward with the project. I hope that all of the time is worthwhile and that we can get something good experience through development throughout the project. 24 | 25 | --- 26 | If you think that you can improve this Code Of Conduct, please drop your opinion on the repository. In that case also, please do not forget the three above. 27 | 28 | Thanks for reading this docs <3 29 | -------------------------------------------------------------------------------- /lib/install/installer.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs-extra') 2 | const path = require('path') 3 | const nm = require('../utils/nm') 4 | const bin = require('./installer/bin') 5 | const git = require('./installer/git') 6 | const local = require('./installer/local') 7 | const remote = require('./installer/remote') 8 | const registry = require('./installer/registry') 9 | const runner = require('../run/runner') 10 | 11 | const installer = (dep, deps, base, resolve, reject) => { 12 | fs.ensureDirSync(nm) 13 | fs.ensureDirSync(path.join(nm, '.bin')) 14 | 15 | const target = (base.length === 0) 16 | ? path.join(nm, dep) 17 | : path.join(nm, base.join('/'), 'node_modules', dep) 18 | fs.ensureDirSync(target) 19 | 20 | const pkg = deps[dep] 21 | var fetch 22 | 23 | switch (pkg.type) { 24 | case 'git': 25 | fetch = git(pkg, target) 26 | break 27 | case 'remote': 28 | fetch = remote(pkg, target) 29 | break 30 | case 'local': 31 | fetch = local(pkg, target) 32 | break 33 | case 'registry': 34 | fetch = registry(pkg, target) 35 | break 36 | } 37 | 38 | fetch.then(() => { 39 | return new Promise((resolve, reject) => { 40 | const args = ['', 'install'] 41 | const pkg = require(path.join(target, 'package.json')) 42 | if (!pkg.scripts || ( 43 | pkg.scripts.preinstall && 44 | pkg.scripts.install && 45 | pkg.scripts.postinstall 46 | )) return resolve() 47 | runner(args, pkg, target).then(resolve).catch(reject) 48 | }) 49 | }).then(() => { 50 | global.dependenciesCount += 1 51 | bin(dep, target) 52 | if (fs.existsSync(path.join(target, 'binding.gyp'))) { 53 | global.nativeBuildQueue.push(target) 54 | } 55 | if (!pkg.dependencies) return resolve() 56 | const tasks = Object.keys(pkg.dependencies).map((item) => { 57 | const list = pkg.dependencies 58 | var keys = [].concat(base, dep) 59 | if (keys.length > 1) keys.splice(-1, 0, 'node_modules') 60 | return new Promise((resolve, reject) => { 61 | installer(item, list, keys, resolve, reject) 62 | }) 63 | }) 64 | Promise.all(tasks).then(() => { 65 | resolve() 66 | }).catch(reject) 67 | }).catch(reject) 68 | } 69 | 70 | module.exports = (deps) => { 71 | return Object.keys(deps).map((dep) => { 72 | return new Promise((resolve, reject) => installer(dep, deps, [], resolve, reject)) 73 | }) 74 | } 75 | -------------------------------------------------------------------------------- /lib/install.js: -------------------------------------------------------------------------------- 1 | const path = require('path') 2 | const resolver = require('./install/resolver') 3 | const installer = require('./install/installer') 4 | const saver = require('./install/saver') 5 | const nodeGyp = require('./utils/node-gyp') 6 | const fs = require('fs-extra') 7 | const nm = require('./utils/nm') 8 | const dropPrivilege = require('./utils/drop-privilege') 9 | 10 | global.dependenciesCount = 0 11 | global.dependenciesTree = {} 12 | global.nativeBuildQueue = [] 13 | global.time = process.hrtime() 14 | 15 | const install = (argv) => { 16 | argv._handled = true 17 | const pkgs = argv._.length > 1 ? argv._.slice(1) : [] 18 | const only = argv.only === 'dev' || argv.only === 'prod' ? argv.only : 'all' 19 | const save = argv.save === 'dev' || argv.save === 'prod' ? argv.save : null 20 | const pkgJSON = require(path.join(process.cwd(), 'package.json')) 21 | const optionalDependencies = pkgJSON.optionalDependencies || {} 22 | const allDependencies = { 23 | all: [ 24 | 'dependencies', 25 | 'devDependencies' 26 | ], 27 | prod: [ 28 | 'dependencies' 29 | ], 30 | dev: [ 31 | 'devDependencies' 32 | ] 33 | } 34 | var deps = Object.assign({}, optionalDependencies) 35 | allDependencies[only].forEach((key) => { 36 | if (!pkgJSON[key]) return 37 | Object.assign(deps, pkgJSON[key]) 38 | }) 39 | pkgs.forEach((pkg) => { 40 | const key = pkg.split('@')[0] 41 | const value = pkg.split('@')[1] || '' 42 | deps[key] = value 43 | }) 44 | const list = resolver(deps) 45 | process.stdout.write('Resolving dependencies\n') 46 | fs.removeSync(nm) 47 | Promise.all(list).then(() => { 48 | dropPrivilege() // if root 49 | const tasks = installer(global.dependenciesTree) 50 | process.stdout.write('Installing dependencies\n') 51 | Promise.all(tasks).then(() => { 52 | if (save) saver(pkgs, save) 53 | global.nativeBuildQueue.forEach((cwd) => { 54 | try { 55 | process.stdout.write('Building dependencies\n') 56 | nodeGyp({ cwd: cwd }) 57 | } catch (e) { 58 | // remove the pkg since the deps could be optional 59 | fs.removeSync(cwd) 60 | } 61 | }) 62 | const duration = process.hrtime(global.time) 63 | const time = duration[0] + duration[1] / 1e9 64 | const s = Math.round(time * 1000) / 1000 65 | process.stdout.write( 66 | `Installed ${global.dependenciesCount} packages in ${s}s\n` 67 | ) 68 | }).catch((e) => { process.stderr.write(e.stack) }) 69 | }).catch((e) => { process.stderr.write(e.stack) }) 70 | } 71 | 72 | module.exports = { 73 | command: 'install', 74 | describe: 'Install dependencies defined in package.json', 75 | handler: install, 76 | aliases: ['i'], 77 | options: { 78 | only: { 79 | type: 'string' 80 | }, 81 | save: { 82 | type: 'string' 83 | } 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /lib/install/resolver/fetchers/git.js: -------------------------------------------------------------------------------- 1 | const request = require('request') 2 | const npmrc = require('../../../utils/npmrc') 3 | const git = require('../../../utils/git') 4 | const semver = require('semver') 5 | 6 | const filetemplate = (hosted) => { 7 | return hosted.filetemplate 8 | .replace('{auth@}', hosted.auth ? hosted.auth + '@' : '') 9 | .replace('{domain}', hosted.domain) 10 | .replace('{user}', hosted.user) 11 | .replace('{project}', hosted.project) 12 | .replace('{committish}', hosted.committish ? hosted.committish : '') 13 | .replace('{path}', 'package.json') 14 | } 15 | 16 | const httpstemplate = (hosted, committish) => { 17 | return hosted.httpstemplate 18 | .replace('git+https', 'https') 19 | .replace('{auth@}', hosted.auth ? hosted.auth + '@' : '') 20 | .replace('{domain}', hosted.domain) 21 | .replace('{user}', hosted.user) 22 | .replace('{project}', hosted.project) 23 | .replace('{#committish}', committish ? '#' + hosted.committish : '') 24 | } 25 | 26 | module.exports = (name, spec, result) => { 27 | var hosted = result.hosted 28 | return new Promise((resolve, reject) => { 29 | if (!hosted.committish) { 30 | hosted.committish = git.sync(['ls-remote', httpstemplate(hosted), 'HEAD']) 31 | .slice(0, 6) 32 | } else if (hosted.committish.startsWith('semver:')) { 33 | const range = hosted.committish.replace('semver:', '') 34 | const list = git.sync(['ls-remote', '--tags', httpstemplate(hosted)]) 35 | .split('\n') 36 | list.forEach((str) => { 37 | if (str.split('\t').length === 1) return 38 | const hash = str.split('\t')[0].slice(0, 6) 39 | const version = str.split('\t')[1].replace('refs/tags/', '') 40 | if (version.match(/\^\{\}/)) return 41 | if (!semver.valid(version)) return 42 | if (semver.satisfies(version, range)) hosted.committish = hash 43 | }) 44 | } else { 45 | const committish = git.sync(['ls-remote', '--tags', httpstemplate(hosted)]) 46 | .split('\n') 47 | .filter((str, i) => { 48 | return str.indexOf(hosted.committish) !== -1 49 | }).pop() 50 | hosted.committish = committish 51 | ? committish.split('\t')[0] 52 | : hosted.committish 53 | } 54 | const options = { 55 | url: filetemplate(hosted), 56 | headers: { 57 | 'User-Agent': npmrc.userAgent 58 | } 59 | } 60 | var body = '' 61 | request.get(options) 62 | .on('data', (chunk) => { body += chunk }) 63 | .on('end', () => { 64 | try { 65 | body = JSON.parse(body) 66 | resolve({ 67 | type: 'git', 68 | version: body.version, 69 | dependencies: body.dependencies, 70 | url: httpstemplate(hosted, true) 71 | }) 72 | } catch (e) { return reject(e) } 73 | }) 74 | .on('error', reject) 75 | }) 76 | } 77 | -------------------------------------------------------------------------------- /lib/lock/resolver/fetchers/git.js: -------------------------------------------------------------------------------- 1 | const request = require('request') 2 | const npmrc = require('../../../utils/npmrc') 3 | const git = require('../../../utils/git') 4 | const semver = require('semver') 5 | 6 | const filetemplate = (hosted) => { 7 | return hosted.filetemplate 8 | .replace('{auth@}', hosted.auth ? hosted.auth + '@' : '') 9 | .replace('{domain}', hosted.domain) 10 | .replace('{user}', hosted.user) 11 | .replace('{project}', hosted.project) 12 | .replace('{committish}', hosted.committish ? hosted.committish : '') 13 | .replace('{path}', 'package.json') 14 | } 15 | 16 | const httpstemplate = (hosted, committish) => { 17 | return hosted.httpstemplate 18 | .replace('git+https', 'https') 19 | .replace('{auth@}', hosted.auth ? hosted.auth + '@' : '') 20 | .replace('{domain}', hosted.domain) 21 | .replace('{user}', hosted.user) 22 | .replace('{project}', hosted.project) 23 | .replace('{#committish}', committish ? '#' + hosted.committish : '') 24 | } 25 | 26 | module.exports = (name, spec, result) => { 27 | var hosted = result.hosted 28 | return new Promise((resolve, reject) => { 29 | if (!hosted.committish) { 30 | hosted.committish = git.sync(['ls-remote', httpstemplate(hosted), 'HEAD']) 31 | .slice(0, 6) 32 | } else if (hosted.committish.startsWith('semver:')) { 33 | const range = hosted.committish.replace('semver:', '') 34 | const list = git.sync(['ls-remote', '--tags', httpstemplate(hosted)]) 35 | .split('\n') 36 | list.forEach((str) => { 37 | if (str.split('\t').length === 1) return 38 | const hash = str.split('\t')[0].slice(0, 6) 39 | const version = str.split('\t')[1].replace('refs/tags/', '') 40 | if (version.match(/\^\{\}/)) return 41 | if (!semver.valid(version)) return 42 | if (semver.satisfies(version, range)) hosted.committish = hash 43 | }) 44 | } else { 45 | const committish = git.sync(['ls-remote', '--tags', httpstemplate(hosted)]) 46 | .split('\n') 47 | .filter((str, i) => { 48 | return str.indexOf(hosted.committish) !== -1 49 | }).pop() 50 | hosted.committish = committish 51 | ? committish.split('\t')[0] 52 | : hosted.committish 53 | } 54 | const options = { 55 | url: filetemplate(hosted), 56 | headers: { 57 | 'User-Agent': npmrc.userAgent 58 | } 59 | } 60 | var body = '' 61 | request.get(options) 62 | .on('data', (chunk) => { body += chunk }) 63 | .on('end', () => { 64 | try { 65 | body = JSON.parse(body) 66 | resolve({ 67 | type: 'git', 68 | version: body.version, 69 | dependencies: body.dependencies, 70 | url: httpstemplate(hosted, true) 71 | }) 72 | } catch (e) { return reject(e) } 73 | }) 74 | .on('error', reject) 75 | }) 76 | } 77 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # dep 2 | 3 | A little Node.js dependency installer with the bare minimum features for module **end-users**. 4 | 5 | [](https://github.com/depjs/dep) 6 | 7 | ###### ToDo 8 | + Follow the spec of npm's [package-lock.json] 9 | 10 | ### Table of Contents 11 | 12 |
  • Features
  • 13 |
  • Usage
  • 14 |
  • Concepts
  • 15 |
  • Installation
  • 16 |
  • Uninstallation
  • 17 |
  • Contributing
  • 18 |
  • License
  • 19 | 20 | ## Features 21 | + **Install** the dependencies defined in a local package.json. 22 | + **Lock** the dependencies installed in a local node_modules. 23 | + **Run** an arbitrary command from scripts in a local package.json. 24 | 25 | dep is trying to have a similar/same interface of the features with npm, but there are some slightly different implementations internally. 26 | 27 | ### Install 28 | #### `dep install` 29 | Install all the dependencies defined in a local package.json. 30 | 31 | #### `dep install (@{version|resource})` 32 | You can install a package as like `npm install`. 33 | 34 | ```console 35 | $ dep install webpack 36 | ``` 37 | 38 | #### `dep install --save={dev|prod} (@{version|resource})` 39 | You can install the package and save it to either `dependencies` or `devDependencies` by using `--only={dev|prod}`. 40 | 41 | ```console 42 | $ dep install webpack --save=dev 43 | ``` 44 | 45 | #### `dep install --only={dev|prod}` 46 | You can install either only `dependencies` or `devDependencies` by using `--only={dev|prod}`. 47 | 48 | ```console 49 | $ dep install --only=prod 50 | ``` 51 | 52 | ### Lock 53 | #### `dep lock` 54 | ToDo. 55 | 56 | It will follow the spec of npm's [package-lock.json]. 57 | 58 | ### Run 59 | #### `dep run [script] -- ` 60 | This command will take the matched key with provided `[script]` among the scripts field defined in package.json and execute the value. 61 | 62 | ```console 63 | $ dep run test 64 | ``` 65 | 66 | You also can provide additional arguments by putting `--`. 67 | 68 | ```console 69 | $ dep run build -- dist/bundle.js 70 | ``` 71 | 72 | #### `dep run` 73 | If you do not give an arbitrary [script] to `dep run`, it lists all of the commands from scripts in a local package.json. 74 | 75 | ```console 76 | $ dep run 77 | Available scripts via `dep run` 78 | 79 | dep run build: 80 | webpack src/index.js 81 | dep run test: 82 | tap "test/*.js" 83 | ``` 84 | 85 | ## Usage 86 | ```console 87 | $ dep -h 88 | A little Node.js dependency installer 89 | 90 | Commands: 91 | install Install dependencies defined in package.json [aliases: i] 92 | lock Lock dependencies installed in node_modules [aliases: l] 93 | run Run an arbitrary command from scripts in package.json [aliases: r] 94 | 95 | Options: 96 | --help, -h Show help [boolean] 97 | --version, -v Show version information [boolean] 98 | ``` 99 | 100 | ## Concepts 101 | 102 | ### End users 103 | The target user is always module **end-user** who makes something with `node_modules` and doesn't make packages. And the goal of this project is to **reproduce** most of the features that the end-users use to build their stuff on daily basis. 104 | 105 | ### Save spaces 106 | Speed and local disk capacity are a trade-off. To take the both benefits, it would be better to have the cache in somewhere proxy layer instead of local. 107 | 108 | Therefore, dep does not make cache files in a local disc for now. 109 | 110 | ### Stability 111 | Stability is a core value. Having a small set makes keeping the green badges easier. 112 | 113 | [![github-actions][g-img]][g-url] 114 | 115 | ## Installation 116 | Since dep works independently of npm, dep has a standalone script to install. 117 | 118 | ### Standalone script 119 | ```console 120 | $ curl -L https://github.com/depjs/dep/raw/master/scripts/install.js | node 121 | ``` 122 | 123 | ### via npm 124 | ```console 125 | $ npm install --global dep 126 | ``` 127 | 128 | ## Uninstallation 129 | Also for uninstallation. 130 | 131 | ### Standalone script 132 | ```console 133 | $ curl -L https://github.com/depjs/dep/raw/master/scripts/uninstall.js | node 134 | ``` 135 | 136 | ### via npm 137 | ```console 138 | $ npm uninstall --global dep 139 | ``` 140 | 141 | ## Contributing 142 | 143 | See [CONTRIBUTING.md][] for more info. 144 | 145 | ## License 146 | [MIT][] 147 | 148 | [g-img]: https://github.com/depjs/dep/workflows/Node.js%20CI/badge.svg 149 | [g-url]: https://github.com/depjs/dep/actions 150 | [npm]: https://github.com/npm/npm 151 | [git repository]: https://github.com/watilde/emoji-cli 152 | [twitter]: https://twitter.com/watilde 153 | [package-lock.json]: https://github.com/npm/npm/blob/latest/doc/spec/package-lock.md 154 | [CONTRIBUTING.md]: https://github.com/depjs/dep/blob/master/.github/CONTRIBUTING.md 155 | [MIT]: https://github.com/depjs/dep/blob/master/LICENSE 156 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. 4 | 5 | ### [0.18.3](https://github.com/depjs/dep/compare/v0.18.2...v0.18.3) (2020-09-16) 6 | 7 | 8 | ### Features 9 | 10 | * integrate lock ([c0e4eba](https://github.com/depjs/dep/commit/c0e4ebae1ddb81a73ddd4a26931588ac562e8750)) 11 | 12 | ### [0.18.2](https://github.com/depjs/dep/compare/v0.18.1...v0.18.2) (2019-12-09) 13 | 14 | 15 | ### Bug Fixes 16 | 17 | * update supported node version ([ceec064](https://github.com/depjs/dep/commit/ceec064f5a151eb653ef9a4afdd82e523141bf8c)) 18 | 19 | 20 | ## [0.18.1](https://github.com/depjs/dep/compare/v0.18.0...v0.18.1) (2018-05-20) 21 | 22 | 23 | ### Bug Fixes 24 | 25 | * add Node.js v8 ([7cf42a8](https://github.com/depjs/dep/commit/7cf42a8)) 26 | * do not suppose semver on registry ([d0125d5](https://github.com/depjs/dep/commit/d0125d5)) 27 | * drop v4 and support v10 ([57da2d3](https://github.com/depjs/dep/commit/57da2d3)) 28 | * lock is not ready yet ([ab5848a](https://github.com/depjs/dep/commit/ab5848a)) 29 | 30 | 31 | 32 | 33 | # [0.18.0](https://github.com/depjs/dep/compare/v0.17.1...v0.18.0) (2018-02-25) 34 | 35 | 36 | ### Features 37 | 38 | * drop dat supports ([b5b0a76](https://github.com/depjs/dep/commit/b5b0a76)) 39 | 40 | 41 | 42 | 43 | ## [0.17.1](https://github.com/depjs/dep/compare/v0.17.0...v0.17.1) (2017-10-27) 44 | 45 | 46 | ### Bug Fixes 47 | 48 | * **deps:** update tar-fs ([fdd4146](https://github.com/depjs/dep/commit/fdd4146)) 49 | 50 | 51 | 52 | 53 | # [0.17.0](https://github.com/depjs/dep/compare/v0.16.1...v0.17.0) (2017-09-26) 54 | 55 | 56 | ### Bug Fixes 57 | 58 | * **deps:** add missing node-gyp files ([8325654](https://github.com/depjs/dep/commit/8325654)) 59 | * **install:** use `--quiet` in git processes ([bbdf942](https://github.com/depjs/dep/commit/bbdf942)) 60 | 61 | 62 | ### Features 63 | 64 | * **install:** support git submodule ([1d410f4](https://github.com/depjs/dep/commit/1d410f4)) 65 | 66 | 67 | 68 | 69 | ## [0.16.1](https://github.com/depjs/dep/compare/v0.16.0...v0.16.1) (2017-09-17) 70 | 71 | 72 | ### Bug Fixes 73 | 74 | * **install:** fix to drop privilege ([3f57f04](https://github.com/depjs/dep/commit/3f57f04)) 75 | * **test:** add `t.end` at 01 test ([958ea3e](https://github.com/depjs/dep/commit/958ea3e)) 76 | * **test:** add a test for native-module ([01f44a5](https://github.com/depjs/dep/commit/01f44a5)) 77 | * **test:** fix lint errors ([732ccfd](https://github.com/depjs/dep/commit/732ccfd)) 78 | * **test:** remove debug log ([49d57c4](https://github.com/depjs/dep/commit/49d57c4)) 79 | * **test:** update the permision of nyc ([7a736b1](https://github.com/depjs/dep/commit/7a736b1)) 80 | * **test:** use exec for Windows ([5f75b3e](https://github.com/depjs/dep/commit/5f75b3e)) 81 | * **test:** use execFile ([f9ccb47](https://github.com/depjs/dep/commit/f9ccb47)) 82 | * **test:** use root user at ci ([e3ef948](https://github.com/depjs/dep/commit/e3ef948)) 83 | 84 | 85 | 86 | 87 | # [0.16.0](https://github.com/depjs/dep/compare/v0.15.0...v0.16.0) (2017-09-13) 88 | 89 | 90 | ### Bug Fixes 91 | 92 | * **deps:** remove is-root ([da453d0](https://github.com/depjs/dep/commit/da453d0)) 93 | * **deps:** remove reuqire-directory ([d2c8db2](https://github.com/depjs/dep/commit/d2c8db2)) 94 | * **install:** install path directly ([b1a71ee](https://github.com/depjs/dep/commit/b1a71ee)) 95 | * **install:** path is already resolved by fetchSpec ([4e7aae1](https://github.com/depjs/dep/commit/4e7aae1)) 96 | * **install:** update the switch in saver ([efd88b9](https://github.com/depjs/dep/commit/efd88b9)) 97 | * **test:** add timeout to test cmd ([b6ffc36](https://github.com/depjs/dep/commit/b6ffc36)) 98 | * **test:** rm `.dat` dir after testing ([7952355](https://github.com/depjs/dep/commit/7952355)) 99 | * **test:** save the file deps in tests ([ff05b3f](https://github.com/depjs/dep/commit/ff05b3f)) 100 | * **test:** update directory tree in tests ([1b42853](https://github.com/depjs/dep/commit/1b42853)) 101 | 102 | 103 | ### Features 104 | 105 | * **meta:** transfer the repository to an org ([4dcb286](https://github.com/depjs/dep/commit/4dcb286)) 106 | 107 | 108 | 109 | 110 | # [0.15.0](https://github.com/watilde/dep/compare/v0.14.6...v0.15.0) (2017-09-09) 111 | 112 | 113 | ### Bug Fixes 114 | 115 | * **test:** add test for the deprecated message ([633e457](https://github.com/watilde/dep/commit/633e457)) 116 | 117 | 118 | ### Features 119 | 120 | * **install:** display deprecated message ([eb9eced](https://github.com/watilde/dep/commit/eb9eced)) 121 | 122 | 123 | 124 | 125 | ## [0.14.6](https://github.com/watilde/dep/compare/v0.14.5...v0.14.6) (2017-09-09) 126 | 127 | 128 | ### Bug Fixes 129 | 130 | * **install:** change the permission of bin file ([17f3fb6](https://github.com/watilde/dep/commit/17f3fb6)) 131 | 132 | 133 | 134 | 135 | ## [0.14.5](https://github.com/watilde/dep/compare/v0.14.4...v0.14.5) (2017-09-08) 136 | 137 | 138 | ### Bug Fixes 139 | 140 | * **run:** update the defualt value of the cwd ([b64c200](https://github.com/watilde/dep/commit/b64c200)) 141 | 142 | 143 | 144 | 145 | ## [0.14.4](https://github.com/watilde/dep/compare/v0.14.3...v0.14.4) (2017-09-08) 146 | 147 | 148 | ### Bug Fixes 149 | 150 | * **install:** passing the right cwd to the runner ([df8009d](https://github.com/watilde/dep/commit/df8009d)) 151 | 152 | 153 | 154 | 155 | ## [0.14.3](https://github.com/watilde/dep/compare/v0.14.2...v0.14.3) (2017-09-06) 156 | 157 | 158 | ### Bug Fixes 159 | 160 | * **deps:** remove coveralls and nyc ([a0a7103](https://github.com/watilde/dep/commit/a0a7103)) 161 | * **deps:** stop using rimraf ([89252d8](https://github.com/watilde/dep/commit/89252d8)) 162 | * **gitignore:** ignore mkdirp ([2375194](https://github.com/watilde/dep/commit/2375194)) 163 | * **install:** update removing file at dat fetcher ([e8ad5b9](https://github.com/watilde/dep/commit/e8ad5b9)) 164 | * **refactor:** stop using mkdirp ([53400c6](https://github.com/watilde/dep/commit/53400c6)) 165 | * **test:** add tests for dat dependency ([2391142](https://github.com/watilde/dep/commit/2391142)) 166 | * **test:** fix coverage settings ([f0efd42](https://github.com/watilde/dep/commit/f0efd42)) 167 | * **travis:** use the env at travis ([dd9c2cf](https://github.com/watilde/dep/commit/dd9c2cf)) 168 | 169 | 170 | 171 | 172 | ## [0.14.2](https://github.com/watilde/dep/compare/v0.14.1...v0.14.2) (2017-08-31) 173 | 174 | 175 | ### Bug Fixes 176 | 177 | * **install:** escape the name of scoped packages ([6dad6e7](https://github.com/watilde/dep/commit/6dad6e7)) 178 | * **install:** tree setter should handle scoped package ([e10a011](https://github.com/watilde/dep/commit/e10a011)) 179 | * **lock:** support scoped packages ([18f6557](https://github.com/watilde/dep/commit/18f6557)) 180 | * **test:** skip mac on the ci for a while ([48e919e](https://github.com/watilde/dep/commit/48e919e)) 181 | 182 | 183 | 184 | 185 | ## [0.14.1](https://github.com/watilde/dep/compare/v0.14.0...v0.14.1) (2017-08-27) 186 | 187 | 188 | ### Bug Fixes 189 | 190 | * **install:** read package.json in the method ([a94dbe8](https://github.com/watilde/dep/commit/a94dbe8)) 191 | 192 | 193 | 194 | 195 | # [0.14.0](https://github.com/watilde/dep/compare/v0.13.6...v0.14.0) (2017-08-25) 196 | 197 | 198 | ### Bug Fixes 199 | 200 | * **install:** add error handling to installer ([bbfd4b8](https://github.com/watilde/dep/commit/bbfd4b8)) 201 | * **install:** grammer fix ([e4028fc](https://github.com/watilde/dep/commit/e4028fc)) 202 | * **utils:** exit when couldn't drop privilege ([bbc4190](https://github.com/watilde/dep/commit/bbc4190)) 203 | 204 | 205 | ### Features 206 | 207 | * **install:** drop privileges instead of exit ([2a81a03](https://github.com/watilde/dep/commit/2a81a03)) 208 | 209 | 210 | 211 | 212 | ## [0.13.6](https://github.com/watilde/dep/compare/v0.13.5...v0.13.6) (2017-08-19) 213 | 214 | 215 | ### Bug Fixes 216 | 217 | * **dep:** make dat-node optional ([a2cba8a](https://github.com/watilde/dep/commit/a2cba8a)) 218 | 219 | 220 | 221 | 222 | ## [0.13.5](https://github.com/watilde/dep/compare/v0.13.4...v0.13.5) (2017-08-19) 223 | 224 | 225 | ### Bug Fixes 226 | 227 | * **install:** fix dat util ([36f14c6](https://github.com/watilde/dep/commit/36f14c6)) 228 | * **test:** fix lint errors ([da93efa](https://github.com/watilde/dep/commit/da93efa)) 229 | 230 | 231 | 232 | 233 | ## [0.13.4](https://github.com/watilde/dep/compare/v0.13.3...v0.13.4) (2017-08-19) 234 | 235 | 236 | ### Bug Fixes 237 | 238 | * **install:** fix dat install logic ([76e3281](https://github.com/watilde/dep/commit/76e3281)) 239 | * **install:** fix dat install process ([5a630bb](https://github.com/watilde/dep/commit/5a630bb)) 240 | 241 | 242 | 243 | 244 | ## [0.13.3](https://github.com/watilde/dep/compare/v0.13.2...v0.13.3) (2017-08-15) 245 | 246 | 247 | ### Bug Fixes 248 | 249 | * **test:** add test for install --only ([5580fe6](https://github.com/watilde/dep/commit/5580fe6)) 250 | * **test:** fix lint errors ([5ace741](https://github.com/watilde/dep/commit/5ace741)) 251 | 252 | 253 | 254 | 255 | ## [0.13.2](https://github.com/watilde/dep/compare/v0.13.1...v0.13.2) (2017-08-12) 256 | 257 | 258 | ### Bug Fixes 259 | 260 | * **install:** mkdirp node_modules/.bin ([bdfb743](https://github.com/watilde/dep/commit/bdfb743)) 261 | * **test:** add test for `install --save` ([679b21b](https://github.com/watilde/dep/commit/679b21b)) 262 | * **test:** fix lint errors ([69acbd0](https://github.com/watilde/dep/commit/69acbd0)) 263 | 264 | 265 | 266 | 267 | ## [0.13.1](https://github.com/watilde/dep/compare/v0.13.0...v0.13.1) (2017-08-10) 268 | 269 | 270 | ### Bug Fixes 271 | 272 | * **bin:** add `depjs` alias ([5e8c905](https://github.com/watilde/dep/commit/5e8c905)) 273 | 274 | 275 | 276 | 277 | # [0.13.0](https://github.com/watilde/dep/compare/v0.12.0...v0.13.0) (2017-08-09) 278 | 279 | 280 | ### Bug Fixes 281 | 282 | * **test:** fix lint errors ([81f3fa5](https://github.com/watilde/dep/commit/81f3fa5)) 283 | 284 | 285 | ### Features 286 | 287 | * **install:** add install --save=dev|prod ([170bcf8](https://github.com/watilde/dep/commit/170bcf8)) 288 | 289 | 290 | 291 | 292 | # [0.12.0](https://github.com/watilde/dep/compare/v0.11.0...v0.12.0) (2017-08-07) 293 | 294 | 295 | ### Features 296 | 297 | * **install:** support install ([4601b84](https://github.com/watilde/dep/commit/4601b84)) 298 | 299 | 300 | 301 | 302 | # [0.11.0](https://github.com/watilde/dep/compare/v0.10.3...v0.11.0) (2017-08-07) 303 | 304 | 305 | ### Bug Fixes 306 | 307 | * **scripts:** use --only option ([2c49f00](https://github.com/watilde/dep/commit/2c49f00)) 308 | 309 | 310 | ### Features 311 | 312 | * **install:** add --only option ([caba701](https://github.com/watilde/dep/commit/caba701)) 313 | 314 | 315 | 316 | 317 | ## [0.10.3](https://github.com/watilde/dep/compare/v0.10.2...v0.10.3) (2017-08-06) 318 | 319 | 320 | ### Bug Fixes 321 | 322 | * **dep:** add .npmignore ([b4bcd03](https://github.com/watilde/dep/commit/b4bcd03)) 323 | * **dep:** add bundleDependencies ([f4b592e](https://github.com/watilde/dep/commit/f4b592e)) 324 | * **dep:** add dat-node ([8c68afb](https://github.com/watilde/dep/commit/8c68afb)) 325 | * **dep:** add unbuild modules to dat-node ([23c405d](https://github.com/watilde/dep/commit/23c405d)) 326 | * **dep:** ignore node_modules in dat-node ([ef25188](https://github.com/watilde/dep/commit/ef25188)) 327 | * **dep:** make dat-node optional ([fb1bc71](https://github.com/watilde/dep/commit/fb1bc71)) 328 | * **dep:** put bundleDependencies ([90163ff](https://github.com/watilde/dep/commit/90163ff)) 329 | * **dep:** remove bundle deps of dat-node ([9dd0675](https://github.com/watilde/dep/commit/9dd0675)) 330 | * **dep:** update dat version ([22c6722](https://github.com/watilde/dep/commit/22c6722)) 331 | * **dep:** update dat-node files ([130e879](https://github.com/watilde/dep/commit/130e879)) 332 | * **dep:** update standard version ([51481ac](https://github.com/watilde/dep/commit/51481ac)) 333 | * **gitignore:** put bundleDependencies ([638dd6e](https://github.com/watilde/dep/commit/638dd6e)) 334 | * **gitignore:** tweak the scope of dat-node ([a76904e](https://github.com/watilde/dep/commit/a76904e)) 335 | * **install:** add dat fixture ([35a88f6](https://github.com/watilde/dep/commit/35a88f6)) 336 | * **install:** fix rimraf call ([c2e4b00](https://github.com/watilde/dep/commit/c2e4b00)) 337 | * **install:** fix the path of node-gyp ([5fe9988](https://github.com/watilde/dep/commit/5fe9988)) 338 | * **install:** replace the path of node-gyp ([e7cbe95](https://github.com/watilde/dep/commit/e7cbe95)) 339 | * **refactor:** use arrow function ([88f67cb](https://github.com/watilde/dep/commit/88f67cb)) 340 | * **scirpts:** update install build process ([bfa004e](https://github.com/watilde/dep/commit/bfa004e)) 341 | * **script:** add stand alone install/uninstall script ([fb1cdcc](https://github.com/watilde/dep/commit/fb1cdcc)) 342 | * **script:** fix uninstall/install scripts ([16ba314](https://github.com/watilde/dep/commit/16ba314)) 343 | * **scripts:** add handling dat-node ([dc16b74](https://github.com/watilde/dep/commit/dc16b74)) 344 | * **scripts:** add native build processes to install script ([cf13f4b](https://github.com/watilde/dep/commit/cf13f4b)) 345 | * **scripts:** change the order to install nodeGyp ([90f82c0](https://github.com/watilde/dep/commit/90f82c0)) 346 | * **scripts:** fix lint errors in the install script ([e9306e6](https://github.com/watilde/dep/commit/e9306e6)) 347 | * **scripts:** fix the install script to make a symlink ([ea50cdc](https://github.com/watilde/dep/commit/ea50cdc)) 348 | * **scripts:** improve the logs ([5a1b218](https://github.com/watilde/dep/commit/5a1b218)) 349 | * **test:** check scripts and fix lint errors ([91b30eb](https://github.com/watilde/dep/commit/91b30eb)) 350 | * **util:** change node-gyp path ([f447d44](https://github.com/watilde/dep/commit/f447d44)) 351 | 352 | 353 | 354 | 355 | ## [0.10.2](https://github.com/watilde/dep/compare/v0.10.1...v0.10.2) (2017-08-03) 356 | 357 | 358 | ### Bug Fixes 359 | 360 | * **dep:** downgrade cross-spawn version because of a regression ([0f59e46](https://github.com/watilde/dep/commit/0f59e46)) 361 | * **dep:** uninstall --save cross-spawn ([82ebdbd](https://github.com/watilde/dep/commit/82ebdbd)) 362 | * **dep:** upgrade cross-spawn version because of a regression ([74e8fa3](https://github.com/watilde/dep/commit/74e8fa3)) 363 | * **run:** detached is flase on win32 ([4010a60](https://github.com/watilde/dep/commit/4010a60)) 364 | * **run:** shell is false on win32 ([8a14105](https://github.com/watilde/dep/commit/8a14105)) 365 | * **run:** use {shell: true} ([a5706ce](https://github.com/watilde/dep/commit/a5706ce)) 366 | * **test:** fix lint errors ([e2a6236](https://github.com/watilde/dep/commit/e2a6236)) 367 | 368 | 369 | 370 | 371 | ## [0.10.1](https://github.com/watilde/dep/compare/v0.10.0...v0.10.1) (2017-08-03) 372 | 373 | 374 | ### Bug Fixes 375 | 376 | * **install:** fix process.stderr ([1bbd3ad](https://github.com/watilde/dep/commit/1bbd3ad)) 377 | * **install:** rm node_modules when install starts ([c845e5a](https://github.com/watilde/dep/commit/c845e5a)) 378 | * **meta:** add a meta keyword to package.json ([6187674](https://github.com/watilde/dep/commit/6187674)) 379 | * **refactor:** replace console.error with process.stderr ([ad5df92](https://github.com/watilde/dep/commit/ad5df92)) 380 | * **run:** support multiple commands ([0e5b51d](https://github.com/watilde/dep/commit/0e5b51d)) 381 | * **test:** add double quotes to wrap file names ([6be34e2](https://github.com/watilde/dep/commit/6be34e2)) 382 | * **test:** fix lint errors ([e2443ad](https://github.com/watilde/dep/commit/e2443ad)) 383 | 384 | 385 | 386 | 387 | # [0.10.0](https://github.com/watilde/dep/compare/v0.9.1...v0.10.0) (2017-08-02) 388 | 389 | 390 | ### Bug Fixes 391 | 392 | * **dep:** install --save is-root ([1e08875](https://github.com/watilde/dep/commit/1e08875)) 393 | * **install:** does not allow root users to run lifecycle scripts ([d38ac94](https://github.com/watilde/dep/commit/d38ac94)) 394 | * **install:** fix installer if the lifecycle is empty ([0bc7d59](https://github.com/watilde/dep/commit/0bc7d59)) 395 | * **install:** minor tweak to the log message ([9287673](https://github.com/watilde/dep/commit/9287673)) 396 | 397 | 398 | ### Features 399 | 400 | * **install:** support install scripts ([6f8bd84](https://github.com/watilde/dep/commit/6f8bd84)) 401 | 402 | 403 | 404 | 405 | ## [0.9.1](https://github.com/watilde/dep/compare/v0.9.0...v0.9.1) (2017-08-02) 406 | 407 | 408 | ### Bug Fixes 409 | 410 | * **refactor:** remove debug comment ([edaffdf](https://github.com/watilde/dep/commit/edaffdf)) 411 | 412 | 413 | 414 | 415 | # [0.9.0](https://github.com/watilde/dep/compare/v0.8.0...v0.9.0) (2017-08-02) 416 | 417 | 418 | ### Bug Fixes 419 | 420 | * **dep:** install --save promise-each ([218d67e](https://github.com/watilde/dep/commit/218d67e)) 421 | * **install:** remove tmp file when resolver is finished ([ca50e62](https://github.com/watilde/dep/commit/ca50e62)) 422 | * **test:** add a test for pre/post script ([bab58b5](https://github.com/watilde/dep/commit/bab58b5)) 423 | * **test:** fix lint errors ([2447b47](https://github.com/watilde/dep/commit/2447b47)) 424 | 425 | 426 | ### Features 427 | 428 | * **run:** support pre/post script ([656d70d](https://github.com/watilde/dep/commit/656d70d)) 429 | 430 | 431 | 432 | 433 | # [0.8.0](https://github.com/watilde/dep/compare/v0.7.0...v0.8.0) (2017-08-01) 434 | 435 | 436 | ### Bug Fixes 437 | 438 | * **dep:** install dat-node --save ([b2e0883](https://github.com/watilde/dep/commit/b2e0883)) 439 | * **dep:** update fs-extra to 4.0.1 ([4b4bc9e](https://github.com/watilde/dep/commit/4b4bc9e)) 440 | * **dep:** update which to 1.3.0 ([932ad96](https://github.com/watilde/dep/commit/932ad96)) 441 | * **install:** fix the logic to get the hash at git resolver ([e2ceb04](https://github.com/watilde/dep/commit/e2ceb04)) 442 | 443 | 444 | ### Features 445 | 446 | * **dat:** support dat dependency as an experimental feature ([7001781](https://github.com/watilde/dep/commit/7001781)) 447 | 448 | 449 | 450 | 451 | ## [0.7.1](https://github.com/watilde/dep/compare/v0.7.0...v0.7.1) (2017-07-31) 452 | 453 | 454 | ### Bug Fixes 455 | 456 | * **install:** fix the logic to get the hash at git resolver ([e2ceb04](https://github.com/watilde/dep/commit/e2ceb04)) 457 | 458 | 459 | 460 | 461 | # [0.7.0](https://github.com/watilde/dep/compare/v0.6.1...v0.7.0) (2017-07-31) 462 | 463 | 464 | ### Bug Fixes 465 | 466 | * **dep:** install update-notifier --save ([a0b0259](https://github.com/watilde/dep/commit/a0b0259)) 467 | * **resolver:** use fetchSpec to follow npm ([12b2c68](https://github.com/watilde/dep/commit/12b2c68)) 468 | 469 | 470 | ### Features 471 | 472 | * **notifier:** add update-notifier ([1ba0023](https://github.com/watilde/dep/commit/1ba0023)) 473 | 474 | 475 | 476 | 477 | ## [0.6.1](https://github.com/watilde/dep/compare/v0.6.0...v0.6.1) (2017-07-30) 478 | 479 | 480 | ### Bug Fixes 481 | 482 | * **dep:** use rimraf ([116bdcc](https://github.com/watilde/dep/commit/116bdcc)) 483 | * **ux:** display log about what dep is doing ([f1ec072](https://github.com/watilde/dep/commit/f1ec072)) 484 | 485 | 486 | 487 | 488 | # [0.6.0](https://github.com/watilde/dep/compare/v0.5.2...v0.6.0) (2017-07-30) 489 | 490 | 491 | ### Bug Fixes 492 | 493 | * **dep:** install --save cross-spawn ([caf560b](https://github.com/watilde/dep/commit/caf560b)) 494 | * **dep:** install --save npm-path ([a4a9016](https://github.com/watilde/dep/commit/a4a9016)) 495 | * **run:** exclude stderr ([b03fe83](https://github.com/watilde/dep/commit/b03fe83)) 496 | * **run:** replace spawn with cross-spawn ([ce0fc62](https://github.com/watilde/dep/commit/ce0fc62)) 497 | * **run:** use `process.env` as the context ([614e787](https://github.com/watilde/dep/commit/614e787)) 498 | * **test:** add double quotes ([d4236a8](https://github.com/watilde/dep/commit/d4236a8)) 499 | * **test:** increase test coverage of run ([6a10926](https://github.com/watilde/dep/commit/6a10926)) 500 | 501 | 502 | ### Features 503 | 504 | * **run:** add `dep run` ([6cf3174](https://github.com/watilde/dep/commit/6cf3174)) 505 | 506 | 507 | 508 | 509 | ## [0.5.2](https://github.com/watilde/dep/compare/v0.5.1...v0.5.2) (2017-07-29) 510 | 511 | 512 | ### Bug Fixes 513 | 514 | * **dep:** add native-build package ([249b777](https://github.com/watilde/dep/commit/249b777)) 515 | * **dep:** install --save-dev tap-spec ([7e93d42](https://github.com/watilde/dep/commit/7e93d42)) 516 | * **dep:** install nyc --save-dev ([87e7cb9](https://github.com/watilde/dep/commit/87e7cb9)) 517 | * **dep:** uninstall istanbul ([7dce735](https://github.com/watilde/dep/commit/7dce735)) 518 | * **dep:** uninstall tape-spec ([f56f18f](https://github.com/watilde/dep/commit/f56f18f)) 519 | * **dep:** use tap instead of tape and coverage ([78df61e](https://github.com/watilde/dep/commit/78df61e)) 520 | * **gitignore:** no need to ignore build dir ([8d7dff8](https://github.com/watilde/dep/commit/8d7dff8)) 521 | * **lock:** use path.sep instead of `/` ([fe210a3](https://github.com/watilde/dep/commit/fe210a3)) 522 | * **refactor:** add catch to the main Promise ([c6a6e87](https://github.com/watilde/dep/commit/c6a6e87)) 523 | * **test:** add a quoted string ([0aa9b30](https://github.com/watilde/dep/commit/0aa9b30)) 524 | * **test:** add a test for lock ([de8ecaa](https://github.com/watilde/dep/commit/de8ecaa)) 525 | * **test:** add all type of deps ([e49a833](https://github.com/watilde/dep/commit/e49a833)) 526 | * **test:** add git tests and rename names ([c4396b1](https://github.com/watilde/dep/commit/c4396b1)) 527 | * **test:** add test to resolve complex tree ([6b404d5](https://github.com/watilde/dep/commit/6b404d5)) 528 | * **test:** drop native build ([fadfa86](https://github.com/watilde/dep/commit/fadfa86)) 529 | * **test:** extracted path.sep is always `/` ([ca748d3](https://github.com/watilde/dep/commit/ca748d3)) 530 | * **test:** fix test-ci script ([7e218d7](https://github.com/watilde/dep/commit/7e218d7)) 531 | * **test:** replace istanbul with nyc ([3d3779c](https://github.com/watilde/dep/commit/3d3779c)) 532 | * **test:** replace single quotes with double ([5d49cfb](https://github.com/watilde/dep/commit/5d49cfb)) 533 | * **test:** test help and version ([fdd4277](https://github.com/watilde/dep/commit/fdd4277)) 534 | * **test:** test unhandled help ([7e6a238](https://github.com/watilde/dep/commit/7e6a238)) 535 | * **test:** update help test ([ea9f596](https://github.com/watilde/dep/commit/ea9f596)) 536 | * **travis:** add addons and env for node-gyp ([e1b3192](https://github.com/watilde/dep/commit/e1b3192)) 537 | * **travis:** add env and addon to v4 ([3a45971](https://github.com/watilde/dep/commit/3a45971)) 538 | * **travis:** disable email notification ([e372291](https://github.com/watilde/dep/commit/e372291)) 539 | * **travis:** exclude osx for a while ([ed99f31](https://github.com/watilde/dep/commit/ed99f31)) 540 | * **travis:** get rid of addons on osx ([cbb227b](https://github.com/watilde/dep/commit/cbb227b)) 541 | * **travis:** run test-ci only on v6 ([1ea8682](https://github.com/watilde/dep/commit/1ea8682)) 542 | * **travis:** use test-ci script ([557acc2](https://github.com/watilde/dep/commit/557acc2)) 543 | 544 | 545 | 546 | 547 | ## [0.5.1](https://github.com/watilde/dep/compare/v0.5.0...v0.5.1) (2017-07-27) 548 | 549 | 550 | ### Bug Fixes 551 | 552 | * **dep:** install --save-dev rimraf ([d9118e9](https://github.com/watilde/dep/commit/d9118e9)) 553 | * **dep:** install --save-dev standard-version ([98b7900](https://github.com/watilde/dep/commit/98b7900)) 554 | * **dep:** install tape ([2946548](https://github.com/watilde/dep/commit/2946548)) 555 | * **dep:** remove build scripts ([48207ee](https://github.com/watilde/dep/commit/48207ee)) 556 | * **dep:** uninstall ava ([396874c](https://github.com/watilde/dep/commit/396874c)) 557 | * **dep:** update semver@5.4.1 from 5.3.0 ([e1b741d](https://github.com/watilde/dep/commit/e1b741d)) 558 | * **refactor:** add existsSync in npmrc ([4163485](https://github.com/watilde/dep/commit/4163485)) 559 | * **refactor:** make dep run on Node.js v4 ([ba9cfaf](https://github.com/watilde/dep/commit/ba9cfaf)) 560 | * **refactor:** replace PWD with process.cwd() ([b4ce500](https://github.com/watilde/dep/commit/b4ce500)) 561 | * **refactor:** stop using destructuring assignment ([97780f3](https://github.com/watilde/dep/commit/97780f3)) 562 | * **refactor:** use request instead of https module ([b606b4d](https://github.com/watilde/dep/commit/b606b4d)) 563 | * **test:** add .travis.yml ([937a08b](https://github.com/watilde/dep/commit/937a08b)) 564 | * **test:** add appveyor.yml ([d1037d7](https://github.com/watilde/dep/commit/d1037d7)) 565 | * **test:** cache node_modules in travis ([b5cecbc](https://github.com/watilde/dep/commit/b5cecbc)) 566 | * **test:** replace let with var ([d4308eb](https://github.com/watilde/dep/commit/d4308eb)) 567 | * **test:** sudo should be false on ci ([0e52953](https://github.com/watilde/dep/commit/0e52953)) 568 | * **test:** support only active LTS versions ([8011d5d](https://github.com/watilde/dep/commit/8011d5d)) 569 | * **test:** test on mac/linux with travis ([9cbbfd7](https://github.com/watilde/dep/commit/9cbbfd7)) 570 | 571 | 572 | 573 | 574 | # [0.5.0](https://github.com/watilde/dep/compare/v0.4.1...v0.5.0) (2017-07-27) 575 | 576 | 577 | ### Bug Fixes 578 | 579 | * **dep:** stop using node-tar ([1981d36](https://github.com/watilde/dep/commit/1981d36)) 580 | 581 | 582 | ### Features 583 | * **install:** support the url deps ([61ae9ef](https://github.com/watilde/dep/commit/61ae9ef)) 584 | 585 | 586 | 587 | # [0.4.1](https://github.com/watilde/dep/compare/v0.4.0...v0.4.1) (2017-07-25) 588 | 589 | 590 | ### Bug Fixes 591 | * **install:** fix the order of the native build ([79d682f](https://github.com/watilde/dep/commit/79d682f)) 592 | * **install:** give node-gyp `--silent` option ([763e43e](https://github.com/watilde/dep/commit/763e43e)) 593 | 594 | 595 | # [0.4.0](https://github.com/watilde/dep/compare/v0.3.0...v0.4.0) (2017-07-25) 596 | 597 | ### Bug Fixes 598 | * **dep:** install --save node-gyp ([a9c167b](https://github.com/watilde/dep/commit/a9c167b)) 599 | * **dep:** install --save fs-extra ([a1d80c5](https://github.com/watilde/dep/commit/a1d80c5)) 600 | 601 | ### Features 602 | * **install:** support the native-build deps ([9656173](https://github.com/watilde/dep/commit/9656173)) 603 | * **install:** support the file deps ([8d1e48c](https://github.com/watilde/dep/commit/8d1e48c)) 604 | * **install:** support the option ([1822dc5](https://github.com/watilde/dep/commit/1822dc5)) 605 | 606 | 607 | 608 | # [0.3.0](https://github.com/watilde/dep/compare/v0.2.2...v0.3.0) (2017-07-24) 609 | 610 | ### Bug Fixes 611 | * **dep:** install --save which ([7927647](https://github.com/watilde/dep/commit/7927647)) 612 | * **refactor:** refactor the installer logic ([6a95f3c](https://github.com/watilde/dep/commit/6a95f3c)) 613 | * **test:** fix lint errors ([23d3997](https://github.com/watilde/dep/commit/23d3997)) 614 | * **dep:** install --save npm-package-arg ([e91bd3d](https://github.com/watilde/dep/commit/e91bd3d)) 615 | * **refactor:** add type modules ([ccd265f](https://github.com/watilde/dep/commit/ccd265f)) 616 | * **refactor:** rename the unclear util names ([7002570](https://github.com/watilde/dep/commit/7002570)) 617 | * **test:** fix lint errors ([02b390e](https://github.com/watilde/dep/commit/02b390e)) 618 | 619 | 620 | ### Features 621 | * **install:** support the git deps ([98eb0fe](https://github.com/watilde/dep/commit/98eb0fe)) 622 | * **install:** add the git deps resolver ([38328ed](https://github.com/watilde/dep/commit/38328ed)) 623 | 624 | 625 | # [0.2.2](https://github.com/watilde/dep/compare/v0.2.1...v0.2.2) (2017-07-22) 626 | 627 | 628 | ### Bug Fixes 629 | 630 | 631 | 632 | # [0.2.1](https://github.com/watilde/dep/compare/v0.2.0...v0.2.2) (2017-07-19) 633 | 634 | 635 | ### Bug Fixes 636 | 637 | 638 | 639 | # [0.2.0](https://github.com/watilde/dep/compare/v0.1.0...v0.2.0) (2017-07-14) 640 | 641 | 642 | ### Features 643 | 644 | 645 | 646 | # [0.1.0](https://github.com/watilde/dep/compare/fc3d2a5...v0.1.0) (2017-06-20) 647 | 648 | Initial release. 649 | --------------------------------------------------------------------------------