Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve filter option in copySync #424

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 22 additions & 1 deletion lib/copy-sync/__tests__/copy-sync-dir.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,7 @@ describe('+ copySync()', () => {
it('should apply filter when it is applied only to dest', done => {
const timeCond = new Date().getTime()

const filter = (s, d) => fs.statSync(d).birthtime.getTime() < timeCond
const filter = (s, d) => fs.existsSync(d) && fs.statSync(d).birthtime.getTime() < timeCond

const dest = path.join(TEST_DIR, 'dest')

Expand Down Expand Up @@ -200,5 +200,26 @@ describe('+ copySync()', () => {
done()
}, 1000)
})

it('should apply filter recursively on failed dirs', () => {
const srcDir = path.join(TEST_DIR, 'src')
const srcFile1 = path.join(srcDir, '1.js')
const srcFile2 = path.join(srcDir, '2.css')
const srcFile3 = path.join(srcDir, 'subdir', '3.css')
fs.outputFileSync(srcFile1, 'file 1 stuff')
fs.outputFileSync(srcFile2, 'file 2 stuff')
fs.outputFileSync(srcFile3, 'file 3 stuff')
const destDir = path.join(TEST_DIR, 'dest')
const destFile1 = path.join(destDir, '1.js')
const destFile2 = path.join(destDir, '2.css')
const destFile3 = path.join(destDir, 'subdir', '3.css')

const filter = s => path.extname(s) === '.css'

fs.copySync(srcDir, destDir, filter)
assert(!fs.existsSync(destFile1))
assert(fs.existsSync(destFile2))
assert(fs.existsSync(destFile3))
})
})
})
41 changes: 0 additions & 41 deletions lib/copy-sync/copy-file-sync.js

This file was deleted.

116 changes: 84 additions & 32 deletions lib/copy-sync/copy-sync.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,24 +2,22 @@

const fs = require('graceful-fs')
const path = require('path')
const copyFileSync = require('./copy-file-sync')
const mkdir = require('../mkdirs')
const buffer = require('../util/buffer')
const mkdirpSync = require('../mkdirs').mkdirsSync

function copySync (src, dest, options) {
if (typeof options === 'function' || options instanceof RegExp) {
options = {filter: options}
}

options = options || {}
options.recursive = !!options.recursive

// default to true for now
options.clobber = 'clobber' in options ? !!options.clobber : true
// overwrite falls back to clobber
options.overwrite = 'overwrite' in options ? !!options.overwrite : options.clobber
options.dereference = 'dereference' in options ? !!options.dereference : false
options.preserveTimestamps = 'preserveTimestamps' in options ? !!options.preserveTimestamps : false

options.filter = options.filter || function () { return true }

// Warn about using preserveTimestamps on 32-bit node:
Expand All @@ -28,34 +26,88 @@ function copySync (src, dest, options) {
see https://github.com/jprichardson/node-fs-extra/issues/269`)
}

const stats = (options.recursive && !options.dereference) ? fs.lstatSync(src) : fs.statSync(src)
const destFolder = path.dirname(dest)
const destFolderExists = fs.existsSync(destFolder)
let performCopy = false

if (options.filter instanceof RegExp) {
console.warn('Warning: fs-extra: Passing a RegExp filter is deprecated, use a function')
performCopy = options.filter.test(src)
} else if (typeof options.filter === 'function') performCopy = options.filter(src, dest)

if (stats.isFile() && performCopy) {
if (!destFolderExists) mkdir.mkdirsSync(destFolder)
copyFileSync(src, dest, {
overwrite: options.overwrite,
errorOnExist: options.errorOnExist,
preserveTimestamps: options.preserveTimestamps
})
} else if (stats.isDirectory() && performCopy) {
if (!fs.existsSync(dest)) mkdir.mkdirsSync(dest)
const contents = fs.readdirSync(src)
contents.forEach(content => {
const opts = options
opts.recursive = true
copySync(path.join(src, content), path.join(dest, content), opts)
})
} else if (options.recursive && stats.isSymbolicLink() && performCopy) {
const srcPath = fs.readlinkSync(src)
fs.symlinkSync(srcPath, dest)
const stats = !options.dereference ? fs.lstatSync(src) : fs.statSync(src)

if (stats.isDirectory()) {
if (options.filter) return filterDir()
return onDir()
} else if (stats.isFile() || stats.isCharacterDevice() || stats.isBlockDevice()) {
if (options.filter) return filterFile()
return onFile()
} else if (stats.isSymbolicLink()) {
return onLink()
}

function onDir () {
mkdirpSync(path.dirname(dest))
fs.readdirSync(src).forEach(item => copySync(path.join(src, item), path.join(dest, item), options))
}

function onFile () {
mkdirpSync(path.dirname(dest))
return copyFileSync()
}

function onLink () {
mkdirpSync(path.dirname(dest))
return fs.symlinkSync(fs.readlinkSync(src), dest)
}

function filterDir () {
if (options.filter instanceof RegExp) {
console.warn('Warning: fs-extra: Passing a RegExp filter is deprecated, use a function')
if (!options.filter.test(src)) return readFailedDir()
return onDir()
} else if (typeof options.filter === 'function') {
if (!options.filter(src, dest)) return readFailedDir()
return onDir()
}

function readFailedDir () {
fs.readdirSync(src).forEach(item => copySync(path.join(src, item), path.join(dest, item), options))
}
}

function filterFile () {
if (options.filter instanceof RegExp) {
if (!options.filter(src)) return
return onFile()
} else if (typeof options.filter === 'function') {
if (!options.filter(src, dest)) return
return onFile()
}
}

function copyFileSync () {
const BUF_LENGTH = 64 * 1024
const _buff = buffer(BUF_LENGTH)

if (fs.existsSync(dest)) {
if (options.overwrite) {
fs.unlinkSync(dest)
} else if (options.errorOnExist) {
throw new Error(`${dest} already exists`)
} else return
}

const fdr = fs.openSync(src, 'r')
const stat = fs.fstatSync(fdr)
const fdw = fs.openSync(dest, 'w', stat.mode)
let bytesRead = 1
let pos = 0

while (bytesRead > 0) {
bytesRead = fs.readSync(fdr, _buff, 0, BUF_LENGTH, pos)
fs.writeSync(fdw, _buff, 0, bytesRead)
pos += bytesRead
}

if (options.preserveTimestamps) {
fs.futimesSync(fdw, stat.atime, stat.mtime)
}

fs.closeSync(fdr)
fs.closeSync(fdw)
}
}

Expand Down
1 change: 0 additions & 1 deletion lib/move-sync/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@ function moveSync (src, dest, options) {
} catch (err) {
if (err.code === 'ENOTEMPTY' || err.code === 'EEXIST' || err.code === 'EPERM') {
removeSync(dest)
options.overwrite = false // just overwriteed it, no need to do it again
return moveSync(src, dest, options)
}

Expand Down