/* * Copyright 2000-2009 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 org.community.intellij.plugins.communitycase.commands; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.vcs.FilePath; import com.intellij.openapi.vcs.VcsException; import com.intellij.openapi.vfs.VirtualFile; import org.community.intellij.plugins.communitycase.Util; import org.community.intellij.plugins.communitycase.config.VcsSettings; import org.community.intellij.plugins.communitycase.i18n.Bundle; import org.jetbrains.annotations.Nullable; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.util.*; /** * File utilities */ public class FileUtils { /** * 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 */ private FileUtils() { // 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(Util.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(Util.toRelativeFiles(root, files)); } /** * Delete files * * @param project the project * @param root a vcs root * @param files files to delete * @param additionalOptions the additional options to add to the command line * @throws VcsException in case of git problem */ public static void delete(Project project, VirtualFile root, Collection<FilePath> files, String... additionalOptions) throws VcsException { for (List<String> paths : chunkPaths(root, files)) { SimpleHandler handler = new SimpleHandler(project, root, Command.RM); handler.addParameters(additionalOptions); handler.endOptions(); handler.addParameters(paths); handler.setRemote(true); handler.run(); } } public static void cherryPick(final Project project, final VirtualFile root, final String hash) throws VcsException { SimpleHandler handler = new SimpleHandler(project, root, Command.CHERRY_PICK); handler.addParameters("-x", "-n", hash); handler.endOptions(); //handler.addRelativePaths(new FilePathImpl(root)); handler.setRemote(true); handler.run(); } /** * Delete files * * @param project the project * @param root a vcs root * @param files files to delete * @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)) { SimpleHandler handler = new SimpleHandler(project, root, Command.RM); handler.endOptions(); handler.addParameters(paths); handler.setRemote(true); handler.run(); } } /** * Delete files * * @param project the project * @param root a vcs root * @param files files to delete * @throws VcsException in case of git problem */ public static void deleteFiles(Project project, VirtualFile root, VirtualFile... files) throws VcsException { deleteFiles(project, root, Arrays.asList(files)); } /** * Add/index files * * @param project the project * @param root a vcs root * @param files files to add * @throws VcsException in case of git problem */ public static void addFiles(Project project, VirtualFile root, Collection<VirtualFile> files) throws VcsException { VcsSettings settings=VcsSettings.getInstance(project); Collection<VirtualFile> dirs=new HashSet<VirtualFile>(); for(VirtualFile f : files) dirs.add(f.getParent()); for(List<String> paths : chunkFiles(root, dirs)) { SimpleHandler handler=new SimpleHandler(project, root, Command.CHECKOUT); if(settings!=null && settings.isUseReservedCheckoutForDirectories()) handler.addParameters("-res");//reserved else handler.addParameters("–unr");//unreserved handler.addParameters("-nc"); handler.endOptions(); handler.addParameters(paths); handler.setRemote(true); handler.run(); } for(List<String> paths : chunkFiles(root, files)) { SimpleHandler handler=new SimpleHandler(project, root, Command.ADD); handler.addParameters("-nc"); handler.endOptions(); handler.addParameters(paths); handler.setRemote(true); handler.run(); } } /** * Add/index files * * @param project the project * @param root a vcs root * @param files files to add * @throws VcsException in case of git problem */ public static void addFiles(Project project, VirtualFile root, VirtualFile... files) throws VcsException { addFiles(project, root, Arrays.asList(files)); } /** * Add/index files * * @param project the project * @param root a vcs root * @param files files to add * @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)) { SimpleHandler handler = new SimpleHandler(project, root, Command.ADD); handler.addParameters("-nc"); handler.endOptions(); handler.addParameters(paths); handler.setRemote(true); handler.run(); } } /** * Get file content for the specific revision * * @param project the project * @param root the vcs root * @param revisionOrBranch the revision to find path in or branch * @param relativePath the relative path * @return the content of file if file is found, null if the file is missing in the revision * @throws VcsException if there is a problem with running git */ @Nullable public static byte[] getFileContent(Project project, VirtualFile root, String revisionOrBranch, String relativePath) throws VcsException { BinaryHandler h = new BinaryHandler(project, root, Command.SHOW); h.setRemote(true); h.setSilent(true); File temp; try { temp = FileUtil.createTempFile(relativePath.replaceAll("\\.","-")+revisionOrBranch.replaceAll("\\\\|/","-"), "tmp"); } catch(IOException e) { throw new VcsException(e); } if(temp.exists()) { //noinspection ResultOfMethodCallIgnored temp.delete(); } temp.deleteOnExit(); h.addParameters("-to \""+temp.getAbsolutePath()+"\""); h.addParameters("\""+relativePath + "@@" + revisionOrBranch+"\""); // try { h.run(); /* } catch (VcsException e) { String m = e.getMessage().trim(); if (m.startsWith("fatal: ambiguous argument ") || (m.startsWith("fatal: Path '") && m.contains("' exists on disk, but not in '"))) { result = null; } else { throw e; } }*/ byte[] bytes=null; FileInputStream savedVersionInputStream=null; try { savedVersionInputStream=new FileInputStream(temp); bytes=new byte[savedVersionInputStream.available()]; int readCount=savedVersionInputStream.read(bytes); if(readCount!=bytes.length) throw new VcsException(Bundle.message("version.tempfile.error",Bundle.getString("error.file.read"))); } catch(IOException e) { throw new VcsException(e); } finally { //noinspection EmptyCatchBlock try { //noinspection ConstantConditions savedVersionInputStream.close(); //noinspection ResultOfMethodCallIgnored temp.delete(); } catch(Exception e) {} //sorry, best effort. } return bytes; } }