From bae874a1b0237a431fc2d8f25c4e4b58e7572ac4 Mon Sep 17 00:00:00 2001 From: Toru Nagashima Date: Mon, 5 Sep 2016 06:21:17 +0900 Subject: [PATCH] New: `--no-initial` option --- README.md | 15 +++++---- src/bin/help.js | 4 ++- src/bin/index.js | 45 +++++++++++++------------ src/bin/main.js | 1 + src/lib/cpx.js | 14 +++++++- test/misc.js | 4 +-- test/watch.js | 87 ++++++++++++++++++++++++++++++++++++++++++++++++ 7 files changed, 138 insertions(+), 32 deletions(-) diff --git a/README.md b/README.md index 2462448..15c8a38 100644 --- a/README.md +++ b/README.md @@ -35,8 +35,10 @@ Options: directory before the first copying. -L, --dereference Follow symbolic links when copying from them. -h, --help Print usage information. - --include-empty-dirs The flag to copy empty directories which is + --include-empty-dirs The flag to copy empty directories which is matched with the glob. + --no-initial The flag to not copy at the initial time of watch. + Use together '--watch' option. -p, --preserve The flag to copy attributes of files. This attributes are uid, gid, atime, and mtime. -t, --transform A module name to transform each file. cpx lookups @@ -101,12 +103,13 @@ cpx.copy(source, dest, callback) - **source** `{string}` -- A file glob of copy targets. - **dest** `{string}` -- A file path of a destination directory. - **options** `{object}` - - **options.clean** `{boolean}` -- The flag to remove files that copied on past before copy. - - **options.dereference** `{boolean}` -- The flag to follow symbolic links when copying from them. - - **options.includeEmptyDirs** `{boolean}` -- The flag to copy empty directories which is matched with the glob. - - **options.preserve** `{boolean}` -- The flag to copy uid, gid, atime, and mtime of files. + - **options.clean** `{boolean}` -- The flag to remove files that copied on past before copy. Default: `false`. + - **options.dereference** `{boolean}` -- The flag to follow symbolic links when copying from them. Default: `false`. + - **options.includeEmptyDirs** `{boolean}` -- The flag to copy empty directories which is matched with the glob. Default: `false`. + - **options.initialCopy** `{boolean}` -- The flag to not copy at the initial time of watch. This is for `cpx.watch()`. Default: `true`. + - **options.preserve** `{boolean}` -- The flag to copy uid, gid, atime, and mtime of files. Default: `false`. - **options.transform** `{((filepath: string) => stream.Transform)[]}` -- Functions that creates a `stream.Transform` object to transform each copying file. - - **options.update** `{boolean}` -- The flag to not overwrite files on destination if the source file is older. + - **options.update** `{boolean}` -- The flag to not overwrite files on destination if the source file is older. Default: `false`. - **callback** `{(err: Error|null) => void}` -- A function that is called at done. Copy files that matches with `source` glob to `dest` directory. diff --git a/src/bin/help.js b/src/bin/help.js index 2e31b16..2a2574b 100644 --- a/src/bin/help.js +++ b/src/bin/help.js @@ -28,8 +28,10 @@ Options: directory before the first copying. -L, --dereference Follow symbolic links when copying from them. -h, --help Print usage information. - --include-empty-dirs The flag to copy empty directories which is + --include-empty-dirs The flag to copy empty directories which is matched with the glob. + --no-initial The flag to not copy at the initial time of watch. + Use together '--watch' option. -p, --preserve The flag to copy attributes of files. This attributes are uid, gid, atime, and mtime. -t, --transform A module name to transform each file. cpx lookups diff --git a/src/bin/index.js b/src/bin/index.js index 96643c1..a0900a9 100644 --- a/src/bin/index.js +++ b/src/bin/index.js @@ -13,46 +13,47 @@ const subarg = require("subarg") //------------------------------------------------------------------------------ // Parse arguments. -const OPTIONS = { - c: "command", - C: "clean", - h: "help", - includeEmptyDirs: "include-empty-dirs", - L: "dereference", - p: "preserve", - t: "transform", - u: "update", - v: "verbose", - V: "version", - w: "watch", -} +const unknowns = new Set() const args = subarg(process.argv.slice(2), { + alias: { + c: "command", + C: "clean", + h: "help", + includeEmptyDirs: "include-empty-dirs", + L: "dereference", + p: "preserve", + t: "transform", + u: "update", + v: "verbose", + V: "version", + w: "watch", + }, boolean: [ "clean", "dereference", "help", "include-empty-dirs", + "initial", "preserve", "update", "verbose", "version", "watch", ], - alias: OPTIONS, + default: {initial: true}, + unknown: (arg) => { + if (arg[0] === "-") { + unknowns.add(arg) + } + }, }) const source = args._[0] const outDir = args._[1] //------------------------------------------------------------------------------ // Validate Options. -const knowns = new Set(["_"]) -for (const key in OPTIONS) { - knowns.add(key) - knowns.add(OPTIONS[key]) -} -const unknowns = Object.keys(args).filter(key => !knowns.has(key)) -if (unknowns.length > 0) { - console.error(`Unknown option(s): ${unknowns.join(", ")}`) +if (unknowns.size > 0) { + console.error(`Unknown option(s): ${Array.from(unknowns).join(", ")}`) process.exit(1) } diff --git a/src/bin/main.js b/src/bin/main.js index 50dc5df..dd4b9e6 100644 --- a/src/bin/main.js +++ b/src/bin/main.js @@ -94,6 +94,7 @@ module.exports = function main(source, outDir, args) { transform: mergedTransformFactories, dereference: args.dereference, includeEmptyDirs: args.includeEmptyDirs, + initialCopy: args.initial, preserve: args.preserve, update: args.update, } diff --git a/src/lib/cpx.js b/src/lib/cpx.js index 5b1691f..505674c 100644 --- a/src/lib/cpx.js +++ b/src/lib/cpx.js @@ -28,6 +28,7 @@ const Queue = require("./queue") const BASE_DIR = Symbol("baseDir") const DEREFERENCE = Symbol("dereference") const INCLUDE_EMPTY_DIRS = Symbol("include-empty-dirs") +const INITIAL_COPY = Symbol("initialCopy") const OUT_DIR = Symbol("outDir") const PRESERVE = Symbol("preserve") const SOURCE = Symbol("source") @@ -145,6 +146,9 @@ module.exports = class Cpx extends EventEmitter { this[OUT_DIR] = normalizePath(outDir) this[DEREFERENCE] = Boolean(options.dereference) this[INCLUDE_EMPTY_DIRS] = Boolean(options.includeEmptyDirs) + this[INITIAL_COPY] = + options.initialCopy === undefined || + Boolean(options.initialCopy) this[PRESERVE] = Boolean(options.preserve) this[TRANSFORM] = [].concat(options.transform).filter(Boolean) this[UPDATE] = Boolean(options.update) @@ -189,6 +193,14 @@ module.exports = class Cpx extends EventEmitter { return this[INCLUDE_EMPTY_DIRS] } + /** + * The flag to copy files at the initial time of watch. + * @type {boolean} + */ + get initialCopy() { + return this[INITIAL_COPY] + } + /** * The flag to copy file attributes. * @type {boolean} @@ -483,7 +495,7 @@ module.exports = class Cpx extends EventEmitter { if (ready) { this.enqueueCopy(normalizedPath) } - else { + else if (this.initialCopy) { firstCopyCount += 1 this.enqueueCopy(normalizedPath, () => { firstCopyCount -= 1 diff --git a/test/misc.js b/test/misc.js index 5cab79d..40592cc 100644 --- a/test/misc.js +++ b/test/misc.js @@ -14,14 +14,14 @@ describe("[misc]", () => { const result = execCommandSync("\"test-ws/a/**/*.txt\" test-ws/b --invalid") assert(result.code === 1) - assert(result.stderr === "Unknown option(s): invalid\n") + assert(result.stderr === "Unknown option(s): --invalid\n") }) it("should throw error if invalid options were given.", () => { const result = execCommandSync("\"test-ws/a/**/*.txt\" test-ws/b --invalid --foo --bar") assert(result.code === 1) - assert(result.stderr === "Unknown option(s): invalid, foo, bar\n") + assert(result.stderr === "Unknown option(s): --invalid, --foo, --bar\n") }) it("should throw error and show help if and were lacking.", () => { diff --git a/test/watch.js b/test/watch.js index b2dced5..361cec9 100644 --- a/test/watch.js +++ b/test/watch.js @@ -308,6 +308,52 @@ describe("The watch method", () => { }) }) + describe("should not copy specified files with globs at first when `--no-initial` option was given:", () => { + beforeEach(() => { + setupTestDir({ + "test-ws/untachable.txt": "untachable", + "test-ws/a/hello.txt": "Hello", + "test-ws/a/b/this-is.txt": "A pen", + "test-ws/a/b/that-is.txt": "A note", + "test-ws/a/b/no-copy.dat": "no-copy", + }) + }) + + /** + * Verify. + * @returns {void} + */ + function verifyFiles() { + assert(content("test-ws/untachable.txt") === "untachable") + assert(content("test-ws/a/hello.txt") === "Hello") + assert(content("test-ws/a/b/this-is.txt") === "A pen") + assert(content("test-ws/a/b/that-is.txt") === "A note") + assert(content("test-ws/a/b/no-copy.dat") === "no-copy") + assert(content("test-ws/b/untachable.txt") === null) + assert(content("test-ws/b/hello.txt") === null) + assert(content("test-ws/b/b/this-is.txt") === null) + assert(content("test-ws/b/b/that-is.txt") === null) + assert(content("test-ws/b/b/no-copy.dat") === null) + } + + it("lib version.", (done) => { + watcher = cpx.watch("test-ws/a/**/*.txt", "test-ws/b", {initialCopy: false}) + watcher.on("watch-ready", () => { + // Done the first copies. + verifyFiles() + done() + }) + }) + + it("command version.", (done) => { + command = execCommand("\"test-ws/a/**/*.txt\" test-ws/b --no-initial --watch --verbose") + waitForReady(() => { + verifyFiles() + done() + }) + }) + }) + ;[ { description: "should copy on file added:", @@ -509,4 +555,45 @@ describe("The watch method", () => { }) }) }) + + describe("should copy it when a file is added even if '--no-initial' option was given:", () => { + beforeEach(() => { + setupTestDir({ + "test-ws/a/hello.txt": "Hello", + "test-ws/a/b/hello.txt": "Hello", + }) + }) + + /** + * Verify. + * @returns {void} + */ + function verifyFiles() { + assert(content("test-ws/b/hello.txt") === null) + assert(content("test-ws/b/b/hello.txt") === null) + assert(content("test-ws/b/added.txt") === "added") + } + + it("lib version.", (done) => { + watcher = cpx.watch("test-ws/a/**", "test-ws/b", {initialCopy: false}) + waitForReady(() => { + writeFile("test-ws/a/added.txt", "added") + waitForCopy(() => { + verifyFiles() + done() + }) + }) + }) + + it("command version.", (done) => { + command = execCommand("\"test-ws/a/**\" test-ws/b --no-initial --watch --verbose") + waitForReady(() => { + writeFile("test-ws/a/added.txt", "added") + waitForCopy(() => { + verifyFiles() + done() + }) + }) + }) + }) })