deps-install
Advanced tools
Comparing version
147
index.js
'use strict'; | ||
const exists = require('fs').existsSync; | ||
const fs = require('fs'); | ||
const { resolve, join } = require('path'); | ||
const cp = require('child_process'); | ||
const join = require('path').join; | ||
const loggy = require('loggy'); | ||
const promisify = require('micro-promisify'); | ||
const { promisify } = require('util'); | ||
const exec = promisify(cp.exec); | ||
const readdirp = require('readdirp'); | ||
const semver = require('semver'); | ||
const readFile = promisify(fs.readFile); | ||
const fsAccess = promisify(fs.access); | ||
async function exists(path) { | ||
try { | ||
await fsAccess(path); | ||
return true; | ||
} catch (error) { | ||
return false; | ||
} | ||
} | ||
const readJSON = async path => { | ||
const data = await readFile(path, 'utf-8'); | ||
const json = JSON.parse(data); | ||
return json; | ||
}; | ||
const readVersions = async (root, filterer) => { | ||
const moduleRoot = join(root, 'node_modules'); | ||
const entries = await readdirp.promise(moduleRoot, { | ||
fileFilter: 'package.json', | ||
directoryFilter(entry) { | ||
const dirName = entry.path.replace(moduleRoot, ''); | ||
return filterer.has(dirName); | ||
}, | ||
depth: 1 | ||
}); | ||
const output = {}; | ||
for (const entry of entries) { | ||
const path = join(moduleRoot, entry.path); | ||
const data = await readJSON(path); | ||
output[data.name] = data.version; | ||
} | ||
return output; | ||
}; | ||
async function checkDeps(root, includeDevDeps = false) { | ||
const pth = resolve(join(root, 'package.json')); | ||
const pkg = await readJSON(pth); | ||
const deps = pkg.dependencies || {}; | ||
if (includeDevDeps) { | ||
const dev = pkg.devDependencies || {}; | ||
Object.assign(deps, dev); | ||
} | ||
const filterer = new Set(Object.keys(deps)); | ||
if (Object.keys(deps).length === 0) { | ||
return []; | ||
} | ||
const installed = await readVersions(root, filterer); | ||
const needUpdate = Object.keys(deps).filter(name => { | ||
if (!installed.hasOwnProperty(name)) return true; | ||
const range = deps[name]; | ||
const actualVer = installed[name]; | ||
// TODO: Better check for URLs. Maybe use private npm properties. | ||
if (/\//.test(range)) return false; | ||
// Skip check for version = latest. | ||
if (range === 'latest') return false; | ||
// e.g. semver('1.0.0', '^1') | ||
if (semver.satisfies(actualVer, range)) return false; | ||
return true; | ||
}); | ||
return needUpdate; | ||
} | ||
// Force colors in `exec` outputs | ||
@@ -14,51 +79,53 @@ process.env.FORCE_COLOR = 'true'; | ||
const installed = cmd => { | ||
const _cache = {}; | ||
function installed(cmd) { | ||
if (cmd in _cache) { | ||
return _cache[cmd]; | ||
} | ||
// shell: true must be set for this test to work on non *nixes. | ||
return !cp.spawnSync(cmd, ['--version'], {shell: true}).error; | ||
}; | ||
// TODO: async version | ||
_cache[cmd] = !cp.spawnSync(cmd, ['--version'], { shell: true }).error; | ||
return _cache[cmd]; | ||
} | ||
const getInstallCmd = { | ||
package: rootPath => { | ||
const pkgPath = join(rootPath, 'package.json'); | ||
if (!exists(pkgPath)) return; | ||
async function getInstallCmd(rootPath) { | ||
const pkgPath = join(rootPath, 'package.json'); | ||
if (!(await exists(pkgPath))) return; | ||
if (installed('yarn')) { | ||
const lockPath = join(rootPath, 'yarn.lock'); | ||
if (exists(lockPath)) return 'yarn'; | ||
} | ||
if (installed('yarn')) { | ||
const lockPath = join(rootPath, 'yarn.lock'); | ||
if (await exists(lockPath)) return 'yarn'; | ||
} | ||
return 'npm'; | ||
}, | ||
bower: rootPath => { | ||
const bowerPath = join(rootPath, 'bower.json'); | ||
if (exists(bowerPath) && installed('bower')) return 'bower'; | ||
}, | ||
}; | ||
if (installed('pnpm')) { | ||
const lockPath = join(rootPath, 'shrinkwrap.yaml'); | ||
if (await exists(lockPath)) return 'pnpm'; | ||
} | ||
module.exports = options => { | ||
if (options == null) options = {}; | ||
return 'npm'; | ||
} | ||
const rootPath = options.rootPath || '.'; | ||
const pkgType = [].concat(options.pkgType || []); | ||
const logger = options.logger || loggy; | ||
async function installDeps(rootPath = '.', options = {}) { | ||
const logger = options.logger || console; | ||
const env = process.env.NODE_ENV === 'production' ? '--production' : ''; | ||
const prevDir = process.cwd(); | ||
process.chdir(rootPath); | ||
if (rootPath !== '.') process.chdir(rootPath); | ||
const execs = pkgType.map(type => { | ||
const cmd = getInstallCmd[type](rootPath); | ||
try { | ||
const cmd = await getInstallCmd(rootPath); | ||
if (!cmd) return; | ||
logger.info(`Installing packages with ${cmd}...`); | ||
return exec(`${cmd} install ${env}`); | ||
}); | ||
return Promise.all(execs).then(() => { | ||
process.chdir(prevDir); | ||
}, error => { | ||
process.chdir(prevDir); | ||
await exec(`${cmd} install ${env}`); | ||
return true; | ||
} catch (error) { | ||
error.code = 'INSTALL_DEPS_FAILED'; | ||
logger.error(error); | ||
throw error; | ||
}); | ||
}; | ||
} finally { | ||
if (rootPath !== '.') process.chdir(prevDir); | ||
} | ||
} | ||
exports.checkDeps = checkDeps; | ||
exports.installDeps = installDeps; |
{ | ||
"name": "deps-install", | ||
"version": "0.1.1", | ||
"description": "Tiny tool to install dependencies with bower, npm, or yarn", | ||
"repository": "brunch/deps-install", | ||
"author": "Brunch team (http://brunch.io)", | ||
"license": "MIT", | ||
"bugs": { | ||
"url": "https://github.com/brunch/deps-install/issues" | ||
"version": "0.2.0", | ||
"description": "Check if node_modules match package.json versions. npm / yarn install shortcut.", | ||
"main": "index.js", | ||
"files": [ | ||
"index.js" | ||
], | ||
"scripts": { | ||
"test": "echo \"Error: no test specified\" && exit 1" | ||
}, | ||
"keywords": [ | ||
"bower", | ||
"npm", | ||
"yarn", | ||
"install", | ||
"dependencies" | ||
"check-dependencies", | ||
"dependency", | ||
"check", | ||
"micro", | ||
"install" | ||
], | ||
"author": "Paul Miller (https://paulmillr.com)", | ||
"repository": "https://github.com/brunch/deps-install.git", | ||
"bugs": "https://github.com/brunch/deps-install/issues", | ||
"license": "MIT", | ||
"dependencies": { | ||
"loggy": "^1", | ||
"micro-promisify": "~0.1.0" | ||
}, | ||
"homepage": "https://github.com/brunch/deps-install#readme", | ||
"devDependencies": { | ||
"eslint": "^3.0.0", | ||
"eslint-config-brunch": "brunch/eslint-config-brunch" | ||
}, | ||
"scripts": { | ||
"test": "eslint ." | ||
}, | ||
"eslintConfig": { | ||
"extends": "brunch" | ||
"readdirp": "^3.2.0", | ||
"semver": "^6.3.0" | ||
} | ||
} |
# deps-install | ||
Tiny tool to install dependencies with bower, npm, or yarn. | ||
> Instantly check if node_modules match package.json versions. Returns list of pkgs that don't. | ||
# License | ||
Inspired by [check-dependencies](https://github.com/mgol/check-dependencies), which itself has too many dependencies. | ||
MIT | ||
## Usage | ||
> npm install deps-install | ||
```javascript | ||
const {checkDeps, installDeps} = require('deps-install'); | ||
(async () => { | ||
// rootPath must have package.json and node_modules | ||
const deps = await checkDeps(rootPath); | ||
console.log(deps.length > 0 ? 'Doing npm install' : 'All clear!'); | ||
if (deps.length) await installDeps(rootPath); | ||
})(); | ||
``` | ||
## License | ||
MIT License (c) 2019, Paul Miller (https://paulmillr.com) |
No bug tracker
MaintenancePackage does not have a linked bug tracker in package.json.
Found 1 instance in 1 package
No repository
Supply chain riskPackage does not have a linked source code repository. Without this field, a package will have no reference to the location of the source code use to generate the package.
Found 1 instance in 1 package
No tests
QualityPackage does not have any tests. This is a strong signal of a poorly maintained or low quality package.
Found 1 instance in 1 package
No website
QualityPackage does not have a website.
Found 1 instance in 1 package
No repository
Supply chain riskPackage does not have a linked source code repository. Without this field, a package will have no reference to the location of the source code use to generate the package.
Found 1 instance in 1 package
6013
120.26%0
-100%115
121.15%25
212.5%4
-20%1
Infinity%3
200%+ Added
+ Added
+ Added
+ Added
+ Added
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed