summaryrefslogtreecommitdiff
path: root/node_modules/dir-compare/src/fileCompareHandler
diff options
context:
space:
mode:
Diffstat (limited to 'node_modules/dir-compare/src/fileCompareHandler')
-rw-r--r--node_modules/dir-compare/src/fileCompareHandler/closeFile.js28
-rw-r--r--node_modules/dir-compare/src/fileCompareHandler/defaultFileCompare.js113
-rw-r--r--node_modules/dir-compare/src/fileCompareHandler/lineBasedFileCompare.js196
3 files changed, 337 insertions, 0 deletions
diff --git a/node_modules/dir-compare/src/fileCompareHandler/closeFile.js b/node_modules/dir-compare/src/fileCompareHandler/closeFile.js
new file mode 100644
index 0000000..10118e1
--- /dev/null
+++ b/node_modules/dir-compare/src/fileCompareHandler/closeFile.js
@@ -0,0 +1,28 @@
+var fs = require('fs')
+
+var closeFilesSync = function (fd1, fd2) {
+ if (fd1) {
+ fs.closeSync(fd1)
+ }
+ if (fd2) {
+ fs.closeSync(fd2)
+ }
+}
+
+var closeFilesAsync = function (fd1, fd2, fdQueue) {
+ if (fd1 && fd2) {
+ return fdQueue.promises.close(fd1).then(() => fdQueue.promises.close(fd2))
+ }
+ if (fd1) {
+ return fdQueue.promises.close(fd1)
+ }
+ if (fd2) {
+ return fdQueue.promises.close(fd2)
+ }
+}
+
+
+module.exports = {
+ closeFilesSync: closeFilesSync,
+ closeFilesAsync: closeFilesAsync
+}
diff --git a/node_modules/dir-compare/src/fileCompareHandler/defaultFileCompare.js b/node_modules/dir-compare/src/fileCompareHandler/defaultFileCompare.js
new file mode 100644
index 0000000..26188ca
--- /dev/null
+++ b/node_modules/dir-compare/src/fileCompareHandler/defaultFileCompare.js
@@ -0,0 +1,113 @@
+var fs = require('fs')
+var bufferEqual = require('buffer-equal')
+var FileDescriptorQueue = require('../fs/FileDescriptorQueue')
+var closeFilesSync = require('./closeFile').closeFilesSync
+var closeFilesAsync = require('./closeFile').closeFilesAsync
+var fsPromise = require('../fs/fsPromise')
+var BufferPool = require('../fs/BufferPool')
+
+var MAX_CONCURRENT_FILE_COMPARE = 8
+var BUF_SIZE = 100000
+var fdQueue = new FileDescriptorQueue(MAX_CONCURRENT_FILE_COMPARE * 2)
+var bufferPool = new BufferPool(BUF_SIZE, MAX_CONCURRENT_FILE_COMPARE); // fdQueue guarantees there will be no more than MAX_CONCURRENT_FILE_COMPARE async processes accessing the buffers concurrently
+
+
+/**
+ * Compares two partial buffers.
+ */
+var compareBuffers = function (buf1, buf2, contentSize) {
+ return bufferEqual(buf1.slice(0, contentSize), buf2.slice(0, contentSize))
+}
+
+/**
+ * Compares two files by content.
+ */
+var compareSync = function (path1, stat1, path2, stat2, options) {
+ var fd1, fd2
+ if (stat1.size !== stat2.size) {
+ return false
+ }
+ var bufferPair = bufferPool.allocateBuffers()
+ try {
+ fd1 = fs.openSync(path1, 'r')
+ fd2 = fs.openSync(path2, 'r')
+ var buf1 = bufferPair.buf1
+ var buf2 = bufferPair.buf2
+ var progress = 0
+ while (true) {
+ var size1 = fs.readSync(fd1, buf1, 0, BUF_SIZE, null)
+ var size2 = fs.readSync(fd2, buf2, 0, BUF_SIZE, null)
+ if (size1 !== size2) {
+ return false
+ } else if (size1 === 0) {
+ // End of file reached
+ return true
+ } else if (!compareBuffers(buf1, buf2, size1)) {
+ return false
+ }
+ }
+ } finally {
+ closeFilesSync(fd1, fd2)
+ bufferPool.freeBuffers(bufferPair)
+ }
+}
+
+
+/**
+ * Compares two files by content
+ */
+var compareAsync = function (path1, stat1, path2, stat2, options) {
+ var fd1, fd2
+ var bufferPair
+ if (stat1.size !== stat2.size) {
+ return Promise.resolve(false)
+ }
+ return Promise.all([fdQueue.promises.open(path1, 'r'), fdQueue.promises.open(path2, 'r')])
+ .then(function (fds) {
+ bufferPair = bufferPool.allocateBuffers()
+ fd1 = fds[0]
+ fd2 = fds[1]
+ var buf1 = bufferPair.buf1
+ var buf2 = bufferPair.buf2
+ var progress = 0
+ var compareAsyncInternal = function () {
+ return Promise.all([
+ fsPromise.read(fd1, buf1, 0, BUF_SIZE, null),
+ fsPromise.read(fd2, buf2, 0, BUF_SIZE, null)
+ ]).then(function (bufferSizes) {
+ var size1 = bufferSizes[0]
+ var size2 = bufferSizes[1]
+ if (size1 !== size2) {
+ return false
+ } else if (size1 === 0) {
+ // End of file reached
+ return true
+ } else if (!compareBuffers(buf1, buf2, size1)) {
+ return false
+ } else {
+ return compareAsyncInternal()
+ }
+ })
+ }
+ return compareAsyncInternal()
+ })
+ .then(
+ // 'finally' polyfill for node 8 and below
+ function (res) {
+ return finalizeAsync(fd1, fd2, bufferPair).then(() => res)
+ },
+ function (err) {
+ return finalizeAsync(fd1, fd2, bufferPair).then(() => { throw err; })
+ }
+ )
+}
+
+function finalizeAsync(fd1, fd2, bufferPair) {
+ bufferPool.freeBuffers(bufferPair)
+ return closeFilesAsync(fd1, fd2, fdQueue)
+}
+
+module.exports = {
+ compareSync: compareSync,
+ compareAsync: compareAsync
+}
diff --git a/node_modules/dir-compare/src/fileCompareHandler/lineBasedFileCompare.js b/node_modules/dir-compare/src/fileCompareHandler/lineBasedFileCompare.js
new file mode 100644
index 0000000..c2de4b2
--- /dev/null
+++ b/node_modules/dir-compare/src/fileCompareHandler/lineBasedFileCompare.js
@@ -0,0 +1,196 @@
+/**
+ * Compare files line by line with options to ignore
+ * line endings and white space differencies.
+ */
+var fs = require('fs')
+var FileDescriptorQueue = require('../fs/FileDescriptorQueue')
+var closeFilesSync = require('./closeFile').closeFilesSync
+var closeFilesAsync = require('./closeFile').closeFilesAsync
+var fsPromise = require('../fs/fsPromise')
+var BufferPool = require('../fs/BufferPool')
+
+const LINE_TOKENIZER_REGEXP = /[^\n]+\n?|\n/g
+const TRIM_LINE_ENDING_REGEXP = /\r\n$/g
+const SPLIT_CONTENT_AND_LINE_ENDING_REGEXP = /([^\r\n]*)([\r\n]*)/
+const TRIM_WHITE_SPACES_REGEXP = /^[ \f\t\v\u00a0\u1680\u2000-\u200a\u2028\u2029\u202f\u205f\u3000\ufeff]+|[ \f\t\v\u00a0\u1680\u2000-\u200a\u2028\u2029\u202f\u205f\u3000\ufeff]+$/g
+
+var MAX_CONCURRENT_FILE_COMPARE = 8
+var BUF_SIZE = 100000
+var fdQueue = new FileDescriptorQueue(MAX_CONCURRENT_FILE_COMPARE * 2)
+var bufferPool = new BufferPool(BUF_SIZE, MAX_CONCURRENT_FILE_COMPARE); // fdQueue guarantees there will be no more than MAX_CONCURRENT_FILE_COMPARE async processes accessing the buffers concurrently
+
+function compareSync(path1, stat1, path2, stat2, options) {
+ var fd1, fd2
+ var bufferPair = bufferPool.allocateBuffers()
+ var bufferSize = options.lineBasedHandlerBufferSize || BUF_SIZE
+ try {
+ fd1 = fs.openSync(path1, 'r')
+ fd2 = fs.openSync(path2, 'r')
+ var buf1 = bufferPair.buf1
+ var buf2 = bufferPair.buf2
+ var nextPosition1 = 0, nextPosition2 = 0
+ while (true) {
+ var lines1 = readLinesSync(fd1, buf1, bufferSize, nextPosition1)
+ var lines2 = readLinesSync(fd2, buf2, bufferSize, nextPosition2)
+ if (lines1.length === 0 && lines2.length === 0) {
+ // End of file reached
+ return true
+ }
+ var equalLines = compareLines(lines1, lines2, options)
+ if (equalLines === 0) {
+ return false
+ }
+ nextPosition1 += calculateSize(lines1, equalLines)
+ nextPosition2 += calculateSize(lines2, equalLines)
+ }
+ } finally {
+ closeFilesSync(fd1, fd2)
+ bufferPool.freeBuffers(bufferPair)
+ }
+}
+
+async function compareAsync(path1, stat1, path2, stat2, options) {
+ var fd1, fd2
+ var bufferSize = options.lineBasedHandlerBufferSize || BUF_SIZE
+ var bufferPair
+ try {
+ var fds = await Promise.all([fdQueue.promises.open(path1, 'r'), fdQueue.promises.open(path2, 'r')])
+ bufferPair = bufferPool.allocateBuffers()
+ fd1 = fds[0]
+ fd2 = fds[1]
+ var buf1 = bufferPair.buf1
+ var buf2 = bufferPair.buf2
+ var nextPosition1 = 0, nextPosition2 = 0
+ while (true) {
+ var lines1 = await readLinesAsync(fd1, buf1, bufferSize, nextPosition1)
+ var lines2 = await readLinesAsync(fd2, buf2, bufferSize, nextPosition2)
+ if (lines1.length === 0 && lines2.length === 0) {
+ // End of file reached
+ return true
+ }
+ var equalLines = compareLines(lines1, lines2, options)
+ if (equalLines === 0) {
+ return false
+ }
+ nextPosition1 += calculateSize(lines1, equalLines)
+ nextPosition2 += calculateSize(lines2, equalLines)
+ }
+ } finally {
+ bufferPool.freeBuffers(bufferPair)
+ await closeFilesAsync(fd1, fd2, fdQueue)
+ }
+}
+
+/**
+ * Read lines from file starting with nextPosition.
+ * Returns 0 lines if eof is reached, otherwise returns at least one complete line.
+ */
+function readLinesSync(fd, buf, bufferSize, nextPosition) {
+ var lines = []
+ var chunk = ""
+ while (true) {
+ var size = fs.readSync(fd, buf, 0, bufferSize, nextPosition)
+ if (size === 0) {
+ // end of file
+ normalizeLastFileLine(lines)
+ return lines
+ }
+ chunk += buf.toString('utf8', 0, size)
+ lines = chunk.match(LINE_TOKENIZER_REGEXP)
+ if (lines.length > 1) {
+ return removeLastIncompleteLine(lines)
+ }
+ nextPosition += size
+ }
+}
+
+/**
+ * Read lines from file starting with nextPosition.
+ * Returns 0 lines if eof is reached, otherwise returns at least one complete line.
+ */
+async function readLinesAsync(fd, buf, bufferSize, nextPosition) {
+ var lines = []
+ var chunk = ""
+ while (true) {
+ var size = await fsPromise.read(fd, buf, 0, bufferSize, nextPosition)
+ if (size === 0) {
+ // end of file
+ normalizeLastFileLine(lines)
+ return lines
+ }
+ chunk += buf.toString('utf8', 0, size)
+ lines = chunk.match(LINE_TOKENIZER_REGEXP)
+ if (lines.length > 1) {
+ return removeLastIncompleteLine(lines)
+ }
+ nextPosition += size
+ }
+}
+
+function removeLastIncompleteLine(lines) {
+ const lastLine = lines[lines.length - 1]
+ if (!lastLine.endsWith('\n')) {
+ return lines.slice(0, lines.length - 1)
+ }
+ return lines
+}
+
+function normalizeLastFileLine(lines) {
+ if (lines.length === 0) {
+ return
+ }
+ const lastLine = lines[lines.length - 1]
+ if (!lastLine.endsWith('\n')) {
+ lines[lines.length - 1] = lastLine + '\n'
+ }
+}
+
+function calculateSize(lines, numberOfLines) {
+ var size = 0
+ for (var i = 0; i < numberOfLines; i++) {
+ var line = lines[i]
+ size += line.length
+ }
+ return size
+}
+
+function compareLines(lines1, lines2, options) {
+ var equalLines = 0
+ var len = lines1.length < lines2.length ? lines1.length : lines2.length
+ for (var i = 0; i < len; i++) {
+ var line1 = lines1[i]
+ var line2 = lines2[i]
+ if (options.ignoreLineEnding) {
+ line1 = trimLineEnding(line1)
+ line2 = trimLineEnding(line2)
+ }
+ if (options.ignoreWhiteSpaces) {
+ line1 = trimSpaces(line1)
+ line2 = trimSpaces(line2)
+ }
+ if (line1 !== line2) {
+ return equalLines
+ }
+ equalLines++
+ }
+ return equalLines
+}
+
+// Trims string like ' abc \n' into 'abc\n'
+function trimSpaces(s) {
+ var matchResult = s.match(SPLIT_CONTENT_AND_LINE_ENDING_REGEXP);
+ var content = matchResult[1]
+ var lineEnding = matchResult[2]
+ var trimmed = content.replace(TRIM_WHITE_SPACES_REGEXP, '')
+ return trimmed + lineEnding
+}
+
+// Trims string like 'abc\r\n' into 'abc\n'
+function trimLineEnding(s) {
+ return s.replace(TRIM_LINE_ENDING_REGEXP, '\n')
+}
+
+module.exports = {
+ compareSync: compareSync,
+ compareAsync: compareAsync
+}