UNPKG

atom-nuclide

Version:

A unified developer experience for web and mobile development, built as a suite of features on top of Atom to provide hackability and the support of an active community.

251 lines (205 loc) 10.3 kB
var _slicedToArray = (function () { function sliceIterator(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i['return']) _i['return'](); } finally { if (_d) throw _e; } } return _arr; } return function (arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { return sliceIterator(arr, i); } else { throw new TypeError('Invalid attempt to destructure non-iterable instance'); } }; })(); /** * Renames a single node to the new path. */ var renameNode = _asyncToGenerator(function* (node, destPath) { if (!isValidRename(node, destPath)) { return; } var filePath = (_FileTreeHelpers2 || _FileTreeHelpers()).default.keyToPath(node.uri); // Need to update the paths in editors before the rename to prevent them from closing // In case of an error - undo the editor paths rename (_FileTreeHelpers2 || _FileTreeHelpers()).default.updatePathInOpenedEditors(filePath, destPath); try { var service = (0, (_nuclideRemoteConnection2 || _nuclideRemoteConnection()).getFileSystemServiceByNuclideUri)(filePath); // Throws if the destPath already exists. yield service.rename((_commonsNodeNuclideUri2 || _commonsNodeNuclideUri()).default.getPath(filePath), (_commonsNodeNuclideUri2 || _commonsNodeNuclideUri()).default.getPath(destPath)); var hgRepository = getHgRepositoryForNode(node); if (hgRepository == null) { return; } yield hgRepository.rename([filePath], destPath, true /* after */); } catch (err) { (_FileTreeHelpers2 || _FileTreeHelpers()).default.updatePathInOpenedEditors(destPath, filePath); throw err; } } /** * Lock on move to prevent concurrent moves, which may lead to race conditions * with the hg wlock. */ ); /** * Moves an array of nodes into the destPath, ignoring nodes that cannot be moved. * This wrapper prevents concurrent move operations. */ var moveNodes = _asyncToGenerator(function* (nodes, destPath) { if (isMoving) { return; } isMoving = true; // Reset isMoving to false whenever move operation completes, errors, or times out. yield (0, (_commonsNodePromise2 || _commonsNodePromise()).triggerAfterWait)(_moveNodesUnprotected(nodes, destPath), MOVE_TIMEOUT, resetIsMoving, /* timeoutFn */ resetIsMoving); }); /* cleanupFn */ var _moveNodesUnprotected = _asyncToGenerator(function* (nodes, destPath) { var paths = []; try { var filteredNodes = nodes.filter(function (node) { return isValidRename(node, destPath); }); // Collapse paths that are in the same subtree, keeping only the subtree root. paths = (_commonsNodeNuclideUri2 || _commonsNodeNuclideUri()).default.collapse(filteredNodes.map(function (node) { return (_FileTreeHelpers2 || _FileTreeHelpers()).default.keyToPath(node.uri); })); if (paths.length === 0) { return; } // Need to update the paths in editors before the rename to prevent them from closing // In case of an error - undo the editor paths rename paths.forEach(function (path) { var newPath = (_commonsNodeNuclideUri2 || _commonsNodeNuclideUri()).default.join(destPath, (_commonsNodeNuclideUri2 || _commonsNodeNuclideUri()).default.basename(path)); (_FileTreeHelpers2 || _FileTreeHelpers()).default.updatePathInOpenedEditors(path, newPath); }); var service = (0, (_nuclideRemoteConnection2 || _nuclideRemoteConnection()).getFileSystemServiceByNuclideUri)(paths[0]); yield service.move(paths.map(function (p) { return (_commonsNodeNuclideUri2 || _commonsNodeNuclideUri()).default.getPath(p); }), (_commonsNodeNuclideUri2 || _commonsNodeNuclideUri()).default.getPath(destPath)); // All filtered nodes should have the same rootUri, so we simply attempt to // retrieve the hg repository using the first node. var hgRepository = getHgRepositoryForNode(filteredNodes[0]); if (hgRepository == null) { return; } yield hgRepository.rename(paths, destPath, true /* after */); } catch (e) { // Restore old editor paths upon error. paths.forEach(function (path) { var newPath = (_commonsNodeNuclideUri2 || _commonsNodeNuclideUri()).default.join(destPath, (_commonsNodeNuclideUri2 || _commonsNodeNuclideUri()).default.basename(path)); (_FileTreeHelpers2 || _FileTreeHelpers()).default.updatePathInOpenedEditors(newPath, path); }); throw e; } } /** * Deletes an array of nodes. */ ); var deleteNodes = _asyncToGenerator(function* (nodes) { // Filter out children nodes to avoid ENOENTs that happen when parents are // deleted before its children. Convert to List so we can use groupBy. var paths = (_immutable2 || _immutable()).default.List((_commonsNodeNuclideUri2 || _commonsNodeNuclideUri()).default.collapse(nodes.map(function (node) { return (_FileTreeHelpers2 || _FileTreeHelpers()).default.keyToPath(node.uri); }))); var localPaths = paths.filter(function (path) { return (_commonsNodeNuclideUri2 || _commonsNodeNuclideUri()).default.isLocal(path); }); var remotePaths = paths.filter(function (path) { return (_commonsNodeNuclideUri2 || _commonsNodeNuclideUri()).default.isRemote(path); }); // 1) Move local nodes to trash. localPaths.forEach(function (path) { return (_electron2 || _electron()).shell.moveItemToTrash(path); }); // 2) Batch delete remote nodes, one request per hostname. if (remotePaths.size > 0) { var pathsByHost = remotePaths.groupBy(function (path) { return (_commonsNodeNuclideUri2 || _commonsNodeNuclideUri()).default.getHostname(path); }); yield Promise.all(pathsByHost.map(_asyncToGenerator(function* (pathGroup) { // Batch delete using fs service. var service = (0, (_nuclideRemoteConnection2 || _nuclideRemoteConnection()).getFileSystemServiceByNuclideUri)(pathGroup.get(0)); yield service.rmdirAll(pathGroup.map(function (path) { return (_commonsNodeNuclideUri2 || _commonsNodeNuclideUri()).default.getPath(path); }).toJS()); }))); } // 3) Batch hg remove nodes that belong to an hg repo, one request per repo. var nodesByHgRepository = (_immutable2 || _immutable()).default.List(nodes).filter(function (node) { return getHgRepositoryForNode(node) != null; }).groupBy(function (node) { return getHgRepositoryForNode(node); }).entrySeq(); yield Promise.all(nodesByHgRepository.map(_asyncToGenerator(function* (_ref) { var _ref2 = _slicedToArray(_ref, 2); var hgRepository = _ref2[0]; var repoNodes = _ref2[1]; var hgPaths = (_commonsNodeNuclideUri2 || _commonsNodeNuclideUri()).default.collapse(repoNodes.map(function (node) { return (_FileTreeHelpers2 || _FileTreeHelpers()).default.keyToPath(node.uri); }).toJS()); yield hgRepository.remove(hgPaths, true /* after */); }))); }); function _asyncToGenerator(fn) { return function () { var gen = fn.apply(this, arguments); return new Promise(function (resolve, reject) { var callNext = step.bind(null, 'next'); var callThrow = step.bind(null, 'throw'); function step(key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { Promise.resolve(value).then(callNext, callThrow); } } callNext(); }); }; } /* * Copyright (c) 2015-present, Facebook, Inc. * All rights reserved. * * This source code is licensed under the license found in the LICENSE file in * the root directory of this source tree. */ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } var _electron2; function _electron() { return _electron2 = require('electron'); } var _immutable2; function _immutable() { return _immutable2 = _interopRequireDefault(require('immutable')); } var _commonsNodeNuclideUri2; function _commonsNodeNuclideUri() { return _commonsNodeNuclideUri2 = _interopRequireDefault(require('../../commons-node/nuclideUri')); } var _FileTreeHelpers2; function _FileTreeHelpers() { return _FileTreeHelpers2 = _interopRequireDefault(require('./FileTreeHelpers')); } var _commonsNodePromise2; function _commonsNodePromise() { return _commonsNodePromise2 = require('../../commons-node/promise'); } var _nuclideRemoteConnection2; function _nuclideRemoteConnection() { return _nuclideRemoteConnection2 = require('../../nuclide-remote-connection'); } var MOVE_TIMEOUT = 10000; function getHgRepositoryForNode(node) { var repository = node.repo; if (repository != null && repository.getType() === 'hg') { return repository; } return null; } /** * Determines whether renaming the given node to the specified destPath is an * acceptable rename. */ function isValidRename(node, destPath_) { var destPath = destPath_; var path = (_FileTreeHelpers2 || _FileTreeHelpers()).default.keyToPath(node.uri); var rootPath = (_FileTreeHelpers2 || _FileTreeHelpers()).default.keyToPath(node.rootUri); destPath = (_FileTreeHelpers2 || _FileTreeHelpers()).default.keyToPath(destPath); return (_FileTreeHelpers2 || _FileTreeHelpers()).default.getEntryByKey(node.uri) != null && // This will only detect exact equalities, mostly preventing moves of a // directory into itself from causing an error. If a case-changing rename // should be a noop for the current OS's file system, this is handled by the // fs module. path !== destPath && // Disallow renames where the destination is a child of the source node. !(_commonsNodeNuclideUri2 || _commonsNodeNuclideUri()).default.contains(path, (_commonsNodeNuclideUri2 || _commonsNodeNuclideUri()).default.dirname(destPath)) && // Disallow renames across projects for the time being, since cross-host and // cross-repository moves are a bit tricky. (_commonsNodeNuclideUri2 || _commonsNodeNuclideUri()).default.contains(rootPath, destPath); }var isMoving = false; function resetIsMoving() { isMoving = false; } module.exports = { getHgRepositoryForNode: getHgRepositoryForNode, isValidRename: isValidRename, renameNode: renameNode, moveNodes: moveNodes, deleteNodes: deleteNodes };