diff --git a/lib/get-files.js b/lib/get-files.js index 446aed5..05916e1 100644 --- a/lib/get-files.js +++ b/lib/get-files.js @@ -4,6 +4,7 @@ import minimatch from 'minimatch'; import IGNORED from './ignored'; import { resolve } from 'path'; import { stat, readdir, readFile } from 'fs-promise'; +import parser from 'gitignore-parser'; /** * Returns a list of files in the given @@ -18,91 +19,58 @@ import { stat, readdir, readFile } from 'fs-promise'; * @return {Array} comprehensive list of paths to sync */ -export default async function getFiles (path, pkg, { - deploymentType = 'npm', +export async function npm (path, pkg, { limit = null, debug = false }) { - if (!pkg && 'npm' === deploymentType) { - const pkgPath = resolve(path, 'package.json'); - const pkgData = await readFile(pkgPath, 'utf8'); - pkg = JSON.parse(pkgData); - } + // the package.json `files` whitelist still + // honors ignores: https://docs.npmjs.com/files/package.json#files + let search = (whitelist || ['.']).push('package.json'); - let search = (pkg ? pkg.files || ['.'] : []).concat( - 'npm' === deploymentType - ? 'package.json' - : 'Dockerfile' - ); + // always include the "main" file + if (pkg.main) { + search.push(pkg.main); + } - if ('npm' === deploymentType && pkg.main) { - search = search.concat(pkg.main); + // always include binary files + if (pkg.bin) { + for (const script in pkg.bin) { + search.push(pkg.bin[script]); + } } + // convert all filenames into absolute paths search = search.map((file) => asAbsolute(file, path)); + // locate files + if (debug) console.time('> [debug] locating files'); + const files = await explode(search, { limit, debug }); + if (debug) console.timeEnd('> [debug] locating files'); + // compile list of ignored patterns and files - let ignored; - if ('npm' === deploymentType) { - const npmIgnore = await maybeRead(resolve(path, '.npmignore')); - const gitIgnore = npmIgnore - ? '' - : (await maybeRead(resolve(path, '.gitignore'))); - ignored = unique(IGNORED - .concat(gitIgnore.split('\n').filter(invalidFilter)) - .concat(npmIgnore.split('\n').filter(invalidFilter))); - } else { - const dockerIgnore = await maybeRead(resolve(path, '.dockerignore')); - ignored = unique(IGNORED - .concat(dockerIgnore.split('\n').filter(invalidFilter))); - } + const npmIgnore = await maybeRead(resolve(path, '.npmignore')); + const ignored = parser.compile( + IGNORED + + '\n' + + npmIgnore + ? npmIgnore + : await maybeRead(resolve(path, '.gitignore')) + ); - ignored = ignored.map((file) => resolve(path, file)); + // if debugging is turned on, describe which files + // are being ignored + const accepts = debug ? function (file) { + const accepted = ignored.accepts(file); + if (!accepted) { + console.log('> [debug] ignoring "%s"', file); + } + return accepted; + } : ignored.accepts; // get files - return unique((await explode(search, ignored, { limit, debug }))); + return unique(files.filter(accepts)); } -/** - * Returns a filter function that - * excludes ignored files in the path. - * - * @param {String} path - * @return {Function} filter fn - */ - -// TODO: revisit this to support the entire -// .dockerignore format like the `!` prefix -const isIgnored = (file, ignored) => { - return ignored.some((test) => { - // test that the target file is not under - // an ignored directory - const dir = test + '/'; - if (file.substr(0, dir.length) === dir) return true; - - // if not match wildcards - return minimatch(file, test); - }); -}; - -/** - * Returns a filter function that - * excludes invalid rules for .*ignore files - * - * @param {String} path - * @return {Function} filter fn - */ - -const invalidFilter = (path) => { - return !( - /* commments */ - '#' === path[0] || - - /* empty lines or newlines */ - !path.trim().length - ); -}; - /** * Transform relative paths into absolutes, * and maintains absolutes as such. @@ -130,7 +98,7 @@ const asAbsolute = function (path, parent) { * @return {Array} of {String}s of full paths */ -const explode = async function (paths, ignored, { limit, debug }) { +const explode = async function (paths, { limit, debug }) { const many = async (all) => { return await Promise.all(all.map(async (file) => { return await list(file); @@ -155,11 +123,6 @@ const explode = async function (paths, ignored, { limit, debug }) { } } - if (isIgnored(file, ignored)) { - if (debug) console.log(`> [debug] Ignoring "${file}"`); - return null; - } - if (s.isDirectory()) { const all = await readdir(file); return many(all.map(subdir => asAbsolute(subdir, file))); diff --git a/lib/ignored.js b/lib/ignored.js index d99276b..6a3b810 100644 --- a/lib/ignored.js +++ b/lib/ignored.js @@ -1,17 +1,17 @@ -export default [ - '.hg', - '.git', - '.gitmodules', - '.svn', - '.npmignore', - '.dockerignore', - '.gitignore', - '.*.swp', - '.DS_Store', - '.wafpickle-*', - '.lock-wscript', - 'npm-debug.log', - 'config.gypi', - 'node_modules', - 'CVS' -]; +// base `.gitignore` to which we add entries +// supplied by the user +export default `.hg +.git +.gitmodules +.svn +.npmignore +.dockerignore +.gitignore +.*.swp +.DS_Store +.wafpicke-* +.lock-wscript +npm-debug.log +config.gypi +node_modules +CVS`; diff --git a/lib/index.js b/lib/index.js index b769b7d..7057692 100644 --- a/lib/index.js +++ b/lib/index.js @@ -1,6 +1,9 @@ import bytes from 'bytes'; import chalk from 'chalk'; -import getFiles from './get-files'; +import { + npm as getNpmFiles, + docker as getDockerFiles +} from './get-npm-files'; import ua from './ua'; import hash from './hash'; import retry from 'async-retry'; @@ -41,7 +44,7 @@ export default class Now extends EventEmitter { this._path = path; let pkg = {}; - let name, description; + let name, description, files; if ('npm' === deploymentType) { try { @@ -68,6 +71,10 @@ export default class Now extends EventEmitter { } description = pkg.description; + + if (this._debug) console.time('> [debug] Getting files'); + files = await getNpmFiles(path, pkg, { debug: this._debug }); + if (this._debug) console.timeEnd('> [debug] Getting files'); } else if ('docker' === deploymentType) { let docker; try { @@ -123,6 +130,10 @@ export default class Now extends EventEmitter { } description = labels.description; + + if (this._debug) console.time('> [debug] Getting files'); + files = await getDockerFiles(path, { debug: this._debug }); + if (this._debug) console.timeEnd('> [debug] Getting files'); } const nowProperties = pkg ? pkg.now || {} : {}; @@ -152,13 +163,6 @@ export default class Now extends EventEmitter { } } - if (this._debug) console.time('> [debug] Getting files'); - const files = await getFiles(path, pkg, { - deploymentType, - debug: this._debug - }); - if (this._debug) console.timeEnd('> [debug] Getting files'); - if (this._debug) console.time('> [debug] Computing hashes'); const hashes = await hash(files); if (this._debug) console.timeEnd('> [debug] Computing hashes'); diff --git a/package.json b/package.json index 1dd13cf..b8ca0ed 100644 --- a/package.json +++ b/package.json @@ -62,6 +62,7 @@ "email-prompt": "0.1.8", "email-validator": "1.0.4", "fs-promise": "0.5.0", + "gitignore-parser": "0.0.2", "graceful-fs": "4.1.4", "ini": "1.3.4", "minimatch": "3.0.0",