├── .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 |