private Couple<String> keyForChange(final Change change) { final FilePath beforePath = ChangesUtil.getBeforePath(change); final String beforeKey = beforePath == null ? null : beforePath.getIOFile().getAbsolutePath(); final FilePath afterPath = ChangesUtil.getAfterPath(change); final String afterKey = afterPath == null ? null : afterPath.getIOFile().getAbsolutePath(); return Couple.of(beforeKey, afterKey); }
public Change getChange(Project project) { // todo unify with if (myChange == null) { File baseDir = new File(project.getBaseDir().getPath()); File file = getAbsolutePath(baseDir, myBeforePath); FilePath beforePath = VcsUtil.getFilePath(file, false); beforePath.refresh(); ContentRevision beforeRevision = null; if (myFileStatus != FileStatus.ADDED) { beforeRevision = new CurrentContentRevision(beforePath) { @Override @NotNull public VcsRevisionNumber getRevisionNumber() { return new TextRevisionNumber(VcsBundle.message("local.version.title")); } }; } ContentRevision afterRevision = null; if (myFileStatus != FileStatus.DELETED) { FilePath afterPath = VcsUtil.getFilePath(getAbsolutePath(baseDir, myAfterPath), false); afterRevision = new PatchedContentRevision(project, beforePath, afterPath); } myChange = new Change(beforeRevision, afterRevision, myFileStatus); } return myChange; }
/** * Sort changes by roots * * @param changes a change list * @param exceptions exceptions to collect * @return sorted changes */ private static Map<VirtualFile, Collection<Change>> sortChangesByGitRoot( @NotNull List<Change> changes, List<VcsException> exceptions) { Map<VirtualFile, Collection<Change>> result = new HashMap<VirtualFile, Collection<Change>>(); for (Change change : changes) { final ContentRevision afterRevision = change.getAfterRevision(); final ContentRevision beforeRevision = change.getBeforeRevision(); // nothing-to-nothing change cannot happen. assert beforeRevision != null || afterRevision != null; // note that any path will work, because changes could happen within single vcs root final FilePath filePath = afterRevision != null ? afterRevision.getFile() : beforeRevision.getFile(); final VirtualFile vcsRoot; try { // the parent paths for calculating roots in order to account for submodules that contribute // to the parent change. The path "." is never is valid change, so there should be no // problem // with it. vcsRoot = GitUtil.getGitRoot(filePath.getParentPath()); } catch (VcsException e) { exceptions.add(e); continue; } Collection<Change> changeList = result.get(vcsRoot); if (changeList == null) { changeList = new ArrayList<Change>(); result.put(vcsRoot, changeList); } changeList.add(change); } return result; }
@NotNull private static FilePath rebasePath( @NotNull FilePath oldBase, @NotNull FilePath newBase, @NotNull FilePath path) { String relativePath = ObjectUtils.assertNotNull(FileUtil.getRelativePath(oldBase.getPath(), path.getPath(), '/')); return VcsUtil.getFilePath(newBase.getPath() + "/" + relativePath, path.isDirectory()); }
@NotNull private GitFileRevision createParentRevision( @NotNull GitRepository repository, @NotNull GitFileRevision currentRevision, @NotNull String parentHash) throws VcsException { FilePath currentRevisionPath = currentRevision.getPath(); if (currentRevisionPath.isDirectory()) { // for directories the history doesn't follow renames return makeRevisionFromHash(currentRevisionPath, parentHash); } // can't limit by the path: in that case rename information will be missed Collection<Change> changes = GitChangeUtils.getDiff( myProject, repository.getRoot(), parentHash, currentRevision.getHash(), null); for (Change change : changes) { ContentRevision afterRevision = change.getAfterRevision(); ContentRevision beforeRevision = change.getBeforeRevision(); if (afterRevision != null && afterRevision.getFile().equals(currentRevisionPath)) { // if the file was renamed, taking the path how it was in the parent; otherwise the path // didn't change FilePath path = (beforeRevision != null ? beforeRevision.getFile() : afterRevision.getFile()); return new GitFileRevision(myProject, path, new GitRevisionNumber(parentHash), true); } } LOG.error( String.format( "Could not find parent revision. Will use the path from parent revision. Current revision: %s, parent hash: %s", currentRevision, parentHash)); return makeRevisionFromHash(currentRevisionPath, parentHash); }
@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); } }
public List<File> getAffectedPaths() { final SortedSet<FilePath> set = myIdx.getAffectedPaths(); final List<File> result = new ArrayList<File>(set.size()); for (FilePath path : set) { result.add(path.getIOFile()); } return result; }
public ThreeState haveChangesUnder(@NotNull VirtualFile virtualFile) { FilePath dir = VcsUtil.getFilePath(virtualFile); FilePath changeCandidate = myIdx.getAffectedPaths().ceiling(dir); if (changeCandidate == null) { return ThreeState.NO; } return FileUtil.isAncestorThreeState(dir.getPath(), changeCandidate.getPath(), false); }
public static boolean canCreateRequest(Change change) { if (ChangesUtil.isTextConflictingChange(change) || change.isTreeConflict() || change.isPhantom()) return false; if (ShowDiffAction.isBinaryChange(change)) return false; final FilePath filePath = ChangesUtil.getFilePath(change); if (filePath.isDirectory()) return false; return true; }
private static List<VirtualFile> impl(final Iterator<FilePath> iterator) { final MyProcessor processor = new MyProcessor(); for (; iterator.hasNext(); ) { final FilePath root = iterator.next(); final VirtualFile vf = root.getVirtualFile(); if (vf == null) continue; VfsUtil.processFilesRecursively(vf, processor, processor); } return processor.getFound(); }
public static BeforeAfter<DiffContent> createBinaryDiffContents( final Project project, final Change change) throws VcsException { final FilePath filePath = ChangesUtil.getFilePath(change); try { return new BeforeAfter<DiffContent>( createBinaryFileContent(project, change.getBeforeRevision(), filePath.getName()), createBinaryFileContent(project, change.getAfterRevision(), filePath.getName())); } catch (IOException e) { throw new VcsException(e); } }
public static void refreshFiles(Project project, HashSet<FilePath> paths) { for (FilePath path : paths) { VirtualFile vFile = path.getVirtualFile(); if (vFile != null) { if (vFile.isDirectory()) { markFileAsDirty(project, vFile); } else { vFile.refresh(true, vFile.isDirectory()); } } } }
@NotNull private static Collection<VirtualFile> getVirtualFilesFromFilePaths( @NotNull Collection<FilePath> paths) { Collection<VirtualFile> files = new ArrayList<VirtualFile>(paths.size()); for (FilePath path : paths) { VirtualFile file = path.getVirtualFile(); if (file != null) { files.add(file); } } return files; }
private void collectLogEntries( final ProgressIndicator indicator, FilePath file, VcsException[] exception, final Consumer<VcsFileRevision> result, final Ref<Boolean> supports15Ref) throws SVNException, VcsException { SVNWCClient wcClient = myVcs.createWCClient(); SVNInfo info = wcClient.doInfo(new File(file.getIOFile().getAbsolutePath()), SVNRevision.UNDEFINED); wcClient.setEventHandler( new ISVNEventHandler() { public void handleEvent(SVNEvent event, double progress) throws SVNException {} public void checkCancelled() throws SVNCancelException { indicator.checkCanceled(); } }); if (info == null || info.getRepositoryRootURL() == null) { exception[0] = new VcsException("File ''{0}'' is not under version control" + file.getIOFile()); return; } final String url = info.getURL() == null ? null : info.getURL().toString(); String relativeUrl = url; final SVNURL repoRootURL = info.getRepositoryRootURL(); final String root = repoRootURL.toString(); if (url != null && url.startsWith(root)) { relativeUrl = url.substring(root.length()); } if (indicator != null) { indicator.setText2(SvnBundle.message("progress.text2.changes.establishing.connection", url)); } final SVNRevision pegRevision = info.getRevision(); SVNLogClient client = myVcs.createLogClient(); final boolean supports15 = SvnUtil.checkRepositoryVersion15(myVcs, url); supports15Ref.set(supports15); client.doLog( new File[] {new File(file.getIOFile().getAbsolutePath())}, SVNRevision.HEAD, SVNRevision.create(1), SVNRevision.UNDEFINED, false, true, supports15, 0, null, new MyLogEntryHandler( myVcs, url, pegRevision, relativeUrl, result, repoRootURL, file.getCharset())); }
@Override protected void renderIcon(FilePath path) { final String module = myModules.get(path.getVirtualFile()); if (module != null) { setIcon(PlatformIcons.CONTENT_ROOT_ICON_CLOSED); } else { if (path.isDirectory()) { setIcon(PlatformIcons.DIRECTORY_CLOSED_ICON); } else { setIcon(path.getFileType().getIcon()); } } }
private File[] getSelectedIoFiles() { final List<Change> changes = getSelectedChanges(); final List<File> files = new ArrayList<>(); for (Change change : changes) { final ContentRevision afterRevision = change.getAfterRevision(); if (afterRevision != null) { final FilePath file = afterRevision.getFile(); final File ioFile = file.getIOFile(); files.add(ioFile); } } return files.toArray(new File[files.size()]); }
private static SimpleDiffRequest createBinaryDiffRequest( final Project project, final Change change) throws VcsException { final FilePath filePath = ChangesUtil.getFilePath(change); final SimpleDiffRequest request = new SimpleDiffRequest(project, filePath.getPath()); try { request.setContents( createBinaryFileContent(project, change.getBeforeRevision(), filePath.getName()), createBinaryFileContent(project, change.getAfterRevision(), filePath.getName())); return request; } catch (IOException e) { throw new VcsException(e); } }
private static boolean directoryOrBinary(final Change change) { // todo instead for repository tab, filter directories (? ask remotely ? non leaf nodes) /*if ((change.getBeforeRevision() instanceof BinaryContentRevision) || (change.getAfterRevision() instanceof BinaryContentRevision)) { changesList.remove(i); continue; }*/ final FilePath path = ChangesUtil.getFilePath(change); if (path.isDirectory()) { return !change.hasOtherLayers(); } /*final FileType type = path.getFileType(); if ((! FileTypes.UNKNOWN.equals(type)) && (type.isBinary())) { return true; }*/ return false; }
private void doShowDiff( @NotNull FilePath filePath, @NotNull VcsFileRevision revision1, @NotNull VcsFileRevision revision2, boolean autoSort) { if (!filePath.isDirectory()) { VcsHistoryUtil.showDifferencesInBackground( myProject, filePath, revision1, revision2, autoSort); } else if (revision2 instanceof CurrentRevision) { GitFileRevision left = (GitFileRevision) revision1; showDiffForDirectory(filePath, left.getHash(), null); } else if (revision1.equals(VcsFileRevision.NULL)) { GitFileRevision right = (GitFileRevision) revision2; showDiffForDirectory(filePath, null, right.getHash()); } else { GitFileRevision left = (GitFileRevision) revision1; GitFileRevision right = (GitFileRevision) revision2; if (autoSort) { Pair<VcsFileRevision, VcsFileRevision> pair = VcsHistoryUtil.sortRevisions(revision1, revision2); left = (GitFileRevision) pair.first; right = (GitFileRevision) pair.second; } showDiffForDirectory(filePath, left.getHash(), right.getHash()); } }
/** * Gets info of the given commit and checks if it was a RENAME. If yes, returns the older file * path, which file was renamed from. If it's not a rename, returns null. */ @Nullable private static FilePath getFirstCommitRenamePath( Project project, VirtualFile root, String commit, FilePath filePath) throws VcsException { // 'git show -M --name-status <commit hash>' returns the information about commit and detects // renames. // NB: we can't specify the filepath, because then rename detection will work only with the // '--follow' option, which we don't wanna use. final GitSimpleHandler h = new GitSimpleHandler(project, root, GitCommand.SHOW); final GitLogParser parser = new GitLogParser(project, GitLogParser.NameStatus.STATUS, HASH, COMMIT_TIME, SHORT_PARENTS); h.setNoSSH(true); h.setStdoutSuppressed(true); h.addParameters("-M", "--name-status", parser.getPretty(), "--encoding=UTF-8", commit); h.endOptions(); final String output = h.run(); final List<GitLogRecord> records = parser.parse(output); if (records.isEmpty()) return null; // we have information about all changed files of the commit. Extracting information about the // file we need. final List<Change> changes = records.get(0).parseChanges(project, root); for (Change change : changes) { if ((change.isMoved() || change.isRenamed()) && filePath.equals(change.getAfterRevision().getFile())) { return change.getBeforeRevision().getFile(); } } return null; }
public void reportAppendableHistory( FilePath path, final VcsAppendableHistorySessionPartner partner) throws VcsException { final FilePath committedPath = ChangesUtil.getCommittedPath(myVcs.getProject(), path); final LogLoader logLoader; if (path.isNonLocal()) { logLoader = new RepositoryLoader(myVcs, path); } else { logLoader = new LocalLoader(myVcs, path); } try { logLoader.preliminary(); } catch (SVNCancelException e) { return; } catch (SVNException e) { throw new VcsException(e); } logLoader.initSupports15(); final MyHistorySession historySession = new MyHistorySession( Collections.<VcsFileRevision>emptyList(), committedPath, Boolean.TRUE.equals(logLoader.mySupport15), null); final Ref<Boolean> sessionReported = new Ref<Boolean>(); final ProgressIndicator indicator = ProgressManager.getInstance().getProgressIndicator(); if (indicator != null) { indicator.setText(SvnBundle.message("progress.text2.collecting.history", path.getName())); } final Consumer<VcsFileRevision> consumer = new Consumer<VcsFileRevision>() { public void consume(VcsFileRevision vcsFileRevision) { if (!Boolean.TRUE.equals(sessionReported.get())) { partner.reportCreatedEmptySession(historySession); sessionReported.set(true); } partner.acceptRevision(vcsFileRevision); } }; logLoader.setConsumer(consumer); logLoader.load(); logLoader.check(); }
@Override public int hashCode() { if (hashcode == 0) { hashcode = myPath != null ? myPath.hashCode() : 0; hashcode = 31 * hashcode + (myVcs != null ? myVcs.getName().hashCode() : 0); } return hashcode; }
private static void correctListForRevision( final ProjectLevelVcsManager plVcsManager, final ContentRevision revision, final SVNChangelistClient client, final String name) { if (revision != null) { final FilePath path = revision.getFile(); final AbstractVcs vcs = plVcsManager.getVcsFor(path); if (vcs != null && VCS_NAME.equals(vcs.getName())) { try { client.doAddToChangelist(new File[] {path.getIOFile()}, SVNDepth.EMPTY, name, null); } catch (SVNException e) { // left in default list } } } }
@Override protected String getName(FilePath path) { final String module = myModules.get(path.getVirtualFile()); if (module != null) { return module; } return super.getName(path); }
private String getDiffWindowTitle(final Change change) { if (change.isMoved() || change.isRenamed()) { final FilePath beforeFilePath = ChangesUtil.getBeforePath(change); final FilePath afterFilePath = ChangesUtil.getAfterPath(change); final String beforePath = beforeFilePath == null ? "" : beforeFilePath.getIOFile().getAbsolutePath(); final String afterPath = afterFilePath == null ? "" : afterFilePath.getIOFile().getAbsolutePath(); return SvnBundle.message( "action.Subversion.properties.difference.diff.for.move.title", beforePath, afterPath); } else { return SvnBundle.message( "action.Subversion.properties.difference.diff.title", ChangesUtil.getFilePath(change).getIOFile().getAbsolutePath()); } }
@Override protected boolean approximatelyHasRoots(final VcsContext dataContext) { final FilePath[] paths = dataContext.getSelectedFilePaths(); if (paths.length == 0) return false; final FileStatusManager fsm = FileStatusManager.getInstance(dataContext.getProject()); for (final FilePath path : paths) { VirtualFile file = path.getVirtualFile(); if (file == null) { continue; } FileStatus status = fsm.getStatus(file); if (isApplicableRoot(file, status, dataContext)) { return true; } } return false; }
@NotNull public static SvnContentRevision createRemote( @NotNull SvnVcs vcs, @NotNull FilePath file, @NotNull SVNRevision revision) { if (file.getFileType().isBinary()) { return new SvnBinaryContentRevision(vcs, file, revision, false); } return new SvnContentRevision(vcs, file, revision, false); }
private String modifyCheckinActionName(final VcsContext dataContext, String checkinActionName) { final FilePath[] roots = getRoots(dataContext); if (roots == null || roots.length == 0) return checkinActionName; final FilePath first = roots[0]; if (roots.length == 1) { if (first.isDirectory()) { return VcsBundle.message("action.name.checkin.directory", checkinActionName); } else { return VcsBundle.message("action.name.checkin.file", checkinActionName); } } else { if (first.isDirectory()) { return VcsBundle.message("action.name.checkin.directories", checkinActionName); } else { return VcsBundle.message("action.name.checkin.files", checkinActionName); } } }
@Override public boolean fileIsUnderVcs(FilePath path) { final ChangeListManager clManager = ChangeListManager.getInstance(myProject); final VirtualFile file = path.getVirtualFile(); if (file == null) { return false; } return !SvnStatusUtil.isIgnoredInAnySense(clManager, file) && !clManager.isUnversioned(file); }
@Override public SvnHistorySession createFromCachedData( Boolean aBoolean, @NotNull List<VcsFileRevision> revisions, @NotNull FilePath filePath, VcsRevisionNumber currentRevision) { return new SvnHistorySession( myVcs, revisions, filePath, aBoolean, currentRevision, false, !filePath.isNonLocal()); }