Skip to content

sync two directories by copying or creating hardlink.

Notifications You must be signed in to change notification settings

dwidge/sync-directory

 
 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Description

sync-directory can sync files from src directory to target directory.

CLI and API are supported.

We have two ways to sync files: hardlink and copy.

If type is copy, sync-directory will copy files from src directory to target directory.

If type is hardlink, sync-directory can create hardlink files in target directory from src directory.

sync-directory uses copy by default for safety. (hardlink will be quicker but some watchers can't trigger change event for target files.)

Cli

npm i sync-directory -g
syncdir <from> <to> [options]

Example: syncdir aaa bbb -w

options:

  • -w, --watch

    Watch changes. false as default.

    Same as config watch.

  • --quiet

    Disable unnecessary logs.

  • --exclude <strings...>

    Exclude some path. Such as syncdir a b --exclude node_modules package-lock.json.

    Same as config exclude

  • -si, --skipInitialSync

    Skip the first time sync actions when it's true. It's useful when you just want the srcFolder to be watched. false as default.

    Same as config skipInitialSync.

  • -nd, --nodeep

    Just walk the first level sub files/folders. Avoids deep scanning of big folders.

    Same as config nodeep.

  • -do, --deleteOrphaned

    Delete orphaned or excluded (when using API) files/folders in target folder. false as default.

    Same as config deleteOrphaned.

  • -hardlink, --hardlink

    Sync with type hardlink, copy as default.

    Same as config type: 'hardlink'.

  • -symlink, --symlink

    support symlink while sync running. false as default.

    Same as config staySymlink.

API

sync

const syncDirectory = require('sync-directory');

syncDirectory.sync(srcDir, targetDir, {
    afterEachSync({ eventType, nodeType, relativePath, srcPath, targetPath }) {

    },
});

async

(async () => {
    const syncDirectory = require('sync-directory');

    const delay = (time = 2000) => new Promise(r => setTimeout(r, time));

    console.log('start'); // time a

    // wait several 2s: 2 * file number
    await syncDirectory.async(srcDir, targetDir, {
        async afterEachSync({ eventType, nodeType, relativePath, srcPath, targetPath }) {
            await delay(2000); // delay 2s after one file/folder was synced
        },
    });

    console.log('end'); // time a + 2 * (file number)
})()

Pick Your API

const syncDirectory = require('sync-directory');
syncDirectory(srcDir, targetDir[, config]);

Syntax

Function Returns Syntax Block the thread?
syncDirectory()
syncDirectory.sync()
undefined or chokidar watcher Synchronous Yes
syncDirectory.async() Promise async / await
Promise.then()
No

Returns

const watcher = syncDirectory(A, B);

watcher is undefined.

const watcher = syncDirectory(A, B, {
    watch: true
});

watcher is a chokidar watcher.

Params

Params Overview

name description type values default can be async ?
srcDir src directory String absolute or relative path - -
targetDir target directory String absolute or relative path - -
config.cwd when srcDir or targetDir is a relative path, they will be formatted to absolute path by `path.join(cwd, srcDir targetDir)` string - process.cwd()
config.watch watch file changes Boolean - false -
config.chokidarWatchOptions watch options (chokidar is used for watching) Object - {} -
config.type way to sync files String 'copy' | 'hardlink' 'copy' -
config.skipInitialSync skip the first time sync actions when it's true. It's useful when you just want the srcFolder to be watched. Boolean true | false false -
config.deleteOrphaned delete orphaned or excluded (API using) files/folders in target folder. false as default. Boolean - false -
config.afterEachSync callback function when every file synced Function - blank function Yes when syncDirectory.async()
config.staySymlink if src folder "A/" is a symlink, the target folder "A/" will also be the same symlink. Boolean - false -
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.nodeep Just walk the first level sub files/folders. Boolean - false -
config.onError callback function when something wrong Function - (err) => { throw new Error(err) } Yes when syncDirectory.async()

Some confusing params

image

Params Details

  • cwd

    Type: String

    Default: process.cwd()

    For: format srcDir | targetDir to absolute path when they are relative paths

    syncDirectory(srcDir, targetDir, {
        cwd: __dirname
    });
  • watch

    Type: true | false

    Default: false

    For: watch file changes.

    syncDirectory(srcDir, targetDir, {
        watch: true
    });
  • chokidarWatchOptions

    Type: Object

    Default: {}

    For: watch options (chokidar is used for watching).

    syncDirectory(srcDir, targetDir, {
        chokidarWatchOptions: {
            awaitWriteFinish: {
                stabilityThreshold: 2000,
                pollInterval: 100
            }
        },
    });
  • afterEachSync

    Type: Function

    Default: () => {}

    For: callback function when every file synced.

    syncDirectory.sync(srcDir, targetDir, {
        afterEachSync({ eventType, nodeType, relativePath, srcPath, targetPath }) {
    
        }
    });
    
    await syncDirectory.async(srcDir, targetDir, {
        async afterEachSync({ eventType, nodeType, relativePath, srcPath, targetPath }) {
            
        }
    });
    • eventType: "init:hardlink" / "init:copy" / "add" / "change" / "unlink" / "unlinkDir" / "addDir"
    • nodeType: "file" / "dir"
    • relativePath: relative file/folder path
    • srcPath: absolute or relative src file/folder path
    • targetPath: absolute or relative target file/folder path
  • type

    Type: 'copy' | 'hardlink'

    Default: 'copy'

    For: way to sync files.

    • copy (default)

      syncDirectory(srcDir, targetDir);
    • hardlink

      syncDirectory(srcDir, targetDir, {
          type: 'hardlink'
      });
  • skipInitialSync

    Type: true | false

    Default: false

    For: enhance the performance

    It's for enhancing the sync performance when you just want srcDir to be watched.

    syncDirectory(srcDir, targetDir, {
        skipInitialSync: true,
        watch: true,
    })

    The srcDir won't be synced to targetDir when skipInitialSync: true and the srcDir's file changes will be watched and synced to targetDir.

  • stayHardlink

    Type: true | false

    Default: true

    Only works 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".

    Then when "src/a.js" changed, "target/a.js" will remain a hardlink. Otherwise will be a copied file.

    Some watchers will not be able to watch changes of "target/a.js".

  • nodeep

    Type: true | false

    Default: false

    Just walk the first level sub files/folders. Avoids deep scanning of big folders.

    The reason why deep was not used is that cli options is --nodeep. Just keep this two the same.

    // srcFolder:
    //     a/     a is symlink
    //      1.js
    
    // targetFolder:
    //     a/
    syncDirectory(srcDir, targetDir, {
        nodeep: true, // 1.js will be ignored
    });
  • deleteOrphaned

    Type: true | false

    Default: false

    Delete orphaned or excluded (when using API) files/folders in target folder. false as default.

    For instance:

    srcDir:
    
    dir1/
        1.js
        2.js
    
    targetDir:
    
    dir2/
        1.js
        2.js
        3.js
    syncDirectory(srcDir, targetDir, {
        deleteOrphaned: true,
        excluded: [ '2.js' ]
    });
    
    // dir2/3.js will be removed because dir1/3.js does not exist.
    // dir2/2.js will be removed because dir1/2.js is excluded.
  • exclude

    Type: Function / RegExp / String / Array (item is RegExp / String)

    Priority: forceSync > exclude.

    Default: null

    For: declare files that should not sync to target directory.

    • Function

      syncDirectory(srcDir, targetDir, {
          exclude(filePath) {
              return /node_modules/.test(filePath);
          }
      });
    • String

      syncDirectory(srcDir, targetDir, {
          exclude: 'node_modules'
      });
    • RegExp

      syncDirectory(srcDir, targetDir, {
          exclude: /node\_modules/
      });
    • Array

      syncDirectory(srcDir, targetDir, {
          exclude: [/node\_modules/]
      });
      syncDirectory(srcDir, targetDir, {
          exclude: ['node_modules']
      });
  • forceSync

    Type: Function / RegExp / String / Array (item is RegExp / String)

    Priority: forceSync > exclude.

    Default: null

    For: some files must be synced even though 'excluded'.

    • Function

      syncDirectory(srcDir, targetDir, {
          exclude: ['node_modules'],
          forceSync(filePath) {
              return /node_modules\/jquery/.test(filePath);
          }
      });
    • String

      syncDirectory(srcDir, targetDir, {
          exclude: ['node_modules'],
          forceSync: 'node_modules/jquery'
      });
    • RegExp

      syncDirectory(srcDir, targetDir, {
          exclude: ['node_modules'],
          forceSync: /node_modules\/jquery/
      });
    • Array

      syncDirectory(srcDir, targetDir, {
          exclude: ['node_modules'],
          forceSync: [/node_modules\/jquery/]
      });
      syncDirectory(srcDir, targetDir, {
          exclude: ['node_modules'],
          forceSync: ['node_modules/jquery']
      });
  • staySymlink

    Type: true | false

    Default: false

    If src folder "A/" is a symlink, the target folder "A/" will also be the same symlink.

    // srcFolder:
    //     a/     a is symlink
    //      1.js
    
    // targetFolder:
    //     a/     a is not symlink
    //      1.js
    syncDirectory(srcDir, targetDir, {
        staySymlink: false,
    });
    // srcFolder:
    //     a/     a is symlink
    //      1.js
    
    // targetFolder:
    //     a/     a is the same symlink
    //      1.js
    syncDirectory(srcDir, targetDir, {
        staySymlink: true,
    });
  • onError

    Type: Function

    Default: (err) => { throw new Error(err) }

    For: callback function when something wrong.

    syncDirectory(srcDir, targetDir, {
        onError(err) {
            console.log(err.message);
        },
    });

LICENSE

MIT

About

sync two directories by copying or creating hardlink.

Resources

Stars

Watchers

Forks

Packages

No packages published

Languages

  • JavaScript 100.0%