DXR is a code search and navigation tool aimed at making sense of large projects. It supports full-text and regex searches as well as structural queries.

Git (975a35c0f5)

VCS Links

Line Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156
'use strict';

var utils = require('./utils');
var config = require('./config/build-config.json');

function getTimestamp(dirPaths) {
  let timestamp = {};

  dirPaths.forEach(function(dirPath) {
    timestamp[dirPath] = {};
    let dir = utils.getFile(dirPath);
    if (dir.exists() && dir.isDirectory()) {
      utils.ls(dir, true).filter(isFileWatched).forEach(function(file) {
        try {
          let relativePath = utils.relativePath(dir.path, file.path);
          timestamp[dirPath][relativePath] = file.lastModifiedTime;
        } catch(e) {
          timestamp = Date.now();
        }
      });
    }
  });
  return timestamp;
}

function isFileWatched(file) {
  let path = file.path;
  let ignores = [];
  let result = true;

  // Ignore all hidden files (ex: .filename)
  if (/^\.\S+|\/\.\S+$/.test(path)) {
    return false;
  }

  config.rebuildBlacklist.forEach(function(pattern) {
    ignores.push(pattern);
  });

  ignores.forEach(function(pattern) {
    if (path.indexOf(pattern) !== -1) {
      result = false;
      return;
    }
  });
  return result;
}

function dirChanged(previous, current, dir) {
  for (let filepath in current) {
    if (!previous[filepath] || current[filepath] > previous[filepath]) {
      utils.log('rebuild', 'file has been changed: ' + dir + '/' + filepath);
      return true;
    }
  }
  return false;
}

function buildConfigChanged(previous, current) {
  if (current.REBUILD == 1) {
    utils.log('rebuild', 'rebuild forced by use of special env like' +
      'LOCALE_BASEDIR, GAIA_DISTRIBUTION_DIR or REBUILD');
    return true;
  }

  let flags = [];

  // We don't detect FLAGS in blacklist because we don't have to rebuild again
  // if someone specifies them.
  let blacklist = ['REBUILD', 'P', 'VERBOSE'];

  for (let flag in current) {
    if (blacklist.indexOf(flag) === -1 && current[flag] !== previous[flag]) {
      flags.push(flag);
    }
  }

  if (flags.length > 0) {
    utils.log('rebuild', 'build config has been changed: ' + flags.join(', '));
  }

  return flags.length > 0;
}

exports.execute = function(options) {
  var scanningDirs = options.GAIA_APPDIRS.split(' ');
  var sharedPath = utils.getFile(options.GAIA_DIR, 'shared').path;
  scanningDirs.push(sharedPath);
  var current = getTimestamp(scanningDirs);
  var timestampFile = utils.getFile(options.STAGE_DIR, 'timestamp.json');
  var rebuildAppDirs = [];

  if (timestampFile.exists()) {
    let record = utils.getJSON(timestampFile);
    let previous = record.timestamp;
    let sharedChanged =
      dirChanged(previous[sharedPath] || {}, current[sharedPath], sharedPath);
    let configChanged =
      buildConfigChanged(record.build_config, options);
    let appsDir = utils.joinPath(options.PROFILE_DIR, 'apps');
    let appsExist = utils.fileExists(appsDir);

    // Rebuild everything if any BUILD_CONFIG attribute / shared file changed or
    // PROFILE_DIR/apps does not exist
    if (configChanged || sharedChanged || !appsExist) {
      rebuildAppDirs = scanningDirs;
    }
    // Rebuild any app that has any of its source file modified or external app
    else {
      for (let appDir in current) {
        if (dirChanged(previous[appDir] || {}, current[appDir], appDir)) {
          rebuildAppDirs.push(appDir);
        }
      }

      // Force rebuilding all apps with custom build.js file or unpakcage
      // external apps which are always named by random uuid
      // These uuid apps may clean up later in bug 1020259
      scanningDirs.forEach(function(appDir) {
        if (rebuildAppDirs.indexOf(appDir) !== -1 || appDir === sharedPath) {
          return;
        }
        var buildFile = utils.getFile(appDir, 'build', 'build.js');
        var webapp = utils.getWebapp(appDir, options);
        if (!webapp) {
          // Some leftover folders may still be in source tree,
          // without any valid app, like apps/browser that has been removed.
          return;
        }

        if (buildFile.exists() ||
            (utils.isExternalApp(webapp) && !webapp.pckManifest) ||
            !utils.fileExists(webapp.profileDirectoryFilePath)) {
          rebuildAppDirs.push(appDir);
        }
      });
    }
  } else {
    rebuildAppDirs = scanningDirs;
  }

  utils.writeContent(timestampFile, JSON.stringify({
    build_config: options,
    timestamp: current
  }, null, 2));

  if (options.VERBOSE === '1') {
    utils.log('rebuild', 'rebuildAppDirs: ' + JSON.stringify(rebuildAppDirs));
  }
  return rebuildAppDirs;
};

exports.getTimestamp = getTimestamp;
exports.isFileWatched = isFileWatched;
exports.dirChanged = dirChanged;
exports.buildConfigChanged = buildConfigChanged;