Newer
Older
CVSS_3.0_GUI / node_modules / nwjs-builder-phoenix / node_modules / dir-compare / compareSync.js
root on 7 May 2019 7 KB Initial commit
var fs = require('fs');
var pathUtils = require('path');
var common = require('./common');

/**
 * Returns the sorted list of entries in a directory.
 */
var getEntries = function (path, options) {
    if (!path) {
        return [];
    } else {
        var statPath = fs.statSync(path);
        if (statPath.isDirectory()) {
           var entries = fs.readdirSync(path);

           var res = [];
           entries.forEach(function (entryName) {
               var entryPath = path + '/' + entryName;
               var lstatEntry = fs.lstatSync(entryPath);
               var isSymlink = lstatEntry.isSymbolicLink();
               var statEntry;
               if(options.skipSymlinks && isSymlink){
                   statEntry = undefined;
               } else{
                   statEntry = fs.statSync(entryPath);
               }
               var entry = {
                   name : entryName,
                   path : entryPath,
                   stat : statEntry,
                   lstat : lstatEntry,
                   symlink : isSymlink,
                   toString : function () {
                       return this.name;
                   }
               };
               if (common.filterEntry(entry, options)){
                   res.push(entry);
               }
           });
           return options.ignoreCase?res.sort(common.compareEntryIgnoreCase):res.sort(common.compareEntryCaseSensitive);
       } else {
           var name = pathUtils.basename(path);
           return [
               {
                   name : name,
                   path : path,
                   stat : statPath,
                   toString : function () {
                       return this.name;
                   }
               }

           ];
       }
    }
}

/**
 * Compares two directories synchronously.
 */
var compare = function (rootEntry1, rootEntry2, level, relativePath, options, statistics, diffSet, symlinkCache) {
    symlinkCache = symlinkCache || {
        dir1 : {},
        dir2 : {}
    };
    var loopDetected1 = common.detectLoop(rootEntry1, symlinkCache.dir1);
    var loopDetected2 = common.detectLoop(rootEntry2, symlinkCache.dir2);

    var symlinkCachePath1, symlinkCachePath2;
    if(rootEntry1 && !loopDetected1){
        symlinkCachePath1 = pathUtils.normalize(pathUtils.resolve(rootEntry1.symlink?fs.realpathSync(rootEntry1.path):rootEntry1.path)).toLowerCase();
        symlinkCache.dir1[symlinkCachePath1] = true;
    }
    if(rootEntry2 && !loopDetected2){
        symlinkCachePath2 = pathUtils.normalize(pathUtils.resolve(rootEntry2.symlink?fs.realpathSync(rootEntry2.path):rootEntry2.path)).toLowerCase();
        symlinkCache.dir2[symlinkCachePath2] = true;
    }
    var path1 = rootEntry1?rootEntry1.path:undefined;
    var path2 = rootEntry2?rootEntry2.path:undefined;
    var entries1 = loopDetected1?[]:getEntries(path1, options);
    var entries2 = loopDetected2?[]:getEntries(path2, options);
    var i1 = 0, i2 = 0;
    while (i1 < entries1.length || i2 < entries2.length) {
        var entry1 = entries1[i1];
        var entry2 = entries2[i2];
        var n1 = entry1 ? entry1.name : undefined;
        var n2 = entry2 ? entry2.name : undefined;
        var p1 = entry1 ? entry1.path : undefined;
        var p2 = entry2 ? entry2.path : undefined;
        var fileStat1 = entry1 ? entry1.stat : undefined;
        var fileStat2 = entry2 ? entry2.stat : undefined;
        var type1, type2;

        // compare entry name (-1, 0, 1)
        var cmp;
        if (i1 < entries1.length && i2 < entries2.length) {
            cmp = options.ignoreCase?common.compareEntryIgnoreCase(entry1, entry2):common.compareEntryCaseSensitive(entry1, entry2);
            type1 = common.getType(fileStat1);
            type2 = common.getType(fileStat2);
        } else if (i1 < entries1.length) {
            type1 = common.getType(fileStat1);
            type2 = common.getType(undefined);
            cmp = -1;
        } else {
            type1 = common.getType(undefined);
            type2 = common.getType(fileStat2);
            cmp = 1;
        }

        // process entry
        if (cmp === 0) {
            // Both left/right exist and have the same name
            if (type1 === type2) {
                var same;
                if(type1==='file'){
                    if (options.compareSize && fileStat1.size !== fileStat2.size) {
                        same = false;
                    } else if(options.compareDate && !common.sameDate(fileStat1.mtime, fileStat2.mtime, options.dateTolerance)){
                        same = false;
                    } else if(options.compareContent){
                        same = options.compareFileSync(p1, fileStat1, p2, fileStat2, options);
                    } else{
                        same = true;
                    }
                } else{
                    same = true;
                }
                if(!options.noDiffSet){
                    options.resultBuilder(entry1, entry2, same ? 'equal' : 'distinct', level, relativePath, options, statistics, diffSet);
                }
                same ? statistics.equal++ : statistics.distinct++;
                if(type1==='file'){
                    same ? statistics.equalFiles++ : statistics.distinctFiles++;
                } else{
                    same ? statistics.equalDirs++ : statistics.distinctDirs++;
                }
            } else {
                // File and directory with same name
                if(!options.noDiffSet){
                    options.resultBuilder(entry1, entry2, 'distinct', level, relativePath, options, statistics, diffSet);
                }
                statistics.distinct+=2;
                statistics.distinctFiles++;
                statistics.distinctDirs++;
            }
            i1++;
            i2++;
            if(!options.skipSubdirs){
                if (type1 === 'directory' && type2 === 'directory') {
                    compare(entry1, entry2, level + 1, relativePath + '/' + entry1.name, options, statistics, diffSet, common.cloneSymlinkCache(symlinkCache));
                } else if (type1 === 'directory') {
                    compare(entry1, undefined, level + 1, relativePath + '/' + entry1.name, options, statistics, diffSet, common.cloneSymlinkCache(symlinkCache));
                } else if (type2 === 'directory') {
                    compare(undefined, entry2, level + 1, relativePath + '/' + entry2.name, options, statistics, diffSet, common.cloneSymlinkCache(symlinkCache));
                }
            }
        } else if (cmp < 0) {
            // Right missing
            if(!options.noDiffSet){
                options.resultBuilder(entry1, undefined, 'left', level, relativePath, options, statistics, diffSet);
            }
            statistics.left++;
            if(type1==='file'){
                statistics.leftFiles++;
            } else{
                statistics.leftDirs++;
            }
            i1++;
            if (type1 === 'directory' && !options.skipSubdirs) {
                compare(entry1, undefined, level + 1, relativePath + '/' + entry1.name, options, statistics, diffSet, common.cloneSymlinkCache(symlinkCache));
            }
        } else {
            // Left missing
            if(!options.noDiffSet){
                options.resultBuilder(undefined, entry2, 'right', level, relativePath, options, statistics, diffSet);
            }
            statistics.right++;
            if(type2==='file'){
                statistics.rightFiles++;
            } else{
                statistics.rightDirs++;
            }
            i2++;
            if (type2 === 'directory' && !options.skipSubdirs) {
                compare(undefined, entry2, level + 1, relativePath + '/' + entry2.name, options, statistics, diffSet, common.cloneSymlinkCache(symlinkCache));
            }
        }
    }
};

module.exports = compare;