/*
* Copyright 2000-2016 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.vcs.log.util;
import com.intellij.openapi.application.PathManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.util.PathUtilRt;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.io.*;
import com.intellij.vcs.log.VcsLogProvider;
import org.jetbrains.annotations.NotNull;
import java.io.File;
import java.io.IOException;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
public class PersistentUtil {
@NotNull public static final File LOG_CACHE = new File(PathManager.getSystemPath(), "vcs-log");
@NotNull private static final String CORRUPTION_MARKER = "corruption.marker";
@NotNull
public static String calcLogId(@NotNull Project project, @NotNull Map<VirtualFile, VcsLogProvider> logProviders) {
int hashcode = calcLogProvidersHash(logProviders);
return project.getLocationHash() + "." + Integer.toHexString(hashcode);
}
private static int calcLogProvidersHash(@NotNull final Map<VirtualFile, VcsLogProvider> logProviders) {
List<VirtualFile> sortedRoots = ContainerUtil.sorted(logProviders.keySet(), Comparator.comparing(VirtualFile::getPath));
return StringUtil.join(sortedRoots, root -> root.getPath() + "." + logProviders.get(root).getSupportedVcs().getName(), ".").hashCode();
}
@NotNull
public static File getStorageFile(@NotNull String storageKind, @NotNull String logId, int version) {
File subdir = new File(LOG_CACHE, storageKind);
String safeLogId = PathUtilRt.suggestFileName(logId, true, true);
final File mapFile = new File(subdir, safeLogId + "." + version);
if (!mapFile.exists()) {
IOUtil.deleteAllFilesStartingWith(new File(subdir, safeLogId));
}
return mapFile;
}
public static void cleanupOldStorageFile(@NotNull String storageKind, @NotNull String logId) {
File subdir = new File(LOG_CACHE, storageKind);
String safeLogId = PathUtilRt.suggestFileName(logId, true, true);
IOUtil.deleteAllFilesStartingWith(new File(subdir, safeLogId));
File[] files = subdir.listFiles();
if (files != null && files.length == 0) {
subdir.delete();
}
}
@NotNull
public static <T> PersistentEnumeratorBase<T> createPersistentEnumerator(@NotNull KeyDescriptor<T> keyDescriptor,
@NotNull String storageKind,
@NotNull String logId,
int version) throws IOException {
File storageFile = getStorageFile(storageKind, logId, version);
return IOUtil.openCleanOrResetBroken(() ->
new PersistentBTreeEnumerator<>(storageFile, keyDescriptor, Page.PAGE_SIZE, null, version),
storageFile);
}
public static boolean deleteWithRenamingAllFilesStartingWith(@NotNull File baseFile) {
File parentFile = baseFile.getParentFile();
if (parentFile == null) return false;
File[] files = parentFile.listFiles(pathname -> pathname.getName().startsWith(baseFile.getName()));
if (files == null) return true;
boolean deleted = true;
for (File f : files) {
deleted &= FileUtil.deleteWithRenaming(f);
}
return deleted;
}
// this method cleans up all storage files for a project in a specified subdir
// it assumes that these storage files all start with "safeLogId."
// as method getStorageFile creates them
// so these two methods should be changed in sync
public static boolean cleanupStorageFiles(@NotNull String subdirName, @NotNull String id) {
File subdir = new File(LOG_CACHE, subdirName);
String safeLogId = PathUtilRt.suggestFileName(id, true, true);
return deleteWithRenamingAllFilesStartingWith(new File(subdir, safeLogId + "."));
}
// do not forget to change cleanupStorageFiles method when editing this one
@NotNull
public static File getStorageFile(@NotNull String subdirName,
@NotNull String kind,
@NotNull String id,
int version,
boolean cleanupOldVersions) {
File subdir = new File(LOG_CACHE, subdirName);
String safeLogId = PathUtilRt.suggestFileName(id, true, true);
File file = new File(subdir, safeLogId + "." + kind + "." + version);
if (cleanupOldVersions && !file.exists()) {
IOUtil.deleteAllFilesStartingWith(new File(subdir, safeLogId + "." + kind));
}
return file;
}
@NotNull
public static File getCorruptionMarkerFile() {
return new File(LOG_CACHE, CORRUPTION_MARKER);
}
}