UNPKG

@ionic/app-scripts

Version:
279 lines (278 loc) 12.7 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); var fs_extra_1 = require("fs-extra"); var path_1 = require("path"); var logger_1 = require("./logger/logger"); var config_1 = require("./util/config"); var Constants = require("./util/constants"); var events_1 = require("./util/events"); var glob_util_1 = require("./util/glob-util"); var helpers_1 = require("./util/helpers"); var watch_1 = require("./watch"); var copyFilePathCache = new Map(); var FILTER_OUT_DIRS_FOR_CLEAN = ['{{WWW}}', '{{BUILD}}']; function copy(context, configFile) { configFile = config_1.getUserConfigFile(context, exports.taskInfo, configFile); var logger = new logger_1.Logger('copy'); return copyWorker(context, configFile) .then(function () { logger.finish(); }) .catch(function (err) { throw logger.fail(err); }); } exports.copy = copy; function copyWorker(context, configFile) { var copyConfig = config_1.fillConfigDefaults(configFile, exports.taskInfo.defaultConfigFile); var keys = Object.keys(copyConfig); var directoriesToCreate = new Set(); var toCopyList = []; return Promise.resolve().then(function () { // for each entry, make sure each glob in the list of globs has had string replacement performed on it cleanConfigContent(keys, copyConfig, context); return getFilesPathsForConfig(keys, copyConfig); }).then(function (resultMap) { // sweet, we have the absolute path of the files in the glob, and the ability to get the relative path // basically, we've got a stew goin' return populateFileAndDirectoryInfo(resultMap, copyConfig, toCopyList, directoriesToCreate); }).then(function () { if (helpers_1.getBooleanPropertyValue(Constants.ENV_CLEAN_BEFORE_COPY)) { cleanDirectories(context, directoriesToCreate); } }).then(function () { // create the directories synchronously to avoid any disk locking issues var directoryPathList = Array.from(directoriesToCreate); for (var _i = 0, directoryPathList_1 = directoryPathList; _i < directoryPathList_1.length; _i++) { var directoryPath = directoryPathList_1[_i]; fs_extra_1.mkdirpSync(directoryPath); } }).then(function () { // sweet, the directories are created, so now let's stream the files var promises = []; var _loop_1 = function (file) { cacheCopyData(file); var promise = helpers_1.copyFileAsync(file.absoluteSourcePath, file.absoluteDestPath); promise.then(function () { logger_1.Logger.debug("Successfully copied " + file.absoluteSourcePath + " to " + file.absoluteDestPath); }).catch(function (err) { logger_1.Logger.warn("Failed to copy " + file.absoluteSourcePath + " to " + file.absoluteDestPath); }); promises.push(promise); }; for (var _i = 0, toCopyList_1 = toCopyList; _i < toCopyList_1.length; _i++) { var file = toCopyList_1[_i]; _loop_1(file); } return Promise.all(promises); }); } exports.copyWorker = copyWorker; function copyUpdate(changedFiles, context) { var logger = new logger_1.Logger('copy update'); var configFile = config_1.getUserConfigFile(context, exports.taskInfo, null); var copyConfig = config_1.fillConfigDefaults(configFile, exports.taskInfo.defaultConfigFile); var keys = Object.keys(copyConfig); var directoriesToCreate = new Set(); var toCopyList = []; return Promise.resolve().then(function () { changedFiles.forEach(function (changedFile) { return logger_1.Logger.debug("copyUpdate, event: " + changedFile.event + ", path: " + changedFile.filePath); }); // for each entry, make sure each glob in the list of globs has had string replacement performed on it cleanConfigContent(keys, copyConfig, context); return getFilesPathsForConfig(keys, copyConfig); }).then(function (resultMap) { // sweet, we have the absolute path of the files in the glob, and the ability to get the relative path // basically, we've got a stew goin' return populateFileAndDirectoryInfo(resultMap, copyConfig, toCopyList, directoriesToCreate); }).then(function () { // first, process any deleted directories var promises = []; var directoryDeletions = changedFiles.filter(function (changedFile) { return changedFile.event === 'unlinkDir'; }); directoryDeletions.forEach(function (changedFile) { return promises.push(processRemoveDir(changedFile)); }); return Promise.all(promises); }).then(function () { // process any deleted files var promises = []; var fileDeletions = changedFiles.filter(function (changedFile) { return changedFile.event === 'unlink'; }); fileDeletions.forEach(function (changedFile) { return promises.push(processRemoveFile(changedFile)); }); return Promise.all(promises); }).then(function () { var promises = []; var additions = changedFiles.filter(function (changedFile) { return changedFile.event === 'change' || changedFile.event === 'add' || changedFile.event === 'addDir'; }); additions.forEach(function (changedFile) { var matchingItems = toCopyList.filter(function (toCopyEntry) { return toCopyEntry.absoluteSourcePath === changedFile.filePath; }); matchingItems.forEach(function (matchingItem) { // create the directories first (if needed) fs_extra_1.mkdirpSync(path_1.dirname(matchingItem.absoluteDestPath)); // cache the data and copy the files cacheCopyData(matchingItem); promises.push(helpers_1.copyFileAsync(matchingItem.absoluteSourcePath, matchingItem.absoluteDestPath)); events_1.emit(events_1.EventType.FileChange, additions); }); }); return Promise.all(promises); }).then(function () { logger.finish('green', true); logger_1.Logger.newLine(); }).catch(function (err) { throw logger.fail(err); }); } exports.copyUpdate = copyUpdate; function cleanDirectories(context, directoriesToCreate) { var filterOut = config_1.replacePathVars(context, FILTER_OUT_DIRS_FOR_CLEAN); var directoryPathList = Array.from(directoriesToCreate); // filter out any directories that we don't want to allow a clean on var cleanableDirectories = directoryPathList.filter(function (directoryPath) { for (var _i = 0, filterOut_1 = filterOut; _i < filterOut_1.length; _i++) { var uncleanableDir = filterOut_1[_i]; if (uncleanableDir === directoryPath) { return false; } } return true; }); return deleteDirectories(cleanableDirectories); } function deleteDirectories(directoryPaths) { var promises = []; for (var _i = 0, directoryPaths_1 = directoryPaths; _i < directoryPaths_1.length; _i++) { var directoryPath = directoryPaths_1[_i]; promises.push(helpers_1.rimRafAsync(directoryPath)); } return Promise.all(promises); } function processRemoveFile(changedFile) { // delete any destination files that match the source file var list = copyFilePathCache.get(changedFile.filePath) || []; copyFilePathCache.delete(changedFile.filePath); var promises = []; var deletedFilePaths = []; list.forEach(function (copiedFile) { var promise = helpers_1.unlinkAsync(copiedFile.absoluteDestPath); promises.push(promise); promise.catch(function (err) { if (err && err.message && err.message.indexOf('ENOENT') >= 0) { logger_1.Logger.warn("Failed to delete " + copiedFile.absoluteDestPath + " because it doesn't exist"); return; } throw err; }); deletedFilePaths.push(copiedFile.absoluteDestPath); }); events_1.emit(events_1.EventType.FileDelete, deletedFilePaths); return Promise.all(promises).catch(function (err) { }); } function processRemoveDir(changedFile) { // remove any files from the cache where the dirname equals the provided path var keysToRemove = []; var directoriesToRemove = new Set(); copyFilePathCache.forEach(function (copiedFiles, filePath) { if (path_1.dirname(filePath) === changedFile.filePath) { keysToRemove.push(filePath); copiedFiles.forEach(function (copiedFile) { return directoriesToRemove.add(path_1.dirname(copiedFile.absoluteDestPath)); }); } }); keysToRemove.forEach(function (keyToRemove) { return copyFilePathCache.delete(keyToRemove); }); // the entries are removed from the cache, now just rim raf the directoryPath var promises = []; directoriesToRemove.forEach(function (directoryToRemove) { promises.push(helpers_1.rimRafAsync(directoryToRemove)); }); events_1.emit(events_1.EventType.DirectoryDelete, Array.from(directoriesToRemove)); return Promise.all(promises); } function cacheCopyData(copyObject) { var list = copyFilePathCache.get(copyObject.absoluteSourcePath); if (!list) { list = []; } list.push(copyObject); copyFilePathCache.set(copyObject.absoluteSourcePath, list); } function getFilesPathsForConfig(copyConfigKeys, copyConfig) { // execute the glob functions to determine what files match each glob var srcToResultsMap = new Map(); var promises = []; copyConfigKeys.forEach(function (key) { var copyOptions = copyConfig[key]; if (copyOptions && copyOptions.src) { var promise = glob_util_1.globAll(copyOptions.src); promises.push(promise); promise.then(function (globResultList) { srcToResultsMap.set(key, globResultList); }); } }); return Promise.all(promises).then(function () { return srcToResultsMap; }); } function populateFileAndDirectoryInfo(resultMap, copyConfig, toCopyList, directoriesToCreate) { resultMap.forEach(function (globResults, dictionaryKey) { globResults.forEach(function (globResult) { // get the relative path from the of each file from the glob var relativePath = path_1.relative(globResult.base, globResult.absolutePath); // append the relative path to the dest var destFileName = path_1.resolve(path_1.join(copyConfig[dictionaryKey].dest, relativePath)); // store the file information toCopyList.push({ absoluteSourcePath: globResult.absolutePath, absoluteDestPath: destFileName }); var directoryToCreate = path_1.dirname(destFileName); directoriesToCreate.add(directoryToCreate); }); }); } function cleanConfigContent(dictionaryKeys, copyConfig, context) { dictionaryKeys.forEach(function (key) { var copyOption = copyConfig[key]; if (copyOption && copyOption.src && copyOption.src.length) { var cleanedUpSrc = config_1.replacePathVars(context, copyOption.src); copyOption.src = cleanedUpSrc; var cleanedUpDest = config_1.replacePathVars(context, copyOption.dest); copyOption.dest = cleanedUpDest; } }); } function copyConfigToWatchConfig(context) { if (!context) { context = config_1.generateContext(context); } var configFile = config_1.getUserConfigFile(context, exports.taskInfo, ''); var copyConfig = config_1.fillConfigDefaults(configFile, exports.taskInfo.defaultConfigFile); var results = []; for (var _i = 0, _a = Object.keys(copyConfig); _i < _a.length; _i++) { var key = _a[_i]; if (copyConfig[key] && copyConfig[key].src) { var list = glob_util_1.generateGlobTasks(copyConfig[key].src, {}); results = results.concat(list); } } var paths = []; var ignored = []; for (var _b = 0, results_1 = results; _b < results_1.length; _b++) { var result = results_1[_b]; paths.push(result.pattern); if (result.opts && result.opts.ignore) { ignored = ignored.concat(result.opts.ignore); } } return { paths: paths, options: { ignored: ignored }, callback: watch_1.copyUpdate }; } exports.copyConfigToWatchConfig = copyConfigToWatchConfig; exports.taskInfo = { fullArg: '--copy', shortArg: '-y', envVar: 'IONIC_COPY', packageConfig: 'ionic_copy', defaultConfigFile: 'copy.config' };