Skip to content

Commit

Permalink
add fs option, update benchmark
Browse files Browse the repository at this point in the history
  • Loading branch information
manidlou committed Apr 29, 2018
1 parent 2070729 commit ac99fb4
Show file tree
Hide file tree
Showing 8 changed files with 322 additions and 73 deletions.
1 change: 1 addition & 0 deletions .gitignore
@@ -1,2 +1,3 @@
node_modules/
benchmark/klaw-sync-benchmark-fixtures/
npm-debug.log
9 changes: 6 additions & 3 deletions .travis.yml
@@ -1,8 +1,11 @@
sudo: false
language: node_js
os:
- linux
- osx
node_js:
- '4'
- '6'
- '8'
- 6
- 8
- 10
script:
- npm test
3 changes: 2 additions & 1 deletion appveyor.yml
Expand Up @@ -2,8 +2,9 @@
environment:
matrix:
# node.js
- nodejs_version: "4"
- nodejs_version: "6"
- nodejs_version: "8"
- nodejs_version: "10"

# Install scripts. (runs after repo cloning)
install:
Expand Down
49 changes: 32 additions & 17 deletions benchmark/bm.js
@@ -1,18 +1,31 @@
'use strict'
const fs = require('fs-extra')
const path = require('path')
const mkp = require('mkp')
const argv = require('minimist')(process.argv.slice(2))
const Benchmark = require('benchmark')
const walkSync = require('walk-sync')
const globSync = require('glob').sync
const klawSync = require('../klaw-sync.js')

function help () {
console.log(`Usage examples:\n`)
console.log(`npm run benchmark -- --dir=<rootdir>`)
console.log(`npm run benchmark -- --dir=<rootdir> --nodir=true (ignore all directories)`)
const testDir = path.join(__dirname, 'klaw-sync-benchmark-fixtures')
const paths = [
{dirs: `${testDir}/{0..9}/{0..9}`, files: `${testDir}/{0..9}/{0..9}/{0..9}.txt`}, // 1000 files
{dirs: `${testDir}/{0..9}/{0..9}/{0..9}`, files: `${testDir}/{0..9}/{0..9}/{0..9}/{0..9}.txt`}, // 10,000
{dirs: `${testDir}/{0..9}/{0..9}/{0..9}/{0..9}`, files: `${testDir}/{0..9}/{0..9}/{0..9}/{0..9}/{0..9}.txt`} // 100,000
]

function tearDown () {
fs.removeSync(testDir)
}

function setup (p) {
tearDown()
mkp.sync(p.dirs)
mkp.sync(p.files)
}

function runBm (root, opts) {
function run (root, opts) {
if (!opts) {
const suite = Benchmark.Suite()
suite.add('walk-sync', function () {
Expand Down Expand Up @@ -48,6 +61,7 @@ function runBm (root, opts) {
}).add('klaw-sync', function () {
klawSync(root, {nodir: true})
}).on('error', function (er) {
tearDown()
return er
}).on('cycle', function (ev) {
console.log(String(ev.target))
Expand All @@ -57,18 +71,19 @@ function runBm (root, opts) {
}
}

if (!argv.dir) {
console.log('err: root dir cannot be null.')
help()
} else {
const dir = path.resolve(argv.dir)
console.log('Running benchmark tests..')
console.log('Running benchmark tests..')
paths.forEach(p => {
setup(p)
const items = klawSync(testDir)
if (argv.nodir) {
console.log(`root dir: ${dir}`)
console.log('option.nodir: true\n')
runBm(dir, {nodir: true})
const filesLen = items.filter(item => !item.stats.isDirectory()).length
console.log('\noption.nodir: true')
console.log(`root dir length: ${items.length}`)
console.log(`files: ${filesLen}\n`)
run(testDir, {nodir: true})
} else {
console.log(`root dir: ${dir}\n`)
runBm(dir)
console.log(`\nroot dir length: ${items.length}\n`)
run(testDir)
}
}
tearDown()
})
40 changes: 20 additions & 20 deletions klaw-sync.js
@@ -1,37 +1,37 @@
'use strict'

const fs = require('graceful-fs')
const path = require('path')

function klawSync (dir, opts) {
dir = path.resolve(dir)
opts = opts || {}
return walk(dir, opts, [])
}

function walk (dir, opts, ls) {
const paths = fs.readdirSync(dir).map(p => dir + path.sep + p)
function klawSync (dir, opts, ls) {
if (!ls) {
ls = []
dir = path.resolve(dir)
opts = opts || {}
opts.fs = opts.fs || fs
if (opts.depthLimit > -1) opts.rootDepth = dir.split(path.sep).length + 1
}
const paths = opts.fs.readdirSync(dir).map(p => dir + path.sep + p)
for (var i = 0; i < paths.length; i += 1) {
const pi = paths[i]
const st = fs.statSync(pi)
const st = opts.fs.statSync(pi)
const item = {path: pi, stats: st}
if (st.isDirectory()) {
if (!st.isDirectory() || (opts.rootDepth && pi.split(path.sep).length - opts.rootDepth >= opts.depthLimit)) {
if (opts.filter) {
if (opts.filter(item) && !opts.nofile) ls.push(item)
} else {
if (!opts.nofile) ls.push(item)
}
} else {
if (opts.filter) {
if (opts.filter(item) && !opts.nodir) {
ls.push(item)
ls = walk(pi, opts, ls)
ls = klawSync(pi, opts, ls)
} else {
if (!opts.noRecurseOnFailedFilter) ls = walk(pi, opts, ls)
if (!opts.noRecurseOnFailedFilter) ls = klawSync(pi, opts, ls)
}
} else {
if (!opts.nodir) ls.push(item)
ls = walk(pi, opts, ls)
}
} else {
if (opts.filter) {
if (opts.filter(item) && !opts.nofile) ls.push(item)
} else {
if (!opts.nofile) ls.push(item)
ls = klawSync(pi, opts, ls)
}
}
}
Expand Down
2 changes: 2 additions & 0 deletions package.json
Expand Up @@ -28,7 +28,9 @@
"benchmark": "^2.1.4",
"fs-extra": "^1.0.0",
"glob": "^7.1.2",
"memory-fs": "^0.4.1",
"minimist": "^1.2.0",
"mkp": "^1.0.1",
"mocha": "^3.5.0",
"standard": "^8.6.0",
"walk-sync": "^0.3.2"
Expand Down
162 changes: 162 additions & 0 deletions test/klaw-sync-customfs.test.js
@@ -0,0 +1,162 @@
'use strict'
const assert = require('assert')
const path = require('path')
const klawSync = require('../klaw-sync.js')
const Memoryfs = require('memory-fs')
const cfs = new Memoryfs()

describe('klaw-sync / custom fs', () => {
const dirnames = ['dir1', 'dir2', 'dir2/dir2_1', 'dir2/dir2_1/dir2_1_1']
const filenames = ['dir1/file1_2', 'dir2/dir2_1/file2_1_1', 'file1']
const TEST_DIR = '/klaw-sync-test-custom-fs'
cfs.mkdirpSync(TEST_DIR)
let DIRS, FILES

beforeEach(() => {
cfs.rmdirSync(TEST_DIR)
cfs.mkdirpSync(TEST_DIR)
DIRS = dirnames.map(dir => path.join(TEST_DIR, dir))
FILES = filenames.map(f => path.join(TEST_DIR, f))
DIRS.forEach(dir => cfs.mkdirpSync(dir))
FILES.forEach((f, i) => cfs.writeFileSync(f, i.toString()))
})

it('should return all items of a dir containing path and stats object', () => {
const paths = [
{path: DIRS[0], stats: cfs.statSync(DIRS[0])},
{path: FILES[0], stats: cfs.statSync(FILES[0])},
{path: DIRS[1], stats: cfs.statSync(DIRS[1])},
{path: DIRS[2], stats: cfs.statSync(DIRS[2])},
{path: DIRS[3], stats: cfs.statSync(DIRS[3])},
{path: FILES[1], stats: cfs.statSync(FILES[1])},
{path: FILES[2], stats: cfs.statSync(FILES[2])}
]
const items = klawSync(TEST_DIR, {fs: cfs})
assert.strictEqual(items.length, paths.length)
items.forEach((p, i) => {
assert.deepStrictEqual(p, paths[i])
assert.strictEqual(p.path, paths[i].path)
assert.deepStrictEqual(p.stats, paths[i].stats)
})
})

it('should return only files if opts.nodir is true', () => {
const filesOnly = [
{path: FILES[0], stats: cfs.statSync(FILES[0])},
{path: FILES[1], stats: cfs.statSync(FILES[1])},
{path: FILES[2], stats: cfs.statSync(FILES[2])}
]
const files = klawSync(TEST_DIR, {nodir: true, fs: cfs})
assert.strictEqual(files.length, filesOnly.length)
files.forEach((f, i) => {
assert.deepStrictEqual(f, filesOnly[i])
assert.strictEqual(f.path, filesOnly[i].path)
assert.deepStrictEqual(f.stats, filesOnly[i].stats)
})
})

it('should return only dirs if opts.nofile is true', () => {
const dirsOnly = [
{path: DIRS[0], stats: cfs.statSync(DIRS[0])},
{path: DIRS[1], stats: cfs.statSync(DIRS[1])},
{path: DIRS[2], stats: cfs.statSync(DIRS[2])},
{path: DIRS[3], stats: cfs.statSync(DIRS[3])}
]
const dirs = klawSync(TEST_DIR, {nofile: true, fs: cfs})
assert.strictEqual(dirs.length, dirsOnly.length)
dirs.forEach((dir, i) => {
assert.deepStrictEqual(dir, dirsOnly[i])
assert.strictEqual(dir.path, dirsOnly[i].path)
assert.deepStrictEqual(dir.stats, dirsOnly[i].stats)
})
})

describe('when opts.filter is true', () => {
it('should filter based on path', () => {
const f1 = path.join(TEST_DIR, 'dir1', 'foo.js')
const f2 = path.join(TEST_DIR, 'dir2', 'dir2_1', 'bar.js')
cfs.writeFileSync(f1, 'f1 file')
cfs.writeFileSync(f2, 'f2 file')
const paths = [
{path: f1, stats: cfs.statSync(f1)},
{path: f2, stats: cfs.statSync(f2)}
]
const filterFunc = i => path.extname(i.path) === '.js'
const items = klawSync(TEST_DIR, {filter: filterFunc, fs: cfs})
assert.strictEqual(items.length, paths.length)
items.forEach((p, i) => {
assert.deepStrictEqual(p, paths[i])
assert.strictEqual(p.path, paths[i].path)
assert.deepStrictEqual(p.stats, paths[i].stats)
})
})

it('should filter but not recurse if noRecurseOnFailedFilter is true', () => {
const dirToIgnore1 = path.join(TEST_DIR, 'node_modules')
const dirToIgnore2 = path.join(dirToIgnore1, 'somepkg')
cfs.mkdirpSync(dirToIgnore2)
const paths = [
{path: DIRS[0], stats: cfs.statSync(DIRS[0])},
{path: FILES[0], stats: cfs.statSync(FILES[0])},
{path: DIRS[1], stats: cfs.statSync(DIRS[1])},
{path: DIRS[2], stats: cfs.statSync(DIRS[2])},
{path: DIRS[3], stats: cfs.statSync(DIRS[3])},
{path: FILES[1], stats: cfs.statSync(FILES[1])},
{path: FILES[2], stats: cfs.statSync(FILES[2])}
]
const filterFunc = i => i.path.indexOf('node_modules') < 0
const items = klawSync(TEST_DIR, {filter: filterFunc, noRecurseOnFailedFilter: true, fs: cfs})
assert.strictEqual(items.length, paths.length)
items.forEach((p, i) => {
assert.deepStrictEqual(p, paths[i])
assert.strictEqual(p.path, paths[i].path)
assert.deepStrictEqual(p.stats, paths[i].stats)
})
})

it('should filter when it is used to ignore items', () => {
const dirToIgnore1 = path.join(TEST_DIR, 'node_modules')
const dirToIgnore2 = path.join(TEST_DIR, '.git')
cfs.mkdirpSync(dirToIgnore1)
cfs.mkdirpSync(dirToIgnore2)
const paths = [
{path: DIRS[0], stats: cfs.statSync(DIRS[0])},
{path: FILES[0], stats: cfs.statSync(FILES[0])},
{path: DIRS[1], stats: cfs.statSync(DIRS[1])},
{path: DIRS[2], stats: cfs.statSync(DIRS[2])},
{path: DIRS[3], stats: cfs.statSync(DIRS[3])},
{path: FILES[1], stats: cfs.statSync(FILES[1])},
{path: FILES[2], stats: cfs.statSync(FILES[2])}
]
const filterFunc = i => i.path.indexOf('node_modules') < 0 && i.path.indexOf('.git') < 0
const items = klawSync(TEST_DIR, {filter: filterFunc, noRecurseOnFailedFilter: true, fs: cfs})
assert.strictEqual(items.length, paths.length)
items.forEach((p, i) => {
assert.deepStrictEqual(p, paths[i])
assert.strictEqual(p.path, paths[i].path)
assert.deepStrictEqual(p.stats, paths[i].stats)
})
})

it('should filter and apply opts.nofile', () => {
const f = path.join(TEST_DIR, 'foo.js')
const d1 = path.join(TEST_DIR, 'foo')
const d2 = path.join(TEST_DIR, 'foobar')
cfs.writeFileSync(f, 'file contents')
cfs.mkdirpSync(d1)
cfs.mkdirpSync(d2)
const paths = [
{path: d1, stats: cfs.statSync(d1)},
{path: d2, stats: cfs.statSync(d2)}
]
const filterFunc = i => i.path.indexOf('foo') > 0
const items = klawSync(TEST_DIR, {filter: filterFunc, nofile: true, fs: cfs})
assert.strictEqual(items.length, paths.length)
items.forEach((p, i) => {
assert.deepStrictEqual(p, paths[i])
assert.strictEqual(p.path, paths[i].path)
assert.deepStrictEqual(p.stats, paths[i].stats)
})
})
})
})

0 comments on commit ac99fb4

Please sign in to comment.