diff --git a/README.md b/README.md index 7405b2a..62803d7 100644 --- a/README.md +++ b/README.md @@ -42,6 +42,12 @@ options: Same as config `exclude` ++ `-sc, --skipChildren` + + Skip children of an `excluded` directory. Avoids deep scanning of excluded big folders. + + Same as config `skipChildren`. + + `-do, --deleteOrphaned` Delete orphaned or `excluded` (when using API) files/folders in target folder. `false` as default. @@ -143,6 +149,7 @@ name | description | type | values | default | can be `async` ? `config.stayHardlink` | only worked when `type: 'hardlink'`. When `stayHardlink: true`, if src file is "src/a.js", the target file "target/a.js" will be a hardlink of "src/a.js". | Boolean | - | `true` | - `config.exclude` | Priority: `forceSync > exclude`. Filter which src files should not be synced. | RegExp / String / Array (item is RegExp / String) | - | null | - `config.forceSync` | Priority: `forceSync > exclude`. Force sync some files even though they are `excluded`. | RegExp / String / Array (item is RegExp / String) | - | `(file) => { return false }` | No +`config.skipChildren` | skip children of an `excluded` directory. | Boolean | - | `false` | - `config.onError` | callback function when something wrong | Function | - | `(err) => { throw new Error(err) }` | Yes when `syncDirectory.async()` #### Some confusing params diff --git a/cmd.js b/cmd.js index 3750aa9..4e1e6b7 100755 --- a/cmd.js +++ b/cmd.js @@ -7,7 +7,7 @@ const commander = require('commander'); const isAbsoluteUrl = require('is-absolute'); const run = require('./index').sync; -const actor = function ({ from, to, watch, deleteOrphaned, supportSymlink, type, quiet, exclude }) { +const actor = function ({ from, to, watch, deleteOrphaned, supportSymlink, type, quiet, exclude, skipChildren }) { const cwd = process.cwd(); if (!from) { @@ -42,6 +42,7 @@ const actor = function ({ from, to, watch, deleteOrphaned, supportSymlink, type, console.log(' - deleteOrphaned:', deleteOrphaned); console.log(' - type: ', type); console.log(' - exclude: ', exclude); + console.log(' - skipChildren: ', skipChildren); console.log(' - supportSymlink: ', supportSymlink); console.log(''); } @@ -51,6 +52,7 @@ const actor = function ({ from, to, watch, deleteOrphaned, supportSymlink, type, type, deleteOrphaned, exclude, + skipChildren afterEachSync({ eventType, relativePath }) { if (!quiet) { console.log(`${eventType}: `, relativePath); @@ -69,8 +71,9 @@ commander .option('-c, --copy', 'Sync with type `copy`, `copy` as default') .option('-hardlink, --hardlink', 'Sync with type `hardlink`, `copy` as default') .option('-e, --exclude ', 'Filter which src files should not be synced') + .option('-sc, --skipChildren', 'Skip children of an excluded directory') .action((from, to, options) => { - const { watch, deleteOrphaned, symlink, hardlink, quiet, exclude } = options; + const { watch, deleteOrphaned, symlink, hardlink, quiet, exclude, skipChildren } = options; const params = { from, @@ -80,6 +83,7 @@ commander supportSymlink: !!symlink, quiet, exclude, + skipChildren: !!skipChildren, type: hardlink ? 'hardlink' : 'copy', }; diff --git a/index.js b/index.js index 337306a..1159712 100644 --- a/index.js +++ b/index.js @@ -16,6 +16,7 @@ const formatParams = (srcDir, targetDir, customOptions) => { include: null, exclude: null, forceSync: null, + skipChildren: false, onError: (err) => { const e = new Error(err.message); e.stack = err.stack; diff --git a/lib/local-syncfiles.js b/lib/local-syncfiles.js index 6f4b5b3..f7add25 100644 --- a/lib/local-syncfiles.js +++ b/lib/local-syncfiles.js @@ -8,17 +8,17 @@ const matchUtil = require('./match-util'); const readdirEnhanced = require('readdir-enhanced'); const { ignoredSymlinkDirs } = require('./config'); -const readdirSync = (dir, filter) => { +const readdirSync = (dir, skip, filter) => { return readdirEnhanced.sync(dir, { - deep: true, + deep: skip ? filter : true, filter, basePath: dir }); }; -const readdirAsync = async (dir, filter) => { +const readdirAsync = async (dir, skip, filter) => { return await readdirEnhanced.async(dir, { - deep: true, + deep: skip ? filter : true, filter, basePath: dir }); @@ -83,8 +83,8 @@ const removeFile = filePath => { } }; -const syncProcessor = (srcDir, targetDir, { type, exclude, forceSync, afterSync, deleteOrphaned, staySymlink, include }) => { - const srcFiles = readdirSync(srcDir, stats => { +const syncProcessor = (srcDir, targetDir, { type, exclude, forceSync, skipChildren, afterSync, deleteOrphaned, staySymlink, include }) => { + const srcFiles = readdirSync(srcDir, skipChildren, stats => { const filePath = stats.path; const isDirectory = isDirectoryUtil(filePath); const relativePath = `${filePath.replace(srcDir, '')}${isDirectory ? '/' : ''}`; @@ -180,8 +180,8 @@ const syncProcessor = (srcDir, targetDir, { type, exclude, forceSync, afterSync, }; // same as syncProcessor -const asyncProcessor = async (srcDir, targetDir, { type, exclude, forceSync, afterSync, deleteOrphaned, staySymlink, include }) => { - const srcFiles = await readdirAsync(srcDir, stats => { +const asyncProcessor = async (srcDir, targetDir, { type, exclude, forceSync, skipChildren, afterSync, deleteOrphaned, staySymlink, include }) => { + const srcFiles = await readdirAsync(srcDir, skipChildren, stats => { const filePath = stats.path; const isDirectory = isDirectoryUtil(filePath); const relativePath = `${filePath.replace(srcDir, '')}${isDirectory ? '/' : ''}`; diff --git a/test/test.js b/test/test.js index 0892f9e..f76e3cf 100644 --- a/test/test.js +++ b/test/test.js @@ -462,8 +462,7 @@ describe('options', function () { const t = syncDirectory => async function () { const exclude = sinon.spy(p => - p.indexOf('/Dccc1/')>=0 || p === '/fccc1'); - //p === '/Dccc1/' || p === '/fccc1'); + p.indexOf('/Dccc1/') === 0 || p === '/fccc1'); await syncDirectory(srcDir, targetDir, { type: 'copy', @@ -471,14 +470,40 @@ describe('options', function () { }); assert(exclude.calledWith('/Dccc1/')); - // assert(exclude.neverCalledWith('/Dccc1/fccc2')); - // assert(exclude.neverCalledWith('/Dccc1/Dccc2/')); + assert(exclude.calledWith('/Dccc1/fccc2')); + assert(exclude.calledWith('/Dccc1/Dccc2/')); assertDirTree(testDir, treeAfter); }; it('copy new/changed except exclude function (sync)', t(syncDirectory.sync)); it('copy new/changed except exclude function (async)', t(syncDirectory.async)); }); + + describe('skipChildren', function () { + const treeAfter = { + srcDir: treeBefore.srcDir, + targetDir: { ...tree.ab, ...tree.d }, + }; + + const t = syncDirectory => async function () { + const exclude = sinon.spy(p => + p === '/Dccc1/' || p === '/fccc1'); + + await syncDirectory(srcDir, targetDir, { + type: 'copy', + exclude, + skipChildren: true, + }); + + assert(exclude.calledWith('/Dccc1/')); + assert(exclude.neverCalledWith('/Dccc1/fccc2')); + assert(exclude.neverCalledWith('/Dccc1/Dccc2/')); + assertDirTree(testDir, treeAfter); + }; + + it('copy and skip exclude dir (sync)', t(syncDirectory.sync)); + it('copy and skip exclude dir (async)', t(syncDirectory.async)); + }); }); describe('forceSync', function () {