--- /dev/null
+/*
+ * Copyright 2000-2011 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.intellij.vcsUtil;
+
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.util.SystemInfo;
+import com.intellij.openapi.util.io.FileUtil;
+import com.intellij.openapi.vcs.FilePath;
+import com.intellij.openapi.vcs.changes.VcsDirtyScopeManager;
+import com.intellij.openapi.vfs.VfsUtil;
+import com.intellij.openapi.vfs.VirtualFile;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+/**
+ * @author Kirill Likhodedov
+ */
+public class VcsFileUtil {
+ /**
+ * If multiple paths are specified on the command line, this limit is used to split paths into chunks.
+ * The limit is less than OS limit to leave space to quoting, spaces, charset conversion, and commands arguments.
+ */
+ public static final int FILE_PATH_LIMIT = 7600;
+
+ /**
+ * Chunk paths on the command line
+ *
+ * @param files the paths to chunk
+ * @return the a list of list of relative paths
+ */
+ public static List<List<String>> chunkRelativePaths(List<String> files) {
+ ArrayList<List<String>> rc = new ArrayList<List<String>>();
+ int start = 0;
+ int size = 0;
+ int i = 0;
+ for (; i < files.size(); i++) {
+ String p = files.get(i);
+ if (size + p.length() > FILE_PATH_LIMIT) {
+ if (start == i) {
+ rc.add(files.subList(i, i + 1));
+ start = i + 1;
+ }
+ else {
+ rc.add(files.subList(start, i));
+ start = i;
+ }
+ size = 0;
+ }
+ else {
+ size += p.length();
+ }
+ }
+ if (start != files.size()) {
+ rc.add(files.subList(start, i));
+ }
+ return rc;
+ }
+
+ /**
+ * The chunk paths
+ *
+ * @param root the vcs root
+ * @param files the file list
+ * @return chunked relative paths
+ */
+ public static List<List<String>> chunkPaths(VirtualFile root, Collection<FilePath> files) {
+ return chunkRelativePaths(toRelativePaths(root, files));
+ }
+
+ /**
+ * The chunk paths
+ *
+ * @param root the vcs root
+ * @param files the file list
+ * @return chunked relative paths
+ */
+ public static List<List<String>> chunkFiles(VirtualFile root, Collection<VirtualFile> files) {
+ return chunkRelativePaths(toRelativeFiles(root, files));
+ }
+
+ public static String getRelativeFilePath(VirtualFile file, @NotNull final VirtualFile baseDir) {
+ return getRelativeFilePath(file.getPath(), baseDir);
+ }
+
+ public static String getRelativeFilePath(FilePath file, @NotNull final VirtualFile baseDir) {
+ return getRelativeFilePath(file.getPath(), baseDir);
+ }
+
+ public static String getRelativeFilePath(String file, @NotNull final VirtualFile baseDir) {
+ if (SystemInfo.isWindows) {
+ file = file.replace('\\', '/');
+ }
+ final String basePath = baseDir.getPath();
+ if (!file.startsWith(basePath)) {
+ return file;
+ }
+ else if (file.equals(basePath)) return ".";
+ return file.substring(baseDir.getPath().length() + 1);
+ }
+
+ /**
+ * Check if character is octal digit
+ *
+ * @param ch a character to test
+ * @return true if the octal digit, false otherwise
+ */
+ public static boolean isOctal(char ch) {
+ return '0' <= ch && ch <= '7';
+ }
+
+ /**
+ * Get relative path
+ *
+ * @param root a root path
+ * @param path a path to file (possibly deleted file)
+ * @return a relative path
+ * @throws IllegalArgumentException if path is not under root.
+ */
+ public static String relativePath(final VirtualFile root, FilePath path) {
+ return relativePath(VfsUtil.virtualToIoFile(root), path.getIOFile());
+ }
+
+ /**
+ * Get relative path
+ *
+ * @param root a root path
+ * @param path a path to file (possibly deleted file)
+ * @return a relative path
+ * @throws IllegalArgumentException if path is not under root.
+ */
+ public static String relativePath(final File root, FilePath path) {
+ return relativePath(root, path.getIOFile());
+ }
+
+ /**
+ * Get relative path
+ *
+ * @param root a root path
+ * @param file a virtual file
+ * @return a relative path
+ * @throws IllegalArgumentException if path is not under root.
+ */
+ public static String relativePath(final File root, VirtualFile file) {
+ return relativePath(root, VfsUtil.virtualToIoFile(file));
+ }
+
+ /**
+ * Get relative path
+ *
+ * @param root a root file
+ * @param file a virtual file
+ * @return a relative path
+ * @throws IllegalArgumentException if path is not under root.
+ */
+ public static String relativePath(final VirtualFile root, VirtualFile file) {
+ return relativePath(VfsUtil.virtualToIoFile(root), VfsUtil.virtualToIoFile(file));
+ }
+
+ /**
+ * Get relative path
+ *
+ * @param root a root file
+ * @param file a virtual file
+ * @return a relative path
+ * @throws IllegalArgumentException if path is not under root.
+ */
+ public static String relativeOrFullPath(final VirtualFile root, VirtualFile file) {
+ if (root == null) {
+ file.getPath();
+ }
+ return relativePath(VfsUtil.virtualToIoFile(root), VfsUtil.virtualToIoFile(file));
+ }
+
+ /**
+ * Get relative path
+ *
+ * @param root a root path
+ * @param path a path to file (possibly deleted file)
+ * @return a relative path
+ * @throws IllegalArgumentException if path is not under root.
+ */
+ public static String relativePath(final File root, File path) {
+ String rc = FileUtil.getRelativePath(root, path);
+ if (rc == null) {
+ throw new IllegalArgumentException("The file " + path + " cannot be made relative to " + root);
+ }
+ return rc.replace(File.separatorChar, '/');
+ }
+
+ /**
+ * Covert list of files to relative paths
+ *
+ * @param root a vcs root
+ * @param filePaths a parameters to convert
+ * @return a list of relative paths
+ * @throws IllegalArgumentException if some path is not under root.
+ */
+ public static List<String> toRelativePaths(@NotNull VirtualFile root, @NotNull final Collection<FilePath> filePaths) {
+ ArrayList<String> rc = new ArrayList<String>(filePaths.size());
+ for (FilePath path : filePaths) {
+ rc.add(relativePath(root, path));
+ }
+ return rc;
+ }
+
+ /**
+ * Covert list of files to relative paths
+ *
+ * @param root a vcs root
+ * @param files a parameters to convert
+ * @return a list of relative paths
+ * @throws IllegalArgumentException if some path is not under root.
+ */
+ public static List<String> toRelativeFiles(@NotNull VirtualFile root, @NotNull final Collection<VirtualFile> files) {
+ ArrayList<String> rc = new ArrayList<String>(files.size());
+ for (VirtualFile file : files) {
+ rc.add(relativePath(root, file));
+ }
+ return rc;
+ }
+
+ /**
+ * Refresh files
+ *
+ * @param project a project
+ * @param affectedFiles affected files and directories
+ */
+ public static void refreshFiles(@NotNull final Project project, @NotNull final Collection<VirtualFile> affectedFiles) {
+ final VcsDirtyScopeManager dirty = VcsDirtyScopeManager.getInstance(project);
+ for (VirtualFile file : affectedFiles) {
+ if (!file.isValid()) {
+ continue;
+ }
+ file.refresh(false, true);
+ if (file.isDirectory()) {
+ dirty.dirDirtyRecursively(file);
+ }
+ else {
+ dirty.fileDirty(file);
+ }
+ }
+ }
+
+ /**
+ * Refresh files
+ *
+ * @param project a project
+ * @param affectedFiles affected files and directories
+ */
+ public static void markFilesDirty(@NotNull final Project project, @NotNull final Collection<VirtualFile> affectedFiles) {
+ final VcsDirtyScopeManager dirty = VcsDirtyScopeManager.getInstance(project);
+ for (VirtualFile file : affectedFiles) {
+ if (!file.isValid()) {
+ continue;
+ }
+ if (file.isDirectory()) {
+ dirty.dirDirtyRecursively(file);
+ }
+ else {
+ dirty.fileDirty(file);
+ }
+ }
+ }
+
+ /**
+ * Mark files dirty
+ *
+ * @param project a project
+ * @param affectedFiles affected files and directories
+ */
+ public static void markFilesDirty(Project project, List<FilePath> affectedFiles) {
+ final VcsDirtyScopeManager dirty = VcsDirtyScopeManager.getInstance(project);
+ for (FilePath file : affectedFiles) {
+ if (file.isDirectory()) {
+ dirty.dirDirtyRecursively(file);
+ }
+ else {
+ dirty.fileDirty(file);
+ }
+ }
+ }
+
+ /**
+ * Refresh files
+ *
+ * @param project a project
+ * @param affectedFiles affected files and directories
+ */
+ public static void refreshFiles(Project project, List<FilePath> affectedFiles) {
+ final VcsDirtyScopeManager dirty = VcsDirtyScopeManager.getInstance(project);
+ for (FilePath file : affectedFiles) {
+ VirtualFile vFile = VcsUtil.getVirtualFile(file.getIOFile());
+ if (vFile != null) {
+ vFile.refresh(false, true);
+ }
+ if (file.isDirectory()) {
+ dirty.dirDirtyRecursively(file);
+ }
+ else {
+ dirty.fileDirty(file);
+ }
+ }
+ }
+
+ /**
+ * The get the possible base for the path. It tries to find the parent for the provided path.
+ *
+ * @param file the file to get base for
+ * @param path the path to to check
+ * @return the file base
+ */
+ @Nullable
+ public static VirtualFile getPossibleBase(final VirtualFile file, final String... path) {
+ if (file == null || path.length == 0) return null;
+
+ VirtualFile current = file;
+ final List<VirtualFile> backTrace = new ArrayList<VirtualFile>();
+ int idx = path.length - 1;
+ while (current != null) {
+ if (SystemInfo.isFileSystemCaseSensitive ? current.getName().equals(path[idx]) : current.getName().equalsIgnoreCase(path[idx])) {
+ if (idx == 0) {
+ return current;
+ }
+ -- idx;
+ } else if (idx != path.length - 1) {
+ int diff = path.length - 1 - idx - 1;
+ for (int i = 0; i < diff; i++) {
+ current = backTrace.remove(backTrace.size() - 1);
+ }
+ idx = path.length - 1;
+ continue;
+ }
+ backTrace.add(current);
+ current = current.getParent();
+ }
+
+ return null;
+ }
+}
import com.intellij.openapi.vcs.VcsException;
import com.intellij.openapi.vcs.changes.BinaryContentRevision;
import com.intellij.openapi.vfs.VirtualFile;
+import com.intellij.vcsUtil.VcsFileUtil;
import git4idea.commands.GitFileUtils;
import org.jetbrains.annotations.NotNull;
return null;
}
final VirtualFile root = GitUtil.getGitRoot(myFile);
- return GitFileUtils.getFileContent(myProject, root, myRevision.getRev(), GitUtil.relativePath(root, myFile));
+ return GitFileUtils.getFileContent(myProject, root, myRevision.getRev(), VcsFileUtil.relativePath(root, myFile));
}
}
import com.intellij.openapi.vcs.history.VcsRevisionNumber;
import com.intellij.openapi.vfs.CharsetToolkit;
import com.intellij.openapi.vfs.VirtualFile;
+import com.intellij.vcsUtil.VcsFileUtil;
import com.intellij.vcsUtil.VcsUtil;
import git4idea.commands.GitFileUtils;
import git4idea.history.wholeTree.GitBinaryMultipleContentsRevision;
return null;
}
VirtualFile root = GitUtil.getGitRoot(myFile);
- byte[] result = GitFileUtils.getFileContent(myProject, root, myRevision.getRev(), GitUtil.relativePath(root, myFile));
+ byte[] result = GitFileUtils.getFileContent(myProject, root, myRevision.getRev(), VcsFileUtil.relativePath(root, myFile));
if (myCharset == null) {
myCharset = myFile.getCharset(myProject);
}
import com.intellij.openapi.vcs.history.VcsFileRevisionEx;
import com.intellij.openapi.vcs.history.VcsRevisionNumber;
import com.intellij.openapi.vfs.VirtualFile;
+import com.intellij.vcsUtil.VcsFileUtil;
import git4idea.commands.GitFileUtils;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public synchronized void loadContent() throws VcsException {
final VirtualFile root = GitUtil.getGitRoot(path);
if (content == null) {
- content = GitFileUtils.getFileContent(project, root, revision.getRev(), GitUtil.relativePath(root, path));
+ content = GitFileUtils.getFileContent(project, root, revision.getRev(), VcsFileUtil.relativePath(root, path));
if (content == null) {
content = new byte[0];
}
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.project.Project;
-import com.intellij.openapi.util.SystemInfo;
-import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.vcs.FilePath;
import com.intellij.openapi.vcs.ProjectLevelVcsManager;
import com.intellij.openapi.vcs.VcsException;
-import com.intellij.openapi.vcs.changes.VcsDirtyScopeManager;
import com.intellij.openapi.vcs.versionBrowser.CommittedChangeList;
import com.intellij.openapi.vcs.vfs.AbstractVcsVirtualFile;
import com.intellij.openapi.vfs.LocalFileSystem;
-import com.intellij.openapi.vfs.VfsUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.util.Consumer;
+import com.intellij.vcsUtil.VcsFileUtil;
import com.intellij.vcsUtil.VcsUtil;
import git4idea.changes.GitChangeUtils;
import git4idea.commands.GitCommand;
return result;
}
- public static String getRelativeFilePath(VirtualFile file, @NotNull final VirtualFile baseDir) {
- return getRelativeFilePath(file.getPath(), baseDir);
- }
-
- public static String getRelativeFilePath(FilePath file, @NotNull final VirtualFile baseDir) {
- return getRelativeFilePath(file.getPath(), baseDir);
- }
-
- public static String getRelativeFilePath(String file, @NotNull final VirtualFile baseDir) {
- if (SystemInfo.isWindows) {
- file = file.replace('\\', '/');
- }
- final String basePath = baseDir.getPath();
- if (!file.startsWith(basePath)) {
- return file;
- }
- else if (file.equals(basePath)) return ".";
- return file.substring(baseDir.getPath().length() + 1);
- }
-
/**
* Sort files by vcs root
*
return rc;
}
- /**
- * Unescape path returned by the Git
- *
- * @param path a path to unescape
- * @return unescaped path
- * @throws VcsException if the path in invalid
- */
- public static String unescapePath(String path) throws VcsException {
- final int l = path.length();
- StringBuilder rc = new StringBuilder(l);
- for (int i = 0; i < path.length(); i++) {
- char c = path.charAt(i);
- if (c == '\\') {
- //noinspection AssignmentToForLoopParameter
- i++;
- if (i >= l) {
- throw new VcsException("Unterminated escape sequence in the path: " + path);
- }
- final char e = path.charAt(i);
- switch (e) {
- case '\\':
- rc.append('\\');
- break;
- case 't':
- rc.append('\t');
- break;
- case 'n':
- rc.append('\n');
- break;
- default:
- if (isOctal(e)) {
- // collect sequence of characters as a byte array.
- // count bytes first
- int n = 0;
- for (int j = i; j < l;) {
- if (isOctal(path.charAt(j))) {
- n++;
- for (int k = 0; k < 3 && j < l && isOctal(path.charAt(j)); k++) {
- //noinspection AssignmentToForLoopParameter
- j++;
- }
- }
- if (j + 1 >= l || path.charAt(j) != '\\' || !isOctal(path.charAt(j + 1))) {
- break;
- }
- //noinspection AssignmentToForLoopParameter
- j++;
- }
- // convert to byte array
- byte[] b = new byte[n];
- n = 0;
- while (i < l) {
- if (isOctal(path.charAt(i))) {
- int code = 0;
- for (int k = 0; k < 3 && i < l && isOctal(path.charAt(i)); k++) {
- code = code * 8 + (path.charAt(i) - '0');
- //noinspection AssignmentToForLoopParameter
- i++;
- }
- b[n++] = (byte)code;
- }
- if (i + 1 >= l || path.charAt(i) != '\\' || !isOctal(path.charAt(i + 1))) {
- break;
- }
- //noinspection AssignmentToForLoopParameter
- i++;
- }
- assert n == b.length;
- // add them to string
- final String encoding = GitConfigUtil.getFileNameEncoding();
- try {
- rc.append(new String(b, encoding));
- }
- catch (UnsupportedEncodingException e1) {
- throw new IllegalStateException("The file name encoding is unsuported: " + encoding);
- }
- }
- else {
- throw new VcsException("Unknown escape sequence '\\" + path.charAt(i) + "' in the path: " + path);
- }
- }
- }
- else {
- rc.append(c);
- }
- }
- return rc.toString();
- }
-
- /**
- * Check if character is octal digit
- *
- * @param ch a character to test
- * @return true if the octal digit, false otherwise
- */
- private static boolean isOctal(char ch) {
- return '0' <= ch && ch <= '7';
- }
-
/**
* Parse UNIX timestamp as it is returned by the git
*
return gitRootOrNull(vFile) != null;
}
- /**
- * Get relative path
- *
- * @param root a root path
- * @param path a path to file (possibly deleted file)
- * @return a relative path
- * @throws IllegalArgumentException if path is not under root.
- */
- public static String relativePath(final VirtualFile root, FilePath path) {
- return relativePath(VfsUtil.virtualToIoFile(root), path.getIOFile());
- }
-
-
- /**
- * Get relative path
- *
- * @param root a root path
- * @param path a path to file (possibly deleted file)
- * @return a relative path
- * @throws IllegalArgumentException if path is not under root.
- */
- public static String relativePath(final File root, FilePath path) {
- return relativePath(root, path.getIOFile());
- }
-
- /**
- * Get relative path
- *
- * @param root a root path
- * @param file a virtual file
- * @return a relative path
- * @throws IllegalArgumentException if path is not under root.
- */
- public static String relativePath(final File root, VirtualFile file) {
- return relativePath(root, VfsUtil.virtualToIoFile(file));
- }
-
- /**
- * Get relative path
- *
- * @param root a root file
- * @param file a virtual file
- * @return a relative path
- * @throws IllegalArgumentException if path is not under root.
- */
- public static String relativePath(final VirtualFile root, VirtualFile file) {
- return relativePath(VfsUtil.virtualToIoFile(root), VfsUtil.virtualToIoFile(file));
- }
-
- /**
- * Get relative path
- *
- * @param root a root file
- * @param file a virtual file
- * @return a relative path
- * @throws IllegalArgumentException if path is not under root.
- */
- public static String relativeOrFullPath(final VirtualFile root, VirtualFile file) {
- if (root == null) {
- file.getPath();
- }
- return relativePath(VfsUtil.virtualToIoFile(root), VfsUtil.virtualToIoFile(file));
- }
-
- /**
- * Get relative path
- *
- * @param root a root path
- * @param path a path to file (possibly deleted file)
- * @return a relative path
- * @throws IllegalArgumentException if path is not under root.
- */
- public static String relativePath(final File root, File path) {
- String rc = FileUtil.getRelativePath(root, path);
- if (rc == null) {
- throw new IllegalArgumentException("The file " + path + " cannot be made relative to " + root);
- }
- return rc.replace(File.separatorChar, '/');
- }
-
- /**
- * Covert list of files to relative paths
- *
- * @param root a vcs root
- * @param filePaths a parameters to convert
- * @return a list of relative paths
- * @throws IllegalArgumentException if some path is not under root.
- */
- public static List<String> toRelativePaths(@NotNull VirtualFile root, @NotNull final Collection<FilePath> filePaths) {
- ArrayList<String> rc = new ArrayList<String>(filePaths.size());
- for (FilePath path : filePaths) {
- rc.add(relativePath(root, path));
- }
- return rc;
- }
-
- /**
- * Covert list of files to relative paths
- *
- * @param root a vcs root
- * @param files a parameters to convert
- * @return a list of relative paths
- * @throws IllegalArgumentException if some path is not under root.
- */
- public static List<String> toRelativeFiles(@NotNull VirtualFile root, @NotNull final Collection<VirtualFile> files) {
- ArrayList<String> rc = new ArrayList<String>(files.size());
- for (VirtualFile file : files) {
- rc.add(relativePath(root, file));
- }
- return rc;
- }
-
- /**
- * Refresh files
- *
- * @param project a project
- * @param affectedFiles affected files and directories
- */
- public static void refreshFiles(@NotNull final Project project, @NotNull final Collection<VirtualFile> affectedFiles) {
- final VcsDirtyScopeManager dirty = VcsDirtyScopeManager.getInstance(project);
- for (VirtualFile file : affectedFiles) {
- if (!file.isValid()) {
- continue;
- }
- file.refresh(false, true);
- if (file.isDirectory()) {
- dirty.dirDirtyRecursively(file);
- }
- else {
- dirty.fileDirty(file);
- }
- }
- }
-
- /**
- * Refresh files
- *
- * @param project a project
- * @param affectedFiles affected files and directories
- */
- public static void markFilesDirty(@NotNull final Project project, @NotNull final Collection<VirtualFile> affectedFiles) {
- final VcsDirtyScopeManager dirty = VcsDirtyScopeManager.getInstance(project);
- for (VirtualFile file : affectedFiles) {
- if (!file.isValid()) {
- continue;
- }
- if (file.isDirectory()) {
- dirty.dirDirtyRecursively(file);
- }
- else {
- dirty.fileDirty(file);
- }
- }
- }
-
-
- /**
- * Mark files dirty
- *
- * @param project a project
- * @param affectedFiles affected files and directories
- */
- public static void markFilesDirty(Project project, List<FilePath> affectedFiles) {
- final VcsDirtyScopeManager dirty = VcsDirtyScopeManager.getInstance(project);
- for (FilePath file : affectedFiles) {
- if (file.isDirectory()) {
- dirty.dirDirtyRecursively(file);
- }
- else {
- dirty.fileDirty(file);
- }
- }
- }
-
- /**
- * Refresh files
- *
- * @param project a project
- * @param affectedFiles affected files and directories
- */
- public static void refreshFiles(Project project, List<FilePath> affectedFiles) {
- final VcsDirtyScopeManager dirty = VcsDirtyScopeManager.getInstance(project);
- for (FilePath file : affectedFiles) {
- VirtualFile vFile = VcsUtil.getVirtualFile(file.getIOFile());
- if (vFile != null) {
- vFile.refresh(false, true);
- }
- if (file.isDirectory()) {
- dirty.dirDirtyRecursively(file);
- }
- else {
- dirty.fileDirty(file);
- }
- }
- }
/**
* Return committer name based on author name and committer name
return String.format("%015x%x", (rev >>> 4), rev & 0xF);
}
- /**
- * The get the possible base for the path. It tries to find the parent for the provided path.
- *
- * @param file the file to get base for
- * @param path the path to to check
- * @return the file base
- */
- @Nullable
- public static VirtualFile getPossibleBase(final VirtualFile file, final String... path) {
- if (file == null || path.length == 0) return null;
-
- VirtualFile current = file;
- final List<VirtualFile> backTrace = new ArrayList<VirtualFile>();
- int idx = path.length - 1;
- while (current != null) {
- if (SystemInfo.isFileSystemCaseSensitive ? current.getName().equals(path[idx]) : current.getName().equalsIgnoreCase(path[idx])) {
- if (idx == 0) {
- return current;
- }
- -- idx;
- } else if (idx != path.length - 1) {
- int diff = path.length - 1 - idx - 1;
- for (int i = 0; i < diff; i++) {
- current = backTrace.remove(backTrace.size() - 1);
- }
- idx = path.length - 1;
- continue;
- }
- backTrace.add(current);
- current = current.getParent();
- }
-
- return null;
- }
-
public static void getLocalCommittedChanges(final Project project,
final VirtualFile root,
final Consumer<GitSimpleHandler> parametersSpecifier,
}
/**
- * Cast or wrap exception into a vcs exception, errors and runtime exceptions are just thrown throw.
+ * Unescape path returned by the Git
*
- * @param t an exception to throw
- * @return a wrapped exception
+ * @param path a path to unescape
+ * @return unescaped path
+ * @throws com.intellij.openapi.vcs.VcsException if the path in invalid
*/
- public static VcsException rethrowVcsException(Throwable t) {
- if (t instanceof Error) {
- throw (Error)t;
- }
- if (t instanceof RuntimeException) {
- throw (RuntimeException)t;
- }
- if (t instanceof VcsException) {
- return (VcsException)t;
+ public static String unescapePath(String path) throws VcsException {
+ final int l = path.length();
+ StringBuilder rc = new StringBuilder(l);
+ for (int i = 0; i < path.length(); i++) {
+ char c = path.charAt(i);
+ if (c == '\\') {
+ //noinspection AssignmentToForLoopParameter
+ i++;
+ if (i >= l) {
+ throw new VcsException("Unterminated escape sequence in the path: " + path);
+ }
+ final char e = path.charAt(i);
+ switch (e) {
+ case '\\':
+ rc.append('\\');
+ break;
+ case 't':
+ rc.append('\t');
+ break;
+ case 'n':
+ rc.append('\n');
+ break;
+ default:
+ if (VcsFileUtil.isOctal(e)) {
+ // collect sequence of characters as a byte array.
+ // count bytes first
+ int n = 0;
+ for (int j = i; j < l;) {
+ if (VcsFileUtil.isOctal(path.charAt(j))) {
+ n++;
+ for (int k = 0; k < 3 && j < l && VcsFileUtil.isOctal(path.charAt(j)); k++) {
+ //noinspection AssignmentToForLoopParameter
+ j++;
+ }
+ }
+ if (j + 1 >= l || path.charAt(j) != '\\' || !VcsFileUtil.isOctal(path.charAt(j + 1))) {
+ break;
+ }
+ //noinspection AssignmentToForLoopParameter
+ j++;
+ }
+ // convert to byte array
+ byte[] b = new byte[n];
+ n = 0;
+ while (i < l) {
+ if (VcsFileUtil.isOctal(path.charAt(i))) {
+ int code = 0;
+ for (int k = 0; k < 3 && i < l && VcsFileUtil.isOctal(path.charAt(i)); k++) {
+ code = code * 8 + (path.charAt(i) - '0');
+ //noinspection AssignmentToForLoopParameter
+ i++;
+ }
+ b[n++] = (byte)code;
+ }
+ if (i + 1 >= l || path.charAt(i) != '\\' || !VcsFileUtil.isOctal(path.charAt(i + 1))) {
+ break;
+ }
+ //noinspection AssignmentToForLoopParameter
+ i++;
+ }
+ assert n == b.length;
+ // add them to string
+ final String encoding = GitConfigUtil.getFileNameEncoding();
+ try {
+ rc.append(new String(b, encoding));
+ }
+ catch (UnsupportedEncodingException e1) {
+ throw new IllegalStateException("The file name encoding is unsuported: " + encoding);
+ }
+ }
+ else {
+ throw new VcsException("Unknown escape sequence '\\" + path.charAt(i) + "' in the path: " + path);
+ }
+ }
+ }
+ else {
+ rc.append(c);
+ }
}
- return new VcsException(t.getMessage(), t);
+ return rc.toString();
}
}
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.util.Consumer;
import com.intellij.util.ui.UIUtil;
-import git4idea.GitUtil;
+import com.intellij.vcsUtil.VcsFileUtil;
import git4idea.GitVcs;
import git4idea.ui.GitUIUtil;
import org.jetbrains.annotations.NotNull;
vcs.runInBackground(new Task.Backgroundable(project, getActionName()) {
public void run(@NotNull ProgressIndicator indicator) {
- GitUtil.refreshFiles(project, Arrays.asList(affectedFiles));
+ VcsFileUtil.refreshFiles(project, Arrays.asList(affectedFiles));
UIUtil.invokeLaterIfNeeded(new Runnable() {
public void run() {
GitUIUtil.showOperationErrors(project, exceptions, actionName);
public void run(@NotNull ProgressIndicator indicator) {
action.consume(indicator);
- GitUtil.refreshFiles(project, Arrays.asList(affectedFiles));
+ VcsFileUtil.refreshFiles(project, Arrays.asList(affectedFiles));
UIUtil.invokeLaterIfNeeded(new Runnable() {
public void run() {
GitUIUtil.showOperationErrors(project, exceptions, getActionName());
import com.intellij.openapi.vcs.VcsDirectoryMapping;
import com.intellij.openapi.vcs.VcsException;
import com.intellij.openapi.vfs.VirtualFile;
+import com.intellij.vcsUtil.VcsFileUtil;
import git4idea.Git;
import git4idea.GitUtil;
import git4idea.GitVcs;
}
vcs.setDirectoryMappings(vcsDirectoryMappings);
vcs.updateActiveVcss();
- GitUtil.refreshFiles(project, Collections.singleton(root));
+ VcsFileUtil.refreshFiles(project, Collections.singleton(root));
}
}
import com.intellij.openapi.vcs.TransactionRunnable;
import com.intellij.openapi.vcs.VcsException;
import com.intellij.openapi.vfs.VirtualFile;
+import com.intellij.vcsUtil.VcsFileUtil;
import git4idea.GitUtil;
import git4idea.GitVcs;
import git4idea.i18n.GitBundle;
catch (VcsException e) {
exceptions.add(e);
}
- GitUtil.refreshFiles(project, affectedRoots);
+ VcsFileUtil.refreshFiles(project, affectedRoots);
for (TransactionRunnable task : myDelayedTasks) {
task.run(exceptions);
}
import com.intellij.util.PairConsumer;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.ui.UIUtil;
+import com.intellij.vcsUtil.VcsFileUtil;
import com.intellij.vcsUtil.VcsUtil;
import git4idea.GitUtil;
import git4idea.commands.GitCommand;
boolean nextCommitAmend)
throws VcsException {
boolean amend = nextCommitAmend;
- for (List<String> paths : GitFileUtils.chunkPaths(root, files)) {
+ for (List<String> paths : VcsFileUtil.chunkPaths(root, files)) {
GitSimpleHandler handler = new GitSimpleHandler(project, root, GitCommand.COMMIT);
handler.setNoSSH(true);
if (amend) {
import com.intellij.util.text.DateFormatUtil;
import com.intellij.util.ui.UIUtil;
import com.intellij.util.ui.tree.TreeUtil;
+import com.intellij.vcsUtil.VcsFileUtil;
import git4idea.GitBranch;
import git4idea.GitRevisionNumber;
-import git4idea.GitUtil;
import git4idea.GitVcs;
import git4idea.actions.GitRepositoryAction;
import git4idea.actions.GitShowAllSubmittedFilesAction;
notifyMessage(myProject, "Failed to rebase", null, NotificationType.ERROR, true, exceptions);
return;
}
- GitUtil.refreshFiles(myProject, rebaseInfo.roots);
+ VcsFileUtil.refreshFiles(myProject, rebaseInfo.roots);
}
}
notifyMessage(myProject, "Failed to push", "Update project and push again", NotificationType.ERROR, true, pushExceptions);
GitUIUtil.showOperationErrors(myProject, exceptions, "git rebase");
}
refreshTree(false, rebaseInfo.uncheckedCommits);
- GitUtil.refreshFiles(myProject, rebaseInfo.roots);
+ VcsFileUtil.refreshFiles(myProject, rebaseInfo.roots);
}
private boolean executeRebase(final List<VcsException> exceptions, RebaseInfo rebaseInfo) {
import com.intellij.openapi.wm.impl.status.TextPanel;
import com.intellij.ui.awt.RelativePoint;
import com.intellij.util.ui.UIUtil;
+import com.intellij.vcsUtil.VcsFileUtil;
import git4idea.GitUtil;
import git4idea.GitVcs;
import git4idea.commands.GitCommand;
GitLineHandler h = new GitLineHandler(myProject, root, GitCommand.FETCH);
h.addParameters("--all", "-v");
final Collection<VcsException> e = GitHandlerUtil
- .doSynchronouslyWithExceptions(h, indicator, "Fetching all for " + GitUtil.relativePath(myProject.getBaseDir(), root));
+ .doSynchronouslyWithExceptions(h, indicator, "Fetching all for " + VcsFileUtil.relativePath(myProject.getBaseDir(), root));
exceptions.addAll(e);
}
}
import com.intellij.openapi.vcs.FilePath;
import com.intellij.openapi.vcs.VcsException;
import com.intellij.openapi.vfs.VirtualFile;
-import git4idea.GitUtil;
+import com.intellij.vcsUtil.VcsFileUtil;
import org.jetbrains.annotations.Nullable;
-import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
* File utilities for the git
*/
public class GitFileUtils {
- /**
- * If multiple paths are specified on the command line, this limit is used to split paths into chunks.
- * The limit is less than OS limit to leave space to quoting, spaces, charset conversion, and commands arguments.
- */
- public static final int FILE_PATH_LIMIT = 7600;
/**
* The private constructor for static utility class
// do nothing
}
- /**
- * Chunk paths on the command line
- *
- * @param files the paths to chunk
- * @return the a list of list of relative paths
- */
- public static List<List<String>> chunkRelativePaths(List<String> files) {
- ArrayList<List<String>> rc = new ArrayList<List<String>>();
- int start = 0;
- int size = 0;
- int i = 0;
- for (; i < files.size(); i++) {
- String p = files.get(i);
- if (size + p.length() > FILE_PATH_LIMIT) {
- if (start == i) {
- rc.add(files.subList(i, i + 1));
- start = i + 1;
- }
- else {
- rc.add(files.subList(start, i));
- start = i;
- }
- size = 0;
- }
- else {
- size += p.length();
- }
- }
- if (start != files.size()) {
- rc.add(files.subList(start, i));
- }
- return rc;
- }
-
- /**
- * The chunk paths
- *
- * @param root the vcs root
- * @param files the file list
- * @return chunked relative paths
- */
- public static List<List<String>> chunkPaths(VirtualFile root, Collection<FilePath> files) {
- return chunkRelativePaths(GitUtil.toRelativePaths(root, files));
- }
-
- /**
- * The chunk paths
- *
- * @param root the vcs root
- * @param files the file list
- * @return chunked relative paths
- */
- public static List<List<String>> chunkFiles(VirtualFile root, Collection<VirtualFile> files) {
- return chunkRelativePaths(GitUtil.toRelativeFiles(root, files));
- }
-
/**
* Delete files
*
public static void delete(Project project, VirtualFile root, Collection<FilePath> files, String... additionalOptions)
throws VcsException {
- for (List<String> paths : chunkPaths(root, files)) {
+ for (List<String> paths : VcsFileUtil.chunkPaths(root, files)) {
GitSimpleHandler handler = new GitSimpleHandler(project, root, GitCommand.RM);
handler.addParameters(additionalOptions);
handler.endOptions();
* @throws VcsException in case of git problem
*/
public static void deleteFiles(Project project, VirtualFile root, List<VirtualFile> files) throws VcsException {
- for (List<String> paths : chunkFiles(root, files)) {
+ for (List<String> paths : VcsFileUtil.chunkFiles(root, files)) {
GitSimpleHandler handler = new GitSimpleHandler(project, root, GitCommand.RM);
handler.endOptions();
handler.addParameters(paths);
* @throws VcsException in case of git problem
*/
public static void addFiles(Project project, VirtualFile root, Collection<VirtualFile> files) throws VcsException {
- for (List<String> paths : chunkFiles(root, files)) {
+ for (List<String> paths : VcsFileUtil.chunkFiles(root, files)) {
GitSimpleHandler handler = new GitSimpleHandler(project, root, GitCommand.ADD);
handler.endOptions();
handler.addParameters(paths);
* @throws VcsException in case of git problem
*/
public static void addPaths(Project project, VirtualFile root, Collection<FilePath> files) throws VcsException {
- for (List<String> paths : chunkPaths(root, files)) {
+ for (List<String> paths : VcsFileUtil.chunkPaths(root, files)) {
GitSimpleHandler handler = new GitSimpleHandler(project, root, GitCommand.ADD);
handler.endOptions();
handler.addParameters(paths);
return result;
}
- /**
- * Returns the GitFileRevision for given parameters.
- * @param revisionOrBranch full hash of the revision, or branch name, or tag name - any will do.
- * @param loadContent should the content be preloaded in the returned VcsFileRevision.
- * @return VcsFileRevision for the given parameters.
- */
- //@Nullable
- //public static VcsFileRevision getFileRevision(Project project, VirtualFile vcsRoot, String revisionOrBranch, String relativePath, boolean loadContent) {
- // GitSimpleHandler h = new GitSimpleHandler(project, vcsRoot, GitCommand.SHOW);
- // h.setNoSSH(true);
- // h.setSilent(true);
- // h.addParameters(revisionOrBranch + ":" + relativePath);
- //
- // if (!loadContent) {
- // h.addParameters("--name-only");
- // }
- //
- //}
-
}
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.util.EventDispatcher;
import com.intellij.util.Processor;
-import git4idea.GitUtil;
+import com.intellij.vcsUtil.VcsFileUtil;
import git4idea.GitVcs;
import git4idea.config.GitVcsApplicationSettings;
import git4idea.config.GitVcsSettings;
public void addRelativePaths(@NotNull final Collection<FilePath> filePaths) {
checkNotStarted();
for (FilePath path : filePaths) {
- myCommandLine.addParameter(GitUtil.relativePath(myWorkingDirectory, path));
+ myCommandLine.addParameter(VcsFileUtil.relativePath(myWorkingDirectory, path));
}
}
public void addRelativePathsForFiles(@NotNull final Collection<File> files) {
checkNotStarted();
for (File file : files) {
- myCommandLine.addParameter(GitUtil.relativePath(myWorkingDirectory, file));
+ myCommandLine.addParameter(VcsFileUtil.relativePath(myWorkingDirectory, file));
}
}
public void addRelativeFiles(@NotNull final Collection<VirtualFile> files) {
checkNotStarted();
for (VirtualFile file : files) {
- myCommandLine.addParameter(GitUtil.relativePath(myWorkingDirectory, file));
+ myCommandLine.addParameter(VcsFileUtil.relativePath(myWorkingDirectory, file));
}
}
* @return true if the command line is too big
*/
public boolean isLargeCommandLine() {
- return myCommandLine.getCommandLineString().length() > GitFileUtils.FILE_PATH_LIMIT;
+ return myCommandLine.getCommandLineString().length() > VcsFileUtil.FILE_PATH_LIMIT;
}
public void runInCurrentThread(Runnable postStartAction) {
import com.intellij.openapi.vcs.TreeDiffProvider;
import com.intellij.openapi.vcs.VcsException;
import com.intellij.openapi.vfs.VirtualFile;
+import com.intellij.vcsUtil.VcsFileUtil;
import com.intellij.vcsUtil.VcsUtil;
import git4idea.GitBranchesSearcher;
import git4idea.changes.GitChangeUtils;
import git4idea.commands.GitCommand;
-import git4idea.commands.GitFileUtils;
import git4idea.commands.GitSimpleHandler;
import git4idea.commands.StringScanner;
for (String path : paths) {
files.add(VcsUtil.getFilePath(path));
}
- for (List<String> pathList : GitFileUtils.chunkPaths(vcsRoot, files)) {
+ for (List<String> pathList : VcsFileUtil.chunkPaths(vcsRoot, files)) {
GitSimpleHandler handler = new GitSimpleHandler(myProject, vcsRoot, GitCommand.DIFF);
handler.addParameters("--name-status", "--diff-filter=ADCRUX", "-M", "HEAD..." + searcher.getRemote().getFullName());
handler.setNoSSH(true);
import com.intellij.openapi.vcs.merge.MergeSession;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.util.ui.ColumnInfo;
+import com.intellij.vcsUtil.VcsFileUtil;
import com.intellij.vcsUtil.VcsRunnable;
import com.intellij.vcsUtil.VcsUtil;
import git4idea.GitFileRevision;
}
}
for (VirtualFile f : files) {
- String path = GitUtil.relativePath(root, f);
+ String path = VcsFileUtil.relativePath(root, f);
Conflict c = cs.get(path);
assert c != null : "The conflict not found for the file: " + f.getPath() + "(" + path + ")";
c.myFile = f;
import com.intellij.openapi.vcs.rollback.RollbackProgressListener;
import com.intellij.openapi.vfs.LocalFileSystem;
import com.intellij.openapi.vfs.VirtualFile;
+import com.intellij.vcsUtil.VcsFileUtil;
import git4idea.GitUtil;
import git4idea.commands.GitCommand;
import git4idea.commands.GitFileUtils;
* @throws VcsException Id it breaks.
*/
public void revert(final VirtualFile root, final List<FilePath> files) throws VcsException {
- for (List<String> paths : GitFileUtils.chunkPaths(root, files)) {
+ for (List<String> paths : VcsFileUtil.chunkPaths(root, files)) {
GitSimpleHandler handler = new GitSimpleHandler(myProject, root, GitCommand.CHECKOUT);
handler.setNoSSH(true);
handler.addParameters("HEAD");
import com.intellij.ui.*;
import com.intellij.util.ui.UIUtil;
import com.intellij.util.ui.tree.TreeUtil;
+import com.intellij.vcsUtil.VcsFileUtil;
import git4idea.DialogManager;
import git4idea.GitUtil;
import git4idea.config.GitVcsSettings;
if (i != null) {
r.setIcon(i);
}
- r.append(GitUtil.getRelativeFilePath(file, parent), SimpleTextAttributes.REGULAR_ATTRIBUTES, true);
+ r.append(VcsFileUtil.getRelativeFilePath(file, parent), SimpleTextAttributes.REGULAR_ATTRIBUTES, true);
}
else {
// the vcs root node
import com.intellij.openapi.vcs.ProjectLevelVcsManager;
import com.intellij.openapi.vfs.*;
import com.intellij.util.containers.HashSet;
+import com.intellij.vcsUtil.VcsFileUtil;
import git4idea.GitUtil;
import git4idea.GitVcs;
import org.jetbrains.annotations.Nullable;
}
return;
}
- VirtualFile base = GitUtil.getPossibleBase(file, ".git", "config");
+ VirtualFile base = VcsFileUtil.getPossibleBase(file, ".git", "config");
if (base != null) {
boolean reported;
synchronized (myReportedRoots) {
import com.intellij.openapi.vfs.*;
import com.intellij.util.containers.HashMap;
import com.intellij.util.containers.HashSet;
-import git4idea.GitUtil;
+import com.intellij.vcsUtil.VcsFileUtil;
import git4idea.GitVcs;
import git4idea.config.GitConfigUtil;
import org.jetbrains.annotations.NotNull;
}
return;
}
- final VirtualFile base = GitUtil.getPossibleBase(file, LOCAL_EXCLUDE_ARRAY);
+ final VirtualFile base = VcsFileUtil.getPossibleBase(file, LOCAL_EXCLUDE_ARRAY);
if (base != null) {
myDirtyScopeManager.dirDirtyRecursively(base);
return;
import com.intellij.openapi.vfs.VirtualFileEvent;
import com.intellij.ui.AppUIUtil;
import com.intellij.util.ui.UIUtil;
+import com.intellij.vcsUtil.VcsFileUtil;
import com.intellij.vcsUtil.VcsUtil;
import git4idea.GitUtil;
import git4idea.GitVcs;
for (Map.Entry<VirtualFile, List<VirtualFile>> e : sortedFiles.entrySet()) {
VirtualFile root = e.getKey();
pi.setText(root.getPresentableUrl());
- for (List<String> paths : GitFileUtils.chunkFiles(root, e.getValue())) {
+ for (List<String> paths : VcsFileUtil.chunkFiles(root, e.getValue())) {
pi.setText2(paths.get(0) + "...");
try {
GitSimpleHandler h = new GitSimpleHandler(myProject, root, GitCommand.LS_FILES);
final VirtualFile root = e.getKey();
indicator.setText(root.getPresentableUrl());
GitFileUtils.addFiles(myProject, root, e.getValue());
- GitUtil.markFilesDirty(myProject, e.getValue());
+ VcsFileUtil.markFilesDirty(myProject, e.getValue());
}
catch (final VcsException ex) {
UIUtil.invokeLaterIfNeeded(new Runnable() {
final VirtualFile root = e.getKey();
indicator.setText(root.getPresentableUrl());
GitFileUtils.addPaths(myProject, root, e.getValue());
- GitUtil.markFilesDirty(myProject, e.getValue());
+ VcsFileUtil.markFilesDirty(myProject, e.getValue());
}
catch (final VcsException ex) {
UIUtil.invokeLaterIfNeeded(new Runnable() {
indicator.setText(root.getPresentableUrl());
GitFileUtils.delete(myProject, root, e.getValue(), "--ignore-unmatch");
if (myProject != null && !myProject.isDisposed()) {
- GitUtil.markFilesDirty(myProject, e.getValue());
+ VcsFileUtil.markFilesDirty(myProject, e.getValue());
}
for (FilePath p : e.getValue()) {
for (File f = p.getIOFile(); f != null && !f.equals(rootFile); f = f.getParentFile()) {
import com.intellij.testFramework.fixtures.IdeaTestFixtureFactory;
import com.intellij.testFramework.fixtures.TestFixtureBuilder;
import com.intellij.util.ui.UIUtil;
-import git4idea.GitUtil;
+import com.intellij.vcsUtil.VcsFileUtil;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
Assert.assertNotNull(dir);
Assert.assertNotNull(childFile);
- final VirtualFile result = GitUtil.getPossibleBase(childFile, dirName);
+ final VirtualFile result = VcsFileUtil.getPossibleBase(childFile, dirName);
Assert.assertEquals(result, dir);
}
Assert.assertNotNull(dir);
Assert.assertNotNull(childFile);
- final VirtualFile result = GitUtil.getPossibleBase(childFile, dirName.split("/"));
+ final VirtualFile result = VcsFileUtil.getPossibleBase(childFile, dirName.split("/"));
Assert.assertEquals(result, dir);
}
Assert.assertNotNull(dir);
Assert.assertNotNull(childFile);
- final VirtualFile result = GitUtil.getPossibleBase(childFile, dirName.split("/"));
+ final VirtualFile result = VcsFileUtil.getPossibleBase(childFile, dirName.split("/"));
Assert.assertEquals(result, dir);
}
}