From 7b04a90472d103ba35f5a943f6a7ec60c286de92 Mon Sep 17 00:00:00 2001
From: James Moger <james.moger@gitblit.com>
Date: Thu, 26 Feb 2015 08:33:21 -0500
Subject: [PATCH] Merge branch 'ticket/239' into develop
---
src/main/java/com/gitblit/manager/RepositoryManager.java | 365 +++++++++++++++++++++++++++++++++++++++++++---------
1 files changed, 301 insertions(+), 64 deletions(-)
diff --git a/src/main/java/com/gitblit/manager/RepositoryManager.java b/src/main/java/com/gitblit/manager/RepositoryManager.java
index 9d38b30..c2c6088 100644
--- a/src/main/java/com/gitblit/manager/RepositoryManager.java
+++ b/src/main/java/com/gitblit/manager/RepositoryManager.java
@@ -21,6 +21,7 @@
import java.lang.reflect.Field;
import java.net.URI;
import java.net.URISyntaxException;
+import java.nio.charset.Charset;
import java.text.MessageFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
@@ -52,6 +53,7 @@
import org.eclipse.jgit.storage.file.WindowCacheConfig;
import org.eclipse.jgit.util.FS;
import org.eclipse.jgit.util.FileUtils;
+import org.eclipse.jgit.util.RawParseUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -63,12 +65,10 @@
import com.gitblit.Constants.FederationStrategy;
import com.gitblit.Constants.PermissionType;
import com.gitblit.Constants.RegistrantType;
-import com.gitblit.GCExecutor;
import com.gitblit.GitBlitException;
import com.gitblit.IStoredSettings;
import com.gitblit.Keys;
-import com.gitblit.LuceneExecutor;
-import com.gitblit.MirrorExecutor;
+import com.gitblit.extensions.RepositoryLifeCycleListener;
import com.gitblit.models.ForkModel;
import com.gitblit.models.Metric;
import com.gitblit.models.RefModel;
@@ -77,6 +77,9 @@
import com.gitblit.models.SearchResult;
import com.gitblit.models.TeamModel;
import com.gitblit.models.UserModel;
+import com.gitblit.service.GarbageCollectorService;
+import com.gitblit.service.LuceneService;
+import com.gitblit.service.MirrorService;
import com.gitblit.utils.ArrayUtils;
import com.gitblit.utils.ByteFormat;
import com.gitblit.utils.CommitCache;
@@ -88,6 +91,8 @@
import com.gitblit.utils.ObjectCache;
import com.gitblit.utils.StringUtils;
import com.gitblit.utils.TimeUtils;
+import com.google.inject.Inject;
+import com.google.inject.Singleton;
/**
* Repository manager creates, updates, deletes and caches git repositories. It
@@ -96,6 +101,7 @@
* @author James Moger
*
*/
+@Singleton
public class RepositoryManager implements IRepositoryManager {
private final Logger logger = LoggerFactory.getLogger(getClass());
@@ -114,29 +120,34 @@
private final IRuntimeManager runtimeManager;
+ private final IPluginManager pluginManager;
+
private final IUserManager userManager;
- private final File repositoriesFolder;
+ private File repositoriesFolder;
- private LuceneExecutor luceneExecutor;
+ private LuceneService luceneExecutor;
- private GCExecutor gcExecutor;
+ private GarbageCollectorService gcExecutor;
- private MirrorExecutor mirrorExecutor;
+ private MirrorService mirrorExecutor;
+ @Inject
public RepositoryManager(
IRuntimeManager runtimeManager,
+ IPluginManager pluginManager,
IUserManager userManager) {
this.settings = runtimeManager.getSettings();
this.runtimeManager = runtimeManager;
+ this.pluginManager = pluginManager;
this.userManager = userManager;
- this.repositoriesFolder = runtimeManager.getFileOrFolder(Keys.git.repositoriesFolder, "${baseFolder}/git");
}
@Override
- public IManager setup() {
- logger.info("Git repositories folder = " + repositoriesFolder.getAbsolutePath());
+ public RepositoryManager start() {
+ repositoriesFolder = runtimeManager.getFileOrFolder(Keys.git.repositoriesFolder, "${baseFolder}/git");
+ logger.info("Repositories folder : {}", repositoriesFolder.getAbsolutePath());
// initialize utilities
String prefix = settings.getString(Keys.git.userRepositoryPrefix, "~");
@@ -147,7 +158,7 @@
// build initial repository list
if (settings.getBoolean(Keys.git.cacheRepositoryList, true)) {
- logger.info("Identifying available repositories...");
+ logger.info("Identifying repositories...");
getRepositoryList();
}
@@ -157,16 +168,19 @@
configureJGit();
configureCommitCache();
+ confirmWriteAccess();
+
return this;
}
@Override
- public IManager stop() {
+ public RepositoryManager stop() {
scheduledExecutor.shutdownNow();
luceneExecutor.close();
gcExecutor.close();
mirrorExecutor.close();
+ closeAll();
return this;
}
@@ -414,12 +428,14 @@
@Override
public void addToCachedRepositoryList(RepositoryModel model) {
if (settings.getBoolean(Keys.git.cacheRepositoryList, true)) {
- repositoryListCache.put(model.name.toLowerCase(), model);
+ String key = getRepositoryKey(model.name);
+ repositoryListCache.put(key, model);
// update the fork origin repository with this repository clone
if (!StringUtils.isEmpty(model.originRepository)) {
- if (repositoryListCache.containsKey(model.originRepository)) {
- RepositoryModel origin = repositoryListCache.get(model.originRepository);
+ String originKey = getRepositoryKey(model.originRepository);
+ if (repositoryListCache.containsKey(originKey)) {
+ RepositoryModel origin = repositoryListCache.get(originKey);
origin.addFork(model.name);
}
}
@@ -436,7 +452,8 @@
if (StringUtils.isEmpty(name)) {
return null;
}
- return repositoryListCache.remove(name.toLowerCase());
+ String key = getRepositoryKey(name);
+ return repositoryListCache.remove(key);
}
/**
@@ -447,6 +464,21 @@
private void clearRepositoryMetadataCache(String repositoryName) {
repositorySizeCache.remove(repositoryName);
repositoryMetricsCache.remove(repositoryName);
+ CommitCache.instance().clear(repositoryName);
+ }
+
+ /**
+ * Reset all caches for this repository.
+ *
+ * @param repositoryName
+ * @since 1.5.1
+ */
+ @Override
+ public void resetRepositoryCache(String repositoryName) {
+ removeFromCachedRepositoryList(repositoryName);
+ clearRepositoryMetadataCache(repositoryName);
+ // force a reload of the repository data (ticket-82, issue-433)
+ getRepositoryModel(repositoryName);
}
/**
@@ -457,6 +489,9 @@
public void resetRepositoryListCache() {
logger.info("Repository cache manually reset");
repositoryListCache.clear();
+ repositorySizeCache.clear();
+ repositoryMetricsCache.clear();
+ CommitCache.instance().clear();
}
/**
@@ -527,8 +562,9 @@
// rebuild fork networks
for (RepositoryModel model : repositoryListCache.values()) {
if (!StringUtils.isEmpty(model.originRepository)) {
- if (repositoryListCache.containsKey(model.originRepository)) {
- RepositoryModel origin = repositoryListCache.get(model.originRepository);
+ String originKey = getRepositoryKey(model.originRepository);
+ if (repositoryListCache.containsKey(originKey)) {
+ RepositoryModel origin = repositoryListCache.get(originKey);
origin.addFork(model.name);
}
}
@@ -562,15 +598,13 @@
/**
* Returns the JGit repository for the specified name.
*
- * @param repositoryName
+ * @param name
* @param logError
* @return repository or null
*/
@Override
- public Repository getRepository(String repositoryName, boolean logError) {
- // Decode url-encoded repository name (issue-278)
- // http://stackoverflow.com/questions/17183110
- repositoryName = repositoryName.replace("%7E", "~").replace("%7e", "~");
+ public Repository getRepository(String name, boolean logError) {
+ String repositoryName = fixRepositoryName(name);
if (isCollectingGarbage(repositoryName)) {
logger.warn(MessageFormat.format("Rejecting request for {0}, busy collecting garbage!", repositoryName));
@@ -592,6 +626,27 @@
}
}
return r;
+ }
+
+ /**
+ * Returns the list of all repository models.
+ *
+ * @return list of all repository models
+ */
+ @Override
+ public List<RepositoryModel> getRepositoryModels() {
+ long methodStart = System.currentTimeMillis();
+ List<String> list = getRepositoryList();
+ List<RepositoryModel> repositories = new ArrayList<RepositoryModel>();
+ for (String repo : list) {
+ RepositoryModel model = getRepositoryModel(repo);
+ if (model != null) {
+ repositories.add(model);
+ }
+ }
+ long duration = System.currentTimeMillis() - methodStart;
+ logger.info(MessageFormat.format("{0} repository models loaded in {1} msecs", duration));
+ return repositories;
}
/**
@@ -652,16 +707,15 @@
* Returns the repository model for the specified repository. This method
* does not consider user access permissions.
*
- * @param repositoryName
+ * @param name
* @return repository model or null
*/
@Override
- public RepositoryModel getRepositoryModel(String repositoryName) {
- // Decode url-encoded repository name (issue-278)
- // http://stackoverflow.com/questions/17183110
- repositoryName = repositoryName.replace("%7E", "~").replace("%7e", "~");
+ public RepositoryModel getRepositoryModel(String name) {
+ String repositoryName = fixRepositoryName(name);
- if (!repositoryListCache.containsKey(repositoryName)) {
+ String repositoryKey = getRepositoryKey(repositoryName);
+ if (!repositoryListCache.containsKey(repositoryKey)) {
RepositoryModel model = loadRepositoryModel(repositoryName);
if (model == null) {
return null;
@@ -671,9 +725,9 @@
}
// cached model
- RepositoryModel model = repositoryListCache.get(repositoryName.toLowerCase());
+ RepositoryModel model = repositoryListCache.get(repositoryKey);
- if (gcExecutor.isCollectingGarbage(model.name)) {
+ if (isCollectingGarbage(model.name)) {
// Gitblit is busy collecting garbage, use our cached model
RepositoryModel rm = DeepCopier.copy(model);
rm.isCollectingGarbage = true;
@@ -729,6 +783,52 @@
}
/**
+ * Replaces illegal character patterns in a repository name.
+ *
+ * @param repositoryName
+ * @return a corrected name
+ */
+ private String fixRepositoryName(String repositoryName) {
+ if (StringUtils.isEmpty(repositoryName)) {
+ return repositoryName;
+ }
+
+ // Decode url-encoded repository name (issue-278)
+ // http://stackoverflow.com/questions/17183110
+ String name = repositoryName.replace("%7E", "~").replace("%7e", "~");
+ name = name.replace("%2F", "/").replace("%2f", "/");
+
+ if (name.charAt(name.length() - 1) == '/') {
+ name = name.substring(0, name.length() - 1);
+ }
+
+ // strip duplicate-slashes from requests for repositoryName (ticket-117, issue-454)
+ // specify first char as slash so we strip leading slashes
+ char lastChar = '/';
+ StringBuilder sb = new StringBuilder();
+ for (char c : name.toCharArray()) {
+ if (c == '/' && lastChar == c) {
+ continue;
+ }
+ sb.append(c);
+ lastChar = c;
+ }
+
+ return sb.toString();
+ }
+
+ /**
+ * Returns the cache key for the repository name.
+ *
+ * @param repositoryName
+ * @return the cache key for the repository
+ */
+ private String getRepositoryKey(String repositoryName) {
+ String name = fixRepositoryName(repositoryName);
+ return StringUtils.stripDotGit(name).toLowerCase();
+ }
+
+ /**
* Workaround JGit. I need to access the raw config object directly in order
* to see if the config is dirty so that I can reload a repository model.
* If I use the stock JGit method to get the config it already reloads the
@@ -778,10 +878,11 @@
model.projectPath = StringUtils.getFirstPathElement(repositoryName);
StoredConfig config = r.getConfig();
- boolean hasOrigin = !StringUtils.isEmpty(config.getString("remote", "origin", "url"));
+ boolean hasOrigin = false;
if (config != null) {
// Initialize description from description file
+ hasOrigin = !StringUtils.isEmpty(config.getString("remote", "origin", "url"));
if (getConfig(config,"description", null) == null) {
File descFile = new File(r.getDirectory(), "description");
if (descFile.exists()) {
@@ -794,6 +895,10 @@
model.description = getConfig(config, "description", "");
model.originRepository = getConfig(config, "originRepository", null);
model.addOwners(ArrayUtils.fromString(getConfig(config, "owner", "")));
+ model.acceptNewPatchsets = getConfig(config, "acceptNewPatchsets", true);
+ model.acceptNewTickets = getConfig(config, "acceptNewTickets", true);
+ model.requireApproval = getConfig(config, "requireApproval", settings.getBoolean(Keys.tickets.requireApproval, false));
+ model.mergeTo = getConfig(config, "mergeTo", null);
model.useIncrementalPushTags = getConfig(config, "useIncrementalPushTags", false);
model.incrementalPushTagPrefix = getConfig(config, "incrementalPushTagPrefix", null);
model.allowForks = getConfig(config, "allowForks", true);
@@ -844,6 +949,9 @@
}
}
model.HEAD = JGitUtils.getHEADRef(r);
+ if (StringUtils.isEmpty(model.mergeTo)) {
+ model.mergeTo = model.HEAD;
+ }
model.availableRefs = JGitUtils.getAvailableHeadTargets(r);
model.sparkleshareId = JGitUtils.getSparkleshareId(r);
model.hasCommits = JGitUtils.hasCommits(r);
@@ -895,7 +1003,8 @@
if (!caseSensitiveCheck && settings.getBoolean(Keys.git.cacheRepositoryList, true)) {
// if we are caching use the cache to determine availability
// otherwise we end up adding a phantom repository to the cache
- return repositoryListCache.containsKey(repositoryName.toLowerCase());
+ String key = getRepositoryKey(repositoryName);
+ return repositoryListCache.containsKey(key);
}
Repository r = getRepository(repositoryName, false);
if (r == null) {
@@ -928,26 +1037,31 @@
*/
@Override
public String getFork(String username, String origin) {
+ if (StringUtils.isEmpty(origin)) {
+ return null;
+ }
String userProject = ModelUtils.getPersonalPath(username);
if (settings.getBoolean(Keys.git.cacheRepositoryList, true)) {
+ String originKey = getRepositoryKey(origin);
String userPath = userProject + "/";
// collect all origin nodes in fork network
Set<String> roots = new HashSet<String>();
- roots.add(origin);
- RepositoryModel originModel = repositoryListCache.get(origin);
+ roots.add(originKey);
+ RepositoryModel originModel = repositoryListCache.get(originKey);
while (originModel != null) {
if (!ArrayUtils.isEmpty(originModel.forks)) {
for (String fork : originModel.forks) {
if (!fork.startsWith(userPath)) {
- roots.add(fork);
+ roots.add(fork.toLowerCase());
}
}
}
if (originModel.originRepository != null) {
- roots.add(originModel.originRepository);
- originModel = repositoryListCache.get(originModel.originRepository);
+ String ooKey = getRepositoryKey(originModel.originRepository);
+ roots.add(ooKey);
+ originModel = repositoryListCache.get(ooKey);
} else {
// break
originModel = null;
@@ -958,7 +1072,8 @@
if (repository.startsWith(userPath)) {
RepositoryModel model = repositoryListCache.get(repository);
if (!StringUtils.isEmpty(model.originRepository)) {
- if (roots.contains(model.originRepository)) {
+ String ooKey = getRepositoryKey(model.originRepository);
+ if (roots.contains(ooKey)) {
// user has a fork in this graph
return model.name;
}
@@ -975,7 +1090,7 @@
settings.getStrings(Keys.git.searchExclusions));
for (String repository : repositories) {
RepositoryModel model = getRepositoryModel(userProject + "/" + repository);
- if (model.originRepository.equalsIgnoreCase(origin)) {
+ if (model.originRepository != null && model.originRepository.equalsIgnoreCase(origin)) {
// user has a fork
return model.name;
}
@@ -996,9 +1111,11 @@
public ForkModel getForkNetwork(String repository) {
if (settings.getBoolean(Keys.git.cacheRepositoryList, true)) {
// find the root, cached
- RepositoryModel model = repositoryListCache.get(repository.toLowerCase());
+ String key = getRepositoryKey(repository);
+ RepositoryModel model = repositoryListCache.get(key);
while (model.originRepository != null) {
- model = repositoryListCache.get(model.originRepository);
+ String originKey = getRepositoryKey(model.originRepository);
+ model = repositoryListCache.get(originKey);
}
ForkModel root = getForkModelFromCache(model.name);
return root;
@@ -1014,7 +1131,8 @@
}
private ForkModel getForkModelFromCache(String repository) {
- RepositoryModel model = repositoryListCache.get(repository.toLowerCase());
+ String key = getRepositoryKey(repository);
+ RepositoryModel model = repositoryListCache.get(key);
if (model == null) {
return null;
}
@@ -1078,12 +1196,49 @@
}
/**
+ * Returns true if the repository is idle (not being accessed).
+ *
+ * @param repository
+ * @return true if the repository is idle
+ */
+ @Override
+ public boolean isIdle(Repository repository) {
+ try {
+ // Read the use count.
+ // An idle use count is 2:
+ // +1 for being in the cache
+ // +1 for the repository parameter in this method
+ Field useCnt = Repository.class.getDeclaredField("useCnt");
+ useCnt.setAccessible(true);
+ int useCount = ((AtomicInteger) useCnt.get(repository)).get();
+ return useCount == 2;
+ } catch (Exception e) {
+ logger.warn(MessageFormat
+ .format("Failed to reflectively determine use count for repository {0}",
+ repository.getDirectory().getPath()), e);
+ }
+ return false;
+ }
+
+ /**
+ * Ensures that all cached repository are completely closed and their resources
+ * are properly released.
+ */
+ @Override
+ public void closeAll() {
+ for (String repository : getRepositoryList()) {
+ close(repository);
+ }
+ }
+
+ /**
* Ensure that a cached repository is completely closed and its resources
* are properly released.
*
* @param repositoryName
*/
- private void closeRepository(String repositoryName) {
+ @Override
+ public void close(String repositoryName) {
Repository repository = getRepository(repositoryName);
if (repository == null) {
return;
@@ -1108,7 +1263,7 @@
repositoryName), e);
}
if (uses > 0) {
- logger.info(MessageFormat
+ logger.debug(MessageFormat
.format("{0}.useCnt={1}, calling close() {2} time(s) to close object and ref databases",
repositoryName, uses, uses));
for (int i = 0; i < uses; i++) {
@@ -1208,7 +1363,7 @@
@Override
public void updateRepositoryModel(String repositoryName, RepositoryModel repository,
boolean isCreate) throws GitBlitException {
- if (gcExecutor.isCollectingGarbage(repositoryName)) {
+ if (isCollectingGarbage(repositoryName)) {
throw new GitBlitException(MessageFormat.format("sorry, Gitblit is busy collecting garbage in {0}",
repositoryName));
}
@@ -1246,7 +1401,7 @@
"Failed to rename ''{0}'' because ''{1}'' already exists.",
repositoryName, repository.name));
}
- closeRepository(repositoryName);
+ close(repositoryName);
File folder = new File(repositoriesFolder, repositoryName);
File destFolder = new File(repositoriesFolder, repository.name);
if (destFolder.exists()) {
@@ -1292,7 +1447,8 @@
// update this repository's origin's fork list
if (!StringUtils.isEmpty(repository.originRepository)) {
- RepositoryModel origin = repositoryListCache.get(repository.originRepository);
+ String originKey = getRepositoryKey(repository.originRepository);
+ RepositoryModel origin = repositoryListCache.get(originKey);
if (origin != null && !ArrayUtils.isEmpty(origin.forks)) {
origin.forks.remove(repositoryName);
origin.forks.add(repository.name);
@@ -1346,6 +1502,16 @@
removeFromCachedRepositoryList(repositoryName);
// model will actually be replaced on next load because config is stale
addToCachedRepositoryList(repository);
+
+ if (isCreate && pluginManager != null) {
+ for (RepositoryLifeCycleListener listener : pluginManager.getExtensions(RepositoryLifeCycleListener.class)) {
+ try {
+ listener.onCreation(repository);
+ } catch (Throwable t) {
+ logger.error(String.format("failed to call plugin onCreation %s", repositoryName), t);
+ }
+ }
+ }
}
/**
@@ -1362,6 +1528,18 @@
config.setString(Constants.CONFIG_GITBLIT, null, "description", repository.description);
config.setString(Constants.CONFIG_GITBLIT, null, "originRepository", repository.originRepository);
config.setString(Constants.CONFIG_GITBLIT, null, "owner", ArrayUtils.toString(repository.owners));
+ config.setBoolean(Constants.CONFIG_GITBLIT, null, "acceptNewPatchsets", repository.acceptNewPatchsets);
+ config.setBoolean(Constants.CONFIG_GITBLIT, null, "acceptNewTickets", repository.acceptNewTickets);
+ if (settings.getBoolean(Keys.tickets.requireApproval, false) == repository.requireApproval) {
+ // use default
+ config.unset(Constants.CONFIG_GITBLIT, null, "requireApproval");
+ } else {
+ // override default
+ config.setBoolean(Constants.CONFIG_GITBLIT, null, "requireApproval", repository.requireApproval);
+ }
+ if (!StringUtils.isEmpty(repository.mergeTo)) {
+ config.setString(Constants.CONFIG_GITBLIT, null, "mergeTo", repository.mergeTo);
+ }
config.setBoolean(Constants.CONFIG_GITBLIT, null, "useIncrementalPushTags", repository.useIncrementalPushTags);
if (StringUtils.isEmpty(repository.incrementalPushTagPrefix) ||
repository.incrementalPushTagPrefix.equals(settings.getString(Keys.git.defaultIncrementalPushTagPrefix, "r"))) {
@@ -1450,6 +1628,17 @@
}
/**
+ * Returns true if the repository can be deleted.
+ *
+ * @return true if the repository can be deleted
+ */
+ @Override
+ public boolean canDelete(RepositoryModel repository) {
+ return settings.getBoolean(Keys.web.allowDeletingNonEmptyRepositories, true)
+ || !repository.hasCommits;
+ }
+
+ /**
* Deletes the repository from the file system and removes the repository
* permission from all repository users.
*
@@ -1470,8 +1659,14 @@
*/
@Override
public boolean deleteRepository(String repositoryName) {
+ RepositoryModel repository = getRepositoryModel(repositoryName);
+ if (!canDelete(repository)) {
+ logger.warn("Attempt to delete {} rejected!", repositoryName);
+ return false;
+ }
+
try {
- closeRepository(repositoryName);
+ close(repositoryName);
// clear the repository cache
clearRepositoryMetadataCache(repositoryName);
@@ -1485,6 +1680,16 @@
FileUtils.delete(folder, FileUtils.RECURSIVE | FileUtils.RETRY);
if (userManager.deleteRepositoryRole(repositoryName)) {
logger.info(MessageFormat.format("Repository \"{0}\" deleted", repositoryName));
+
+ if (pluginManager != null) {
+ for (RepositoryLifeCycleListener listener : pluginManager.getExtensions(RepositoryLifeCycleListener.class)) {
+ try {
+ listener.onDeletion(repository);
+ } catch (Throwable t) {
+ logger.error(String.format("failed to call plugin onDeletion %s", repositoryName), t);
+ }
+ }
+ }
return true;
}
}
@@ -1644,16 +1849,18 @@
}
protected void configureLuceneIndexing() {
- luceneExecutor = new LuceneExecutor(settings, this);
- scheduledExecutor.scheduleAtFixedRate(luceneExecutor, 1, 2, TimeUnit.MINUTES);
- logger.info("Lucene executor is scheduled to process indexed branches every 2 minutes.");
+ luceneExecutor = new LuceneService(settings, this);
+ String frequency = settings.getString(Keys.web.luceneFrequency, "2 mins");
+ int mins = TimeUtils.convertFrequencyToMinutes(frequency, 2);
+ scheduledExecutor.scheduleAtFixedRate(luceneExecutor, 1, mins, TimeUnit.MINUTES);
+ logger.info("Lucene will process indexed branches every {} minutes.", mins);
}
protected void configureGarbageCollector() {
// schedule gc engine
- gcExecutor = new GCExecutor(settings, this);
+ gcExecutor = new GarbageCollectorService(settings, this);
if (gcExecutor.isReady()) {
- logger.info("GC executor is scheduled to scan repositories every 24 hours.");
+ logger.info("Garbage Collector (GC) will scan repositories every 24 hours.");
Calendar c = Calendar.getInstance();
c.set(Calendar.HOUR_OF_DAY, settings.getInteger(Keys.git.garbageCollectionHour, 0));
c.set(Calendar.MINUTE, 0);
@@ -1673,20 +1880,21 @@
}
logger.info(MessageFormat.format("Next scheculed GC scan is in {0}", when));
scheduledExecutor.scheduleAtFixedRate(gcExecutor, delay, 60 * 24, TimeUnit.MINUTES);
+ } else {
+ logger.info("Garbage Collector (GC) is disabled.");
}
}
protected void configureMirrorExecutor() {
- mirrorExecutor = new MirrorExecutor(settings, this);
+ mirrorExecutor = new MirrorService(settings, this);
if (mirrorExecutor.isReady()) {
- int mins = TimeUtils.convertFrequencyToMinutes(settings.getString(Keys.git.mirrorPeriod, "30 mins"));
- if (mins < 5) {
- mins = 5;
- }
+ int mins = TimeUtils.convertFrequencyToMinutes(settings.getString(Keys.git.mirrorPeriod, "30 mins"), 5);
int delay = 1;
scheduledExecutor.scheduleAtFixedRate(mirrorExecutor, delay, mins, TimeUnit.MINUTES);
- logger.info("Mirror executor is scheduled to fetch updates every {} minutes.", mins);
+ logger.info("Mirror service will fetch updates every {} minutes.", mins);
logger.info("Next scheduled mirror fetch is in {} minutes", delay);
+ } else {
+ logger.info("Mirror service is disabled.");
}
}
@@ -1698,7 +1906,6 @@
cfg.setPackedGitLimit(settings.getFilesize(Keys.git.packedGitLimit, cfg.getPackedGitLimit()));
cfg.setDeltaBaseCacheLimit(settings.getFilesize(Keys.git.deltaBaseCacheLimit, cfg.getDeltaBaseCacheLimit()));
cfg.setPackedGitOpenFiles(settings.getFilesize(Keys.git.packedGitOpenFiles, cfg.getPackedGitOpenFiles()));
- cfg.setStreamFileThreshold(settings.getFilesize(Keys.git.streamFileThreshold, cfg.getStreamFileThreshold()));
cfg.setPackedGitMMAP(settings.getBoolean(Keys.git.packedGitMmap, cfg.isPackedGitMMAP()));
try {
@@ -1707,22 +1914,35 @@
logger.debug(MessageFormat.format("{0} = {1,number,0}", Keys.git.packedGitLimit, cfg.getPackedGitLimit()));
logger.debug(MessageFormat.format("{0} = {1,number,0}", Keys.git.deltaBaseCacheLimit, cfg.getDeltaBaseCacheLimit()));
logger.debug(MessageFormat.format("{0} = {1,number,0}", Keys.git.packedGitOpenFiles, cfg.getPackedGitOpenFiles()));
- logger.debug(MessageFormat.format("{0} = {1,number,0}", Keys.git.streamFileThreshold, cfg.getStreamFileThreshold()));
logger.debug(MessageFormat.format("{0} = {1}", Keys.git.packedGitMmap, cfg.isPackedGitMMAP()));
} catch (IllegalArgumentException e) {
logger.error("Failed to configure JGit parameters!", e);
+ }
+
+ try {
+ // issue-486/ticket-151: UTF-9 & UTF-18
+ // issue-560/ticket-237: 'UTF8'
+ Field field = RawParseUtils.class.getDeclaredField("encodingAliases");
+ field.setAccessible(true);
+ Map<String, Charset> encodingAliases = (Map<String, Charset>) field.get(null);
+ encodingAliases.put("'utf8'", RawParseUtils.UTF8_CHARSET);
+ encodingAliases.put("utf-9", RawParseUtils.UTF8_CHARSET);
+ encodingAliases.put("utf-18", RawParseUtils.UTF8_CHARSET);
+ logger.info("Alias 'UTF8', UTF-9 & UTF-18 encodings as UTF-8 in JGit");
+ } catch (Throwable t) {
+ logger.error("Failed to inject UTF-9 & UTF-18 encoding aliases into JGit", t);
}
}
protected void configureCommitCache() {
int daysToCache = settings.getInteger(Keys.web.activityCacheDays, 14);
if (daysToCache <= 0) {
- logger.info("commit cache disabled");
+ logger.info("Commit cache is disabled");
} else {
long start = System.nanoTime();
long repoCount = 0;
long commitCount = 0;
- logger.info(MessageFormat.format("preparing {0} day commit cache. please wait...", daysToCache));
+ logger.info(MessageFormat.format("Preparing {0} day commit cache. please wait...", daysToCache));
CommitCache.instance().setCacheDays(daysToCache);
Date cutoff = CommitCache.instance().getCutoffDate();
for (String repositoryName : getRepositoryList()) {
@@ -1749,4 +1969,21 @@
daysToCache, commitCount, repoCount, TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - start)));
}
}
+
+ protected void confirmWriteAccess() {
+ try {
+ if (!getRepositoriesFolder().exists()) {
+ getRepositoriesFolder().mkdirs();
+ }
+ File file = File.createTempFile(".test-", ".txt", getRepositoriesFolder());
+ file.delete();
+ } catch (Exception e) {
+ logger.error("");
+ logger.error(Constants.BORDER2);
+ logger.error("Please check filesystem permissions!");
+ logger.error("FAILED TO WRITE TO REPOSITORIES FOLDER!!", e);
+ logger.error(Constants.BORDER2);
+ logger.error("");
+ }
+ }
}
--
Gitblit v1.9.1