public Collection<Change> getAllChanges() { final Collection<Change> changes = new HashSet<Change>(); for (LocalChangeList list : myMap.values()) { changes.addAll(list.getChanges()); } return changes; }
public Pair<List<RepositoryLocationGroup>, List<RepositoryLocation>> groupLocations( final List<RepositoryLocation> in) { final List<RepositoryLocationGroup> groups = new ArrayList<RepositoryLocationGroup>(); final List<RepositoryLocation> singles = new ArrayList<RepositoryLocation>(); final MultiMap<SVNURL, RepositoryLocation> map = new MultiMap<SVNURL, RepositoryLocation>(); for (RepositoryLocation location : in) { final SvnRepositoryLocation svnLocation = (SvnRepositoryLocation) location; final String url = svnLocation.getURL(); final SVNURL root = SvnUtil.getRepositoryRoot(myVcs, url); if (root == null) { // should not occur LOG.info("repository root not found for location:" + location.toPresentableString()); singles.add(location); } else { map.putValue(root, svnLocation); } } final Set<SVNURL> keys = map.keySet(); for (SVNURL key : keys) { final Collection<RepositoryLocation> repositoryLocations = map.get(key); if (repositoryLocations.size() == 1) { singles.add(repositoryLocations.iterator().next()); } else { final SvnRepositoryLocationGroup group = new SvnRepositoryLocationGroup(key, repositoryLocations); groups.add(group); } } return new Pair<List<RepositoryLocationGroup>, List<RepositoryLocation>>(groups, singles); }
public List<ShelvedChangeList> importChangeLists( final Collection<VirtualFile> files, final Consumer<VcsException> exceptionConsumer) { final List<ShelvedChangeList> result = new ArrayList<ShelvedChangeList>(files.size()); try { final FilesProgress filesProgress = new FilesProgress(files.size(), "Processing "); for (VirtualFile file : files) { filesProgress.updateIndicator(file); final String description = file.getNameWithoutExtension().replace('_', ' '); final File patchPath = getPatchPath(description); final ShelvedChangeList list = new ShelvedChangeList( patchPath.getPath(), description, new SmartList<ShelvedBinaryFile>(), file.getTimeStamp()); try { final List<TextFilePatch> patchesList = loadPatches(myProject, file.getPath(), new CommitContext()); if (!patchesList.isEmpty()) { FileUtil.copy(new File(file.getPath()), patchPath); // add only if ok to read patch myShelvedChangeLists.add(list); result.add(list); } } catch (IOException e) { exceptionConsumer.consume(new VcsException(e)); } catch (PatchSyntaxException e) { exceptionConsumer.consume(new VcsException(e)); } } } finally { notifyStateChanged(); } return result; }
private void processDeletedFiles(Project project) { final List<Pair<FilePath, WorkingCopyFormat>> deletedFiles = new ArrayList<Pair<FilePath, WorkingCopyFormat>>(); final Collection<FilePath> filesToProcess = new ArrayList<FilePath>(); List<VcsException> exceptions = new ArrayList<VcsException>(); final AbstractVcsHelper vcsHelper = AbstractVcsHelper.getInstance(project); try { fillDeletedFiles(project, deletedFiles, filesToProcess); if (deletedFiles.isEmpty() && filesToProcess.isEmpty() || myUndoingMove) return; SvnVcs vcs = SvnVcs.getInstance(project); final VcsShowConfirmationOption.Value value = vcs.getDeleteConfirmation().getValue(); if (value != VcsShowConfirmationOption.Value.DO_NOTHING_SILENTLY) { if (!deletedFiles.isEmpty()) { final Collection<FilePath> confirmed = promptAboutDeletion(deletedFiles, vcs, value, vcsHelper); if (confirmed != null) { filesToProcess.addAll(confirmed); } } if (filesToProcess != null && !filesToProcess.isEmpty()) { runInBackground( project, "Deleting files from Subversion", createDeleteRunnable(project, vcs, filesToProcess, exceptions)); } final List<FilePath> deletedFilesFiles = ObjectsConvertor.convert( deletedFiles, new Convertor<Pair<FilePath, WorkingCopyFormat>, FilePath>() { @Override public FilePath convert(Pair<FilePath, WorkingCopyFormat> o) { return o.getFirst(); } }); for (FilePath file : deletedFilesFiles) { final FilePath parent = file.getParentPath(); if (parent != null) { myFilesToRefresh.add(parent.getVirtualFile()); } } if (filesToProcess != null) { deletedFilesFiles.removeAll(filesToProcess); } for (FilePath file : deletedFilesFiles) { FileUtil.delete(file.getIOFile()); } } } catch (SVNException e) { exceptions.add(new VcsException(e)); } if (!exceptions.isEmpty()) { vcsHelper.showErrors(exceptions, SvnBundle.message("delete.files.errors.title")); } }
@CalledInAwt public static void refreshPassedFilesAndMoveToChangelist( @NotNull final Project project, final Collection<FilePath> directlyAffected, final Collection<VirtualFile> indirectlyAffected, final Consumer<Collection<FilePath>> targetChangelistMover) { final LocalFileSystem lfs = LocalFileSystem.getInstance(); for (FilePath filePath : directlyAffected) { lfs.refreshAndFindFileByIoFile(filePath.getIOFile()); } if (project.isDisposed()) return; final ChangeListManager changeListManager = ChangeListManager.getInstance(project); if (!directlyAffected.isEmpty() && targetChangelistMover != null) { changeListManager.invokeAfterUpdate( new Runnable() { @Override public void run() { targetChangelistMover.consume(directlyAffected); } }, InvokeAfterUpdateMode.SYNCHRONOUS_CANCELLABLE, VcsBundle.message("change.lists.manager.move.changes.to.list"), new Consumer<VcsDirtyScopeManager>() { @Override public void consume(final VcsDirtyScopeManager vcsDirtyScopeManager) { markDirty(vcsDirtyScopeManager, directlyAffected, indirectlyAffected); } }, null); } else { markDirty(VcsDirtyScopeManager.getInstance(project), directlyAffected, indirectlyAffected); } }
protected VirtualFile[] getSelectedFiles() { final Change[] changes = getSelectedChanges(); Collection<VirtualFile> files = new HashSet<VirtualFile>(); for (Change change : changes) { final ContentRevision afterRevision = change.getAfterRevision(); if (afterRevision != null) { final VirtualFile file = afterRevision.getFile().getVirtualFile(); if (file != null && file.isValid()) { files.add(file); } } } files.addAll(getSelectedVirtualFiles(null)); return VfsUtilCore.toVirtualFileArray(files); }
// called NOT under ChangeListManagerImpl lock public void notifyStartProcessingChanges(final VcsModifiableDirtyScope scope) { final Collection<Change> oldChanges = new ArrayList<Change>(); for (LocalChangeList list : myMap.values()) { final Collection<Change> affectedChanges = ((LocalChangeListImpl) list).startProcessingChanges(myProject, scope); if (!affectedChanges.isEmpty()) { oldChanges.addAll(affectedChanges); } } for (Change change : oldChanges) { myIdx.changeRemoved(change); } // scope should be modified for correct moves tracking correctScopeForMoves(scope, oldChanges); myLocallyDeleted.cleanAndAdjustScope(scope); mySwitchedHolder.cleanAndAdjustScope(scope); }
private static void filterOutInvalid(final Collection<VirtualFile> files) { for (Iterator<VirtualFile> iterator = files.iterator(); iterator.hasNext(); ) { final VirtualFile file = iterator.next(); if (!file.isValid() || !file.exists()) { LOG.info("Refresh root is not valid: " + file.getPath()); iterator.remove(); } } }
@NotNull public static Collection<VcsDirectoryMapping> findRoots( @NotNull VirtualFile rootDir, @NotNull Project project) throws IllegalArgumentException { if (!rootDir.isDirectory()) { throw new IllegalArgumentException( "Can't find VCS at the target file system path. Reason: expected to find a directory there but it's not. The path: " + rootDir.getParent()); } Collection<VcsRoot> roots = ServiceManager.getService(project, VcsRootDetector.class).detect(rootDir); Collection<VcsDirectoryMapping> result = ContainerUtilRt.newArrayList(); for (VcsRoot vcsRoot : roots) { VirtualFile vFile = vcsRoot.getPath(); AbstractVcs rootVcs = vcsRoot.getVcs(); if (rootVcs != null && vFile != null) { result.add(new VcsDirectoryMapping(vFile.getPath(), rootVcs.getName())); } } return result; }
@Nullable public String listNameIfOnlyOne(final @Nullable Change[] changes) { if (changes == null || changes.length == 0) { return null; } final Change first = changes[0]; for (LocalChangeList list : myMap.values()) { final Collection<Change> listChanges = list.getChanges(); if (listChanges.contains(first)) { // must contain all other for (int i = 1; i < changes.length; i++) { final Change change = changes[i]; if (!listChanges.contains(change)) { return null; } } return list.getName(); } } return null; }
private void processAddedFiles(Project project) { SvnVcs vcs = SvnVcs.getInstance(project); List<VirtualFile> addedVFiles = new ArrayList<VirtualFile>(); Map<VirtualFile, File> copyFromMap = new HashMap<VirtualFile, File>(); final Set<VirtualFile> recursiveItems = new HashSet<VirtualFile>(); fillAddedFiles(project, vcs, addedVFiles, copyFromMap, recursiveItems); if (addedVFiles.isEmpty()) return; final VcsShowConfirmationOption.Value value = vcs.getAddConfirmation().getValue(); if (value != VcsShowConfirmationOption.Value.DO_NOTHING_SILENTLY) { final AbstractVcsHelper vcsHelper = AbstractVcsHelper.getInstance(project); final Collection<VirtualFile> filesToProcess = promptAboutAddition(vcs, addedVFiles, value, vcsHelper); if (filesToProcess != null && !filesToProcess.isEmpty()) { final List<VcsException> exceptions = new ArrayList<VcsException>(); runInBackground( project, "Adding files to Subversion", createAdditionRunnable(project, vcs, copyFromMap, filesToProcess, exceptions)); if (!exceptions.isEmpty()) { vcsHelper.showErrors(exceptions, SvnBundle.message("add.files.errors.title")); } } } }
private void checkOverwrites(final Project project) { final Collection<AddedFileInfo> addedFileInfos = myAddedFiles.get(project); final Collection<File> deletedFiles = myDeletedFiles.get(project); if (addedFileInfos.isEmpty() || deletedFiles.isEmpty()) return; final Iterator<AddedFileInfo> iterator = addedFileInfos.iterator(); while (iterator.hasNext()) { AddedFileInfo addedFileInfo = iterator.next(); final File ioFile = new File(addedFileInfo.myDir.getPath(), addedFileInfo.myName); if (deletedFiles.remove(ioFile)) { iterator.remove(); } } }
private void fillDeletedFiles( Project project, List<Pair<FilePath, WorkingCopyFormat>> deletedFiles, Collection<FilePath> deleteAnyway) throws SVNException { final SvnVcs vcs = SvnVcs.getInstance(project); final Collection<File> files = myDeletedFiles.remove(project); for (final File file : files) { final SVNStatus status = new RepeatSvnActionThroughBusy() { @Override protected void executeImpl() throws SVNException { myT = vcs.getFactory(file).createStatusClient().doStatus(file, false); } }.compute(); boolean isAdded = SVNStatusType.STATUS_ADDED.equals(status.getNodeStatus()); final FilePath filePath = VcsContextFactory.SERVICE.getInstance().createFilePathOn(file); if (isAdded) { deleteAnyway.add(filePath); } else { deletedFiles.add(Pair.create(filePath, vcs.getWorkingCopyFormat(file))); } } }
public boolean updateStep(final AtomicSectionsAware atomicSectionsAware) { final MultiMap<VcsRoot, String> dirty = new MultiMap<VcsRoot, String>(); final long oldPoint = System.currentTimeMillis() - (myVcsConfiguration.CHANGED_ON_SERVER_INTERVAL > 0 ? myVcsConfiguration.CHANGED_ON_SERVER_INTERVAL * 60000 : DISCRETE); synchronized (myLock) { for (VcsRoot root : myQueries.keySet()) { final Collection<String> collection = myQueries.get(root); for (String s : collection) { dirty.putValue(root, s); } } myQueries.clear(); final Set<VcsRoot> roots = new HashSet<VcsRoot>(); for (Map.Entry<VcsRoot, Long> entry : myTs.entrySet()) { if (!dirty.get(entry.getKey()).isEmpty()) continue; final Long ts = entry.getValue(); if ((ts == null) || (oldPoint > ts)) { roots.add(entry.getKey()); } } for (Map.Entry<String, Pair<Boolean, VcsRoot>> entry : myChanged.entrySet()) { final VcsRoot vcsRoot = entry.getValue().getSecond(); if ((!dirty.get(vcsRoot).isEmpty()) || roots.contains(vcsRoot)) { dirty.putValue(vcsRoot, entry.getKey()); } } } if (dirty.isEmpty()) return false; final Map<String, Pair<Boolean, VcsRoot>> results = new HashMap<String, Pair<Boolean, VcsRoot>>(); for (VcsRoot vcsRoot : dirty.keySet()) { atomicSectionsAware.checkShouldExit(); // todo - actually it means nothing since the only known VCS to use this scheme is Git and now // it always allow // todo - background operations. when it changes, develop more flexible behavior here if (!vcsRoot.vcs.isVcsBackgroundOperationsAllowed(vcsRoot.path)) continue; final TreeDiffProvider provider = vcsRoot.vcs.getTreeDiffProvider(); if (provider == null) continue; final Collection<String> paths = dirty.get(vcsRoot); final Collection<String> remotelyChanged = provider.getRemotelyChanged(vcsRoot.path, paths); for (String path : paths) { results.put(path, new Pair<Boolean, VcsRoot>(remotelyChanged.contains(path), vcsRoot)); } } final long curTime = System.currentTimeMillis(); synchronized (myLock) { myChanged.putAll(results); for (VcsRoot vcsRoot : dirty.keySet()) { myTs.put(vcsRoot, curTime); } } return true; }
@Override public Pair<SvnChangeList, FilePath> getOneList(final VirtualFile file, VcsRevisionNumber number) throws VcsException { final RootUrlInfo rootUrlInfo = myVcs.getSvnFileUrlMapping().getWcRootForFilePath(new File(file.getPath())); if (rootUrlInfo == null) return null; final VirtualFile root = rootUrlInfo.getVirtualFile(); if (root == null) return null; final SvnRepositoryLocation svnRootLocation = (SvnRepositoryLocation) getLocationFor(new FilePathImpl(root)); if (svnRootLocation == null) return null; final String url = svnRootLocation.getURL(); final long revision; try { revision = Long.parseLong(number.asString()); } catch (NumberFormatException e) { throw new VcsException(e); } final SvnChangeList[] result = new SvnChangeList[1]; final SVNLogClient logger; final SVNRevision revisionBefore; final SVNURL repositoryUrl; final SVNURL svnurl; final SVNInfo targetInfo; try { logger = myVcs.createLogClient(); revisionBefore = SVNRevision.create(revision); svnurl = SVNURL.parseURIEncoded(url); final SVNWCClient client = myVcs.createWCClient(); final SVNInfo info = client.doInfo(svnurl, SVNRevision.UNDEFINED, SVNRevision.HEAD); targetInfo = client.doInfo(new File(file.getPath()), SVNRevision.UNDEFINED); if (info == null) { throw new VcsException("Can not get repository URL"); } repositoryUrl = info.getRepositoryRootURL(); } catch (SVNException e) { LOG.info(e); throw new VcsException(e); } tryExactHit(svnRootLocation, result, logger, revisionBefore, repositoryUrl, svnurl); if (result[0] == null) { tryByRoot(result, logger, revisionBefore, repositoryUrl); if (result[0] == null) { FilePath path = tryStepByStep(svnRootLocation, result, logger, revisionBefore, targetInfo, svnurl); path = path == null ? new FilePathImpl(file) : path; // and pass & take rename context there return new Pair<SvnChangeList, FilePath>(result[0], path); } } if (result[0].getChanges().size() == 1) { final Collection<Change> changes = result[0].getChanges(); final Change change = changes.iterator().next(); final ContentRevision afterRevision = change.getAfterRevision(); if (afterRevision != null) { return new Pair<SvnChangeList, FilePath>(result[0], afterRevision.getFile()); } else { return new Pair<SvnChangeList, FilePath>(result[0], new FilePathImpl(file)); } } String relativePath = SVNPathUtil.getRelativePath( targetInfo.getRepositoryRootURL().toString(), targetInfo.getURL().toString()); relativePath = relativePath.startsWith("/") ? relativePath : "/" + relativePath; final Change targetChange = result[0].getByPath(relativePath); if (targetChange == null) { FilePath path = tryStepByStep(svnRootLocation, result, logger, revisionBefore, targetInfo, svnurl); path = path == null ? new FilePathImpl(file) : path; // and pass & take rename context there return new Pair<SvnChangeList, FilePath>(result[0], path); } return new Pair<SvnChangeList, FilePath>(result[0], new FilePathImpl(file)); }
public boolean updateStep() { final MultiMap<VcsRoot, String> dirty = new MultiMap<VcsRoot, String>(); final long oldPoint = System.currentTimeMillis() - (myVcsConfiguration.CHANGED_ON_SERVER_INTERVAL > 0 ? myVcsConfiguration.CHANGED_ON_SERVER_INTERVAL * 60000 : DISCRETE); synchronized (myLock) { // just copies myQueries MultiMap to dirty MultiMap for (VcsRoot root : myQueries.keySet()) { final Collection<String> collection = myQueries.get(root); for (String s : collection) { dirty.putValue(root, s); } } myQueries.clear(); // collect roots for which cache update should be performed (by timestamp) final Set<VcsRoot> roots = new HashSet<VcsRoot>(); for (Map.Entry<VcsRoot, Long> entry : myTs.entrySet()) { // ignore timestamp, as still remote changes checking is required // TODO: why not to add in roots anyway??? - as dirty is still checked when adding myChanged // files. if (!dirty.get(entry.getKey()).isEmpty()) continue; // update only if timeout expired final Long ts = entry.getValue(); if ((ts == null) || (oldPoint > ts)) { roots.add(entry.getKey()); } } // Add dirty files from those vcs roots, that // - needs to be update by timestamp criteria // - that already contain files for update through manually added requests for (Map.Entry<String, Pair<Boolean, VcsRoot>> entry : myChanged.entrySet()) { final VcsRoot vcsRoot = entry.getValue().getSecond(); if ((!dirty.get(vcsRoot).isEmpty()) || roots.contains(vcsRoot)) { dirty.putValue(vcsRoot, entry.getKey()); } } } if (dirty.isEmpty()) return false; final Map<String, Pair<Boolean, VcsRoot>> results = new HashMap<String, Pair<Boolean, VcsRoot>>(); for (VcsRoot vcsRoot : dirty.keySet()) { // todo - actually it means nothing since the only known VCS to use this scheme is Git and now // it always allow // todo - background operations. when it changes, develop more flexible behavior here if (!vcsRoot.getVcs().isVcsBackgroundOperationsAllowed(vcsRoot.getPath())) continue; final TreeDiffProvider provider = vcsRoot.getVcs().getTreeDiffProvider(); if (provider == null) continue; final Collection<String> paths = dirty.get(vcsRoot); final Collection<String> remotelyChanged = provider.getRemotelyChanged(vcsRoot.getPath(), paths); for (String path : paths) { // TODO: Contains invoked for each file - better to use Set (implementations just use List) // TODO: Why to store boolean for changed or not - why not just remove such values from // myChanged??? results.put(path, new Pair<Boolean, VcsRoot>(remotelyChanged.contains(path), vcsRoot)); } } final long curTime = System.currentTimeMillis(); synchronized (myLock) { myChanged.putAll(results); for (VcsRoot vcsRoot : dirty.keySet()) { myTs.put(vcsRoot, curTime); } } return true; }
@CalledInAwt public static ApplyPatchStatus executePatchGroup( final Collection<PatchApplier> group, final LocalChangeList localChangeList) { if (group.isEmpty()) return ApplyPatchStatus.SUCCESS; // ? final Project project = group.iterator().next().myProject; ApplyPatchStatus result = ApplyPatchStatus.SUCCESS; for (PatchApplier patchApplier : group) { result = ApplyPatchStatus.and(result, patchApplier.nonWriteActionPreCheck()); } final Label beforeLabel = LocalHistory.getInstance().putSystemLabel(project, "Before patch"); final TriggerAdditionOrDeletion trigger = new TriggerAdditionOrDeletion(project); final Ref<ApplyPatchStatus> refStatus = new Ref<>(result); try { CommandProcessor.getInstance() .executeCommand( project, new Runnable() { @Override public void run() { for (PatchApplier applier : group) { refStatus.set(ApplyPatchStatus.and(refStatus.get(), applier.createFiles())); applier.addSkippedItems(trigger); } trigger.prepare(); if (refStatus.get() == ApplyPatchStatus.SUCCESS) { // all pre-check results are valuable only if not successful; actual status we // can receive after executeWritable refStatus.set(null); } for (PatchApplier applier : group) { refStatus.set(ApplyPatchStatus.and(refStatus.get(), applier.executeWritable())); if (refStatus.get() == ApplyPatchStatus.ABORT) break; } } }, VcsBundle.message("patch.apply.command"), null); } finally { VcsFileListenerContextHelper.getInstance(project).clearContext(); LocalHistory.getInstance().putSystemLabel(project, "After patch"); } result = refStatus.get(); result = result == null ? ApplyPatchStatus.FAILURE : result; trigger.processIt(); final Set<FilePath> directlyAffected = new HashSet<>(); final Set<VirtualFile> indirectlyAffected = new HashSet<>(); for (PatchApplier applier : group) { directlyAffected.addAll(applier.getDirectlyAffected()); indirectlyAffected.addAll(applier.getIndirectlyAffected()); } directlyAffected.addAll(trigger.getAffected()); final Consumer<Collection<FilePath>> mover = localChangeList == null ? null : createMover(project, localChangeList); refreshPassedFilesAndMoveToChangelist(project, directlyAffected, indirectlyAffected, mover); if (result == ApplyPatchStatus.FAILURE) { suggestRollback(project, group, beforeLabel); } else if (result == ApplyPatchStatus.ABORT) { rollbackUnderProgress(project, project.getBaseDir(), beforeLabel); } showApplyStatus(project, result); return result; }