From db23fe697a9a3cd3bd9600ec2bdd990d0427ef8a Mon Sep 17 00:00:00 2001 From: Matt Simerson Date: Thu, 2 May 2024 13:53:58 -0700 Subject: [PATCH] feat: getDir is now recursive --- CHANGELOG.md | 5 ++++ lib/reader.js | 50 ++++++++++++++++++----------------- lib/watch.js | 3 ++- package.json | 2 +- test/config.js | 11 ++++---- test/config/dir/subdir/4.flat | 1 + test/reader.js | 25 +++++++++--------- 7 files changed, 53 insertions(+), 44 deletions(-) create mode 100644 test/config/dir/subdir/4.flat diff --git a/CHANGELOG.md b/CHANGELOG.md index 96c55ae..1f37c6a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,10 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/). ### Unreleased +### [1.3.0] - 2024-05-02 + +- feat: getDir is now recursive + ### [1.2.4] - 2024-04-26 - fix(watch): callback was losing context. Use explicit obj @@ -134,3 +138,4 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/). [1.2.1]: https://github.com/haraka/haraka-config/releases/tag/v1.2.1 [1.2.2]: https://github.com/haraka/haraka-config/releases/tag/v1.2.2 [1.2.4]: https://github.com/haraka/haraka-config/releases/tag/v1.2.4 +[1.3.0]: https://github.com/haraka/haraka-config/releases/tag/v1.3.0 \ No newline at end of file diff --git a/lib/reader.js b/lib/reader.js index 7b667b0..f70a982 100644 --- a/lib/reader.js +++ b/lib/reader.js @@ -137,30 +137,32 @@ class Reader { return result } - read_dir(name, opts = {}) { - return new Promise((resolve, reject) => { - this._read_args[name] = { opts } - - fsp - .stat(name) - .then((stat) => stat.isDirectory()) - .then(() => fsp.readdir(name)) - .then(async (fileList) => { - const contents = [] - for (const file of fileList) { - const type = opts.type ?? this.getType(file) - contents.push({ - path: file, - data: this.load_config(path.resolve(name, file), type, opts), - }) - } - return contents - }) - .then(resolve) - .catch(reject) - - if (opts.watchCb) watch.dir2(this, name) - }) + async read_dir(name, opts = {}) { + this._read_args[name] = { opts } + + const contents = [] + const dirs = [] + + const stat = await fsp.stat(name) + if (stat.isDirectory()) dirs.push(name) + + for (const dir of dirs) { + for (const entry of await fsp.readdir(dir)) { + const entryPath = path.join(dir, entry) + const stat = await fsp.stat(entryPath) + if (stat.isDirectory()) dirs.push(entryPath) // recursion + if (stat.isFile()) { + const type = opts.type ?? this.getType(entry) + contents.push({ + path: entryPath, + data: this.load_config(entryPath, type, opts), + }) + } + } + } + + if (opts.watchCb) watch.dir2(this, name) + return contents } get_filetype_reader(type) { diff --git a/lib/watch.js b/lib/watch.js index 6b764eb..061482a 100644 --- a/lib/watch.js +++ b/lib/watch.js @@ -89,7 +89,7 @@ Watch.dir2 = (reader, dirPath) => { const watchOpts = { persistent: false, recursive: true } // recursive is only supported on Windows (win32, win64) and macOS (darwin) - if (!/win/.test(process.platform)) watchOpts.recursive = false + if (!/win|darwin/.test(process.platform)) watchOpts.recursive = false watchers[dirPath] = fs.watch(dirPath, watchOpts, (fse, filename) => { // console.log(`event: ${fse}, ${filename}`); @@ -105,6 +105,7 @@ Watch.dir2 = (reader, dirPath) => { args.opts.watchCb() }, 2 * 1000) }) + watchers[dirPath].unref() } Watch.onEvent = (reader, name, args) => { diff --git a/package.json b/package.json index 410565c..ae4361d 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,7 @@ "name": "haraka-config", "license": "MIT", "description": "Haraka's config file loader", - "version": "1.2.4", + "version": "1.3.0", "homepage": "http://haraka.github.io", "repository": { "type": "git", diff --git a/test/config.js b/test/config.js index 36a2fc6..78fd342 100644 --- a/test/config.js +++ b/test/config.js @@ -467,7 +467,7 @@ describe('getDir', function () { if (err) console.error(err) assert.ifError(err) assert.equal(err, null) - assert.equal(files.length, 3) + assert.equal(files.length, 4) assert.equal(files[0].data, `contents1${os.EOL}`) assert.equal(files[2].data, `contents3${os.EOL}`) done() @@ -484,8 +484,8 @@ describe('getDir', function () { it('reloads when file in dir is touched', function (done) { this.timeout(3500) - // due to differences in fs.watch, this test is not reliable on Mac OS X - if (/darwin/.test(process.platform)) return done() + // due to differences in fs.watch, this test is unreliable on Mac OS X + // if (/darwin/.test(process.platform)) return done() let callCount = 0 @@ -496,9 +496,8 @@ describe('getDir', function () { if (err) console.error(err) callCount++ if (callCount === 1) { - // console.log(files); assert.equal(err, null) - assert.equal(files.length, 3) + assert.equal(files.length, 4) assert.equal(files[0].data, `contents1${os.EOL}`) assert.equal(files[2].data, `contents3${os.EOL}`) fs.writeFile(tmpFile, 'contents4\n', (err2) => { @@ -506,7 +505,7 @@ describe('getDir', function () { // console.log('file touched, waiting for callback'); }) } - if (callCount === 2) { + else if (callCount === 2) { assert.equal(files[3].data, 'contents4\n') fs.unlink(tmpFile, () => {}) done() diff --git a/test/config/dir/subdir/4.flat b/test/config/dir/subdir/4.flat new file mode 100644 index 0000000..50d8aae --- /dev/null +++ b/test/config/dir/subdir/4.flat @@ -0,0 +1 @@ +contents4 \ No newline at end of file diff --git a/test/reader.js b/test/reader.js index 308941d..bfeeab0 100644 --- a/test/reader.js +++ b/test/reader.js @@ -170,22 +170,23 @@ describe('reader', function () { describe('read_dir', function () { it('returns dir contents', async function () { - // may have race collission with config.getDir test - const result = await this.cfreader.read_dir( - path.resolve('test/config/dir'), - ) - assert.deepEqual(result, [ - { data: 'contents1', path: '1.ext' }, - { data: 'contents2', path: '2.ext' }, - { data: 'contents3', path: '3.ext' }, + const dir = path.resolve('test/config/dir') + assert.deepEqual(await this.cfreader.read_dir(dir), [ + { data: 'contents1', path: path.join(dir, '1.ext') }, + { data: 'contents2', path: path.join(dir, '2.ext') }, + { data: 'contents3', path: path.join(dir, '3.ext') }, + { data: 'contents4', path: path.join(dir, 'subdir', '4.flat') }, ]) }) it('returns dir with mixed types', async function () { - const result = await this.cfreader.read_dir('test/config/mixed') - assert.deepEqual(result, [ - { data: { main: {}, sect: { one: 'true' } }, path: '1.ini' }, - { data: { main: { two: false } }, path: '2.yml' }, + const dir = path.join('test', 'config', 'mixed') + assert.deepEqual(await this.cfreader.read_dir(dir), [ + { + data: { main: {}, sect: { one: 'true' } }, + path: path.join(dir, '1.ini'), + }, + { data: { main: { two: false } }, path: path.join(dir, '2.yml') }, ]) }) })