|
|
@ -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))); |
|
|
|