mirror of
https://github.com/scm-manager/scm-manager.git
synced 2025-11-03 12:05:52 +01:00
merge with branch 1.x
This commit is contained in:
@@ -160,6 +160,23 @@ public class GitChangesetConverter implements Closeable
|
||||
return createChangeset(commit, branches);
|
||||
}
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @param commit
|
||||
* @param branch
|
||||
*
|
||||
* @return
|
||||
*
|
||||
* @throws IOException
|
||||
*/
|
||||
public Changeset createChangeset(RevCommit commit, String branch)
|
||||
throws IOException
|
||||
{
|
||||
return createChangeset(commit, Lists.newArrayList(branch));
|
||||
}
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
|
||||
@@ -35,6 +35,9 @@ package sonia.scm.repository;
|
||||
|
||||
//~--- JDK imports ------------------------------------------------------------
|
||||
|
||||
import javax.xml.bind.annotation.XmlAccessType;
|
||||
import javax.xml.bind.annotation.XmlAccessorType;
|
||||
import javax.xml.bind.annotation.XmlElement;
|
||||
import javax.xml.bind.annotation.XmlRootElement;
|
||||
|
||||
/**
|
||||
@@ -42,4 +45,15 @@ import javax.xml.bind.annotation.XmlRootElement;
|
||||
* @author Sebastian Sdorra
|
||||
*/
|
||||
@XmlRootElement(name = "config")
|
||||
public class GitConfig extends SimpleRepositoryConfig {}
|
||||
@XmlAccessorType(XmlAccessType.FIELD)
|
||||
public class GitConfig extends SimpleRepositoryConfig {
|
||||
|
||||
@XmlElement(name = "gc-expression")
|
||||
private String gcExpression;
|
||||
|
||||
public String getGcExpression()
|
||||
{
|
||||
return gcExpression;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
/**
|
||||
* Copyright (c) 2014, Sebastian Sdorra
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of SCM-Manager; nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* http://bitbucket.org/sdorra/scm-manager
|
||||
*
|
||||
*/
|
||||
package sonia.scm.repository;
|
||||
|
||||
/**
|
||||
* Constants for Git.
|
||||
*
|
||||
* @author Sebastian Sdorra
|
||||
* @since 1.50
|
||||
*/
|
||||
public final class GitConstants {
|
||||
|
||||
/**
|
||||
* Default branch repository property.
|
||||
*/
|
||||
public static final String PROPERTY_DEFAULT_BRANCH = "git.default-branch";
|
||||
|
||||
private GitConstants() {
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,164 @@
|
||||
/***
|
||||
* Copyright (c) 2015, Sebastian Sdorra
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of SCM-Manager; nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* https://bitbucket.org/sdorra/scm-manager
|
||||
*
|
||||
*/
|
||||
|
||||
package sonia.scm.repository;
|
||||
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import com.google.common.base.Stopwatch;
|
||||
import com.google.inject.Inject;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
import org.eclipse.jgit.api.GarbageCollectCommand;
|
||||
import org.eclipse.jgit.api.Git;
|
||||
import org.eclipse.jgit.api.errors.GitAPIException;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Executes git gc on every git repository. Statistics of the gc process are logged to the info level. The task is
|
||||
* disabled by default and must be enabled through the global git configuration.
|
||||
*
|
||||
* @author Sebastian Sdorra
|
||||
* @since 1.47
|
||||
*/
|
||||
public class GitGcTask implements Runnable {
|
||||
|
||||
private static final String SP = System.getProperty("line.seperator", "\n");
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(GitGcTask.class);
|
||||
|
||||
private final RepositoryManager repositoryManager;
|
||||
private final RepositoryDirectoryHandler repositoryHandler;
|
||||
|
||||
@Inject
|
||||
public GitGcTask(RepositoryManager repositoryManager)
|
||||
{
|
||||
this.repositoryManager = repositoryManager;
|
||||
this.repositoryHandler = (RepositoryDirectoryHandler) repositoryManager.getHandler(GitRepositoryHandler.TYPE_NAME);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
for (Repository repository : repositoryManager.getAll())
|
||||
{
|
||||
handle(repository);
|
||||
}
|
||||
}
|
||||
|
||||
private void handle(Repository repository){
|
||||
if (GitRepositoryHandler.TYPE_NAME.equals(repository.getType()))
|
||||
{
|
||||
if (repository.isValid() && repository.isHealthy())
|
||||
{
|
||||
logger.info("start git gc for repository {}", repository.getName());
|
||||
Stopwatch sw = Stopwatch.createStarted();
|
||||
gc(repository);
|
||||
logger.debug("gc of repository {} has finished after {}", repository.getName(), sw.stop());
|
||||
}
|
||||
else
|
||||
{
|
||||
logger.debug("skip non valid/healthy repository {}", repository.getName());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
logger.trace("skip non git repository {}", repository.getName());
|
||||
}
|
||||
}
|
||||
|
||||
private void appendProperties(StringBuilder buffer, Properties properties){
|
||||
for (Map.Entry<Object,Object> entry : properties.entrySet()){
|
||||
buffer.append(SP).append(" - ").append(entry.getKey()).append(" = ").append(entry.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
private String message(Repository repository, Properties statistics, String span){
|
||||
StringBuilder buffer = new StringBuilder("gc statistics for ");
|
||||
buffer.append(repository.getName()).append(" ").append(span).append(" execution:");
|
||||
appendProperties(buffer, statistics);
|
||||
return buffer.toString();
|
||||
}
|
||||
|
||||
private void statistics(Repository repository, GarbageCollectCommand gcc) throws GitAPIException {
|
||||
Properties properties = gcc.getStatistics();
|
||||
logger.info(message(repository, properties, "before"));
|
||||
}
|
||||
|
||||
private void execute(Repository repository, GarbageCollectCommand gcc) throws GitAPIException {
|
||||
Properties properties = gcc.call();
|
||||
logger.info(message(repository, properties, "after"));
|
||||
}
|
||||
|
||||
private void gc(Repository repository){
|
||||
File file = repositoryHandler.getDirectory(repository);
|
||||
Git git = null;
|
||||
try {
|
||||
git = open(file);
|
||||
GarbageCollectCommand gcc = git.gc();
|
||||
// print statistics before execution, because it looks like
|
||||
// jgit returns the statistics after gc has finished
|
||||
statistics(repository, gcc);
|
||||
execute(repository, gcc);
|
||||
}
|
||||
catch (IOException ex)
|
||||
{
|
||||
logger.warn("failed to open git repository", ex);
|
||||
}
|
||||
catch (GitAPIException ex)
|
||||
{
|
||||
logger.warn("failed running git gc command", ex);
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (git != null){
|
||||
git.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens the git repository. This method is only visible for testing purposes.
|
||||
*
|
||||
* @param file repository directory
|
||||
*
|
||||
* @return git for repository
|
||||
*
|
||||
* @throws IOException
|
||||
*/
|
||||
@VisibleForTesting
|
||||
protected Git open(File file) throws IOException {
|
||||
return Git.open(file);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -36,6 +36,7 @@ package sonia.scm.repository;
|
||||
//~--- non-JDK imports --------------------------------------------------------
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Maps;
|
||||
|
||||
import org.eclipse.jgit.errors.IncorrectObjectTypeException;
|
||||
import org.eclipse.jgit.lib.ObjectId;
|
||||
@@ -49,12 +50,14 @@ import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import sonia.scm.util.IOUtil;
|
||||
import sonia.scm.web.CollectingPackParserListener;
|
||||
|
||||
//~--- JDK imports ------------------------------------------------------------
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -72,7 +75,7 @@ public class GitHookChangesetCollector
|
||||
//~--- constructors ---------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Constructs ...
|
||||
* Constructs a new instance
|
||||
*
|
||||
*
|
||||
* @param rpack
|
||||
@@ -83,19 +86,19 @@ public class GitHookChangesetCollector
|
||||
{
|
||||
this.rpack = rpack;
|
||||
this.receiveCommands = receiveCommands;
|
||||
this.listener = CollectingPackParserListener.get(rpack);
|
||||
}
|
||||
|
||||
//~--- methods --------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Method description
|
||||
* Collect all new changesets from the received hook.
|
||||
*
|
||||
*
|
||||
* @return
|
||||
* @return new changesets
|
||||
*/
|
||||
public List<Changeset> collectChangesets()
|
||||
{
|
||||
List<Changeset> changesets = Lists.newArrayList();
|
||||
Map<String, Changeset> changesets = Maps.newLinkedHashMap();
|
||||
|
||||
org.eclipse.jgit.lib.Repository repository = rpack.getRepository();
|
||||
|
||||
@@ -110,7 +113,19 @@ public class GitHookChangesetCollector
|
||||
|
||||
for (ReceiveCommand rc : receiveCommands)
|
||||
{
|
||||
if (rc.getType() != ReceiveCommand.Type.DELETE)
|
||||
String ref = rc.getRefName();
|
||||
|
||||
logger.trace("handle receive command, type={}, ref={}, result={}", rc.getType(), ref, rc.getResult());
|
||||
|
||||
if (rc.getType() == ReceiveCommand.Type.DELETE)
|
||||
{
|
||||
logger.debug("skip delete of ref {}", ref);
|
||||
}
|
||||
else if (! GitUtil.isBranch(ref))
|
||||
{
|
||||
logger.debug("skip ref {}, because it is not a branch", ref);
|
||||
}
|
||||
else
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -124,13 +139,10 @@ public class GitHookChangesetCollector
|
||||
builder.append(rc.getType()).append(", ref=");
|
||||
builder.append(rc.getRefName()).append(", result=");
|
||||
builder.append(rc.getResult());
|
||||
|
||||
logger.error(builder.toString(), ex);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
logger.debug("skip delete of branch {}", rc.getRefName());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -144,35 +156,13 @@ public class GitHookChangesetCollector
|
||||
GitUtil.release(walk);
|
||||
}
|
||||
|
||||
return changesets;
|
||||
return Lists.newArrayList(changesets.values());
|
||||
}
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @param changesets
|
||||
* @param converter
|
||||
* @param walk
|
||||
* @param rc
|
||||
*
|
||||
* @throws IOException
|
||||
* @throws IncorrectObjectTypeException
|
||||
*/
|
||||
private void collectChangesets(List<Changeset> changesets,
|
||||
private void collectChangesets(Map<String, Changeset> changesets,
|
||||
GitChangesetConverter converter, RevWalk walk, ReceiveCommand rc)
|
||||
throws IncorrectObjectTypeException, IOException
|
||||
{
|
||||
//J-
|
||||
logger.trace("handle receive command, type={}, ref={}, result={}",
|
||||
new Object[] {
|
||||
rc.getType(),
|
||||
rc.getRefName(),
|
||||
rc.getResult()
|
||||
}
|
||||
);
|
||||
//J+
|
||||
|
||||
ObjectId newId = rc.getNewId();
|
||||
|
||||
String branch = GitUtil.getBranch(rc.getRefName());
|
||||
@@ -187,7 +177,7 @@ public class GitHookChangesetCollector
|
||||
|
||||
ObjectId oldId = rc.getOldId();
|
||||
|
||||
if ((oldId != null) &&!oldId.equals(ObjectId.zeroId()))
|
||||
if ((oldId != null) && !oldId.equals(ObjectId.zeroId()))
|
||||
{
|
||||
logger.trace("mark {} as uninteresting for rev walk", oldId.getName());
|
||||
|
||||
@@ -196,19 +186,39 @@ public class GitHookChangesetCollector
|
||||
|
||||
RevCommit commit = walk.next();
|
||||
|
||||
List<String> branches = Lists.newArrayList(branch);
|
||||
|
||||
while (commit != null)
|
||||
{
|
||||
String id = commit.getId().name();
|
||||
Changeset changeset = changesets.get(id);
|
||||
|
||||
// parse commit body to avoid npe
|
||||
walk.parseBody(commit);
|
||||
if (changeset != null)
|
||||
{
|
||||
logger.trace(
|
||||
"commit {} already received durring this push, add branch {} to the commit",
|
||||
commit, branch);
|
||||
changeset.getBranches().add(branch);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
Changeset changeset = converter.createChangeset(commit, branches);
|
||||
// only append new commits
|
||||
if (listener.isNew(commit))
|
||||
{
|
||||
|
||||
logger.trace("retrive commit {} for hook", changeset.getId());
|
||||
// parse commit body to avoid npe
|
||||
walk.parseBody(commit);
|
||||
|
||||
changesets.add(changeset);
|
||||
changeset = converter.createChangeset(commit, branch);
|
||||
|
||||
logger.trace("retrieve commit {} for hook", changeset.getId());
|
||||
|
||||
changesets.put(id, changeset);
|
||||
}
|
||||
else
|
||||
{
|
||||
logger.trace("commit {} was already received", commit.getId());
|
||||
}
|
||||
}
|
||||
|
||||
commit = walk.next();
|
||||
}
|
||||
@@ -216,9 +226,10 @@ public class GitHookChangesetCollector
|
||||
|
||||
//~--- fields ---------------------------------------------------------------
|
||||
|
||||
/** Field description */
|
||||
/** listener to track new objects */
|
||||
private final CollectingPackParserListener listener;
|
||||
|
||||
private final List<ReceiveCommand> receiveCommands;
|
||||
|
||||
/** Field description */
|
||||
private final ReceivePack rpack;
|
||||
}
|
||||
|
||||
@@ -35,6 +35,7 @@ package sonia.scm.repository;
|
||||
|
||||
//~--- non-JDK imports --------------------------------------------------------
|
||||
|
||||
import com.google.common.base.Strings;
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.Singleton;
|
||||
|
||||
@@ -50,6 +51,11 @@ import sonia.scm.repository.spi.GitRepositoryServiceProvider;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import sonia.scm.store.ConfigurationStoreFactory;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import sonia.scm.SCMContextProvider;
|
||||
import sonia.scm.schedule.Scheduler;
|
||||
import sonia.scm.schedule.Task;
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -66,19 +72,27 @@ public class GitRepositoryHandler
|
||||
|
||||
/** Field description */
|
||||
public static final String RESOURCE_VERSION =
|
||||
"/sonia/scm/version/scm-git-plugin";
|
||||
"sonia/scm/version/scm-git-plugin";
|
||||
|
||||
/** Field description */
|
||||
public static final String TYPE_DISPLAYNAME = "Git";
|
||||
|
||||
/** Field description */
|
||||
public static final String TYPE_NAME = "git";
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(GitRepositoryHandler.class);
|
||||
|
||||
/** Field description */
|
||||
public static final Type TYPE = new RepositoryType(TYPE_NAME,
|
||||
TYPE_DISPLAYNAME,
|
||||
GitRepositoryServiceProvider.COMMANDS);
|
||||
|
||||
private static final Object LOCK = new Object();
|
||||
|
||||
private final Scheduler scheduler;
|
||||
|
||||
private Task task;
|
||||
|
||||
//~--- constructors ---------------------------------------------------------
|
||||
|
||||
/**
|
||||
@@ -87,15 +101,48 @@ public class GitRepositoryHandler
|
||||
*
|
||||
* @param storeFactory
|
||||
* @param fileSystem
|
||||
* @param scheduler
|
||||
*/
|
||||
@Inject
|
||||
public GitRepositoryHandler(ConfigurationStoreFactory storeFactory, FileSystem fileSystem)
|
||||
public GitRepositoryHandler(ConfigurationStoreFactory storeFactory, FileSystem fileSystem, Scheduler scheduler)
|
||||
{
|
||||
super(storeFactory, fileSystem);
|
||||
this.scheduler = scheduler;
|
||||
}
|
||||
|
||||
//~--- get methods ----------------------------------------------------------
|
||||
|
||||
@Override
|
||||
public void init(SCMContextProvider context)
|
||||
{
|
||||
super.init(context);
|
||||
scheduleGc();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setConfig(GitConfig config)
|
||||
{
|
||||
super.setConfig(config);
|
||||
scheduleGc();
|
||||
}
|
||||
|
||||
private void scheduleGc()
|
||||
{
|
||||
synchronized (LOCK){
|
||||
if ( task != null ){
|
||||
logger.debug("cancel existing git gc task");
|
||||
task.cancel();
|
||||
task = null;
|
||||
}
|
||||
String exp = getConfig().getGcExpression();
|
||||
if (!Strings.isNullOrEmpty(exp))
|
||||
{
|
||||
logger.info("schedule git gc task with expression {}", exp);
|
||||
task = scheduler.schedule(exp, GitGcTask.class);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
|
||||
@@ -0,0 +1,97 @@
|
||||
/**
|
||||
* Copyright (c) 2014, Sebastian Sdorra
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of SCM-Manager; nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* http://bitbucket.org/sdorra/scm-manager
|
||||
*
|
||||
*/
|
||||
package sonia.scm.repository;
|
||||
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import com.google.common.base.Objects;
|
||||
import com.google.common.eventbus.Subscribe;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import sonia.scm.EagerSingleton;
|
||||
import sonia.scm.HandlerEventType;
|
||||
import sonia.scm.event.ScmEventBus;
|
||||
import sonia.scm.plugin.Extension;
|
||||
|
||||
/**
|
||||
* Repository listener which handles git related repository events.
|
||||
*
|
||||
* @author Sebastian Sdorra
|
||||
* @since 1.50
|
||||
*/
|
||||
@Extension
|
||||
@EagerSingleton
|
||||
public class GitRepositoryModifyListener {
|
||||
|
||||
/**
|
||||
* the logger for GitRepositoryModifyListener
|
||||
*/
|
||||
private static final Logger logger = LoggerFactory.getLogger(GitRepositoryModifyListener.class);
|
||||
|
||||
/**
|
||||
* Receives {@link RepositoryModificationEvent} and fires a {@link ClearRepositoryCacheEvent} if
|
||||
* the default branch of a git repository was modified.
|
||||
*
|
||||
* @param event repository modification event
|
||||
*/
|
||||
@Subscribe
|
||||
public void handleEvent(RepositoryModificationEvent event){
|
||||
Repository repository = event.getItem();
|
||||
|
||||
if ( isModifyEvent(event) &&
|
||||
isGitRepository(event.getItem()) &&
|
||||
hasDefaultBranchChanged(event.getItemBeforeModification(), repository))
|
||||
{
|
||||
logger.info("git default branch of repository {} has changed, sending clear cache event", repository.getId());
|
||||
sendClearRepositoryCacheEvent(repository);
|
||||
}
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
protected void sendClearRepositoryCacheEvent(Repository repository) {
|
||||
ScmEventBus.getInstance().post(new ClearRepositoryCacheEvent(repository));
|
||||
}
|
||||
|
||||
private boolean isModifyEvent(RepositoryEvent event) {
|
||||
return event.getEventType() == HandlerEventType.MODIFY;
|
||||
}
|
||||
|
||||
private boolean isGitRepository(Repository repository) {
|
||||
return GitRepositoryHandler.TYPE_NAME.equals(repository.getType());
|
||||
}
|
||||
|
||||
private boolean hasDefaultBranchChanged(Repository old, Repository current) {
|
||||
return !Objects.equal(
|
||||
old.getProperty(GitConstants.PROPERTY_DEFAULT_BRANCH),
|
||||
current.getProperty(GitConstants.PROPERTY_DEFAULT_BRANCH)
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -36,6 +36,7 @@ package sonia.scm.repository;
|
||||
//~--- non-JDK imports --------------------------------------------------------
|
||||
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import com.google.common.base.Strings;
|
||||
import com.google.common.collect.ArrayListMultimap;
|
||||
import com.google.common.collect.Multimap;
|
||||
|
||||
@@ -262,7 +263,7 @@ public final class GitUtil
|
||||
{
|
||||
if (formatter != null)
|
||||
{
|
||||
formatter.release();
|
||||
formatter.close();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -276,7 +277,7 @@ public final class GitUtil
|
||||
{
|
||||
if (walk != null)
|
||||
{
|
||||
walk.release();
|
||||
walk.close();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -290,7 +291,7 @@ public final class GitUtil
|
||||
{
|
||||
if (walk != null)
|
||||
{
|
||||
walk.release();
|
||||
walk.close();;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -335,6 +336,20 @@ public final class GitUtil
|
||||
|
||||
return branch;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@code true} if the provided reference name is a branch name.
|
||||
*
|
||||
* @param refName reference name
|
||||
*
|
||||
* @return {@code true} if the name is a branch name
|
||||
*
|
||||
* @since 1.50
|
||||
*/
|
||||
public static boolean isBranch(String refName)
|
||||
{
|
||||
return Strings.nullToEmpty(refName).startsWith(PREFIX_HEADS);
|
||||
}
|
||||
|
||||
/**
|
||||
* Method description
|
||||
@@ -631,6 +646,26 @@ public final class GitUtil
|
||||
return String.format(REMOTE_REF, repository.getId(), branch);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of the tag or {@code null} if the the ref is not a tag.
|
||||
*
|
||||
* @param refName ref name
|
||||
*
|
||||
* @return name of tag or {@link null}
|
||||
*
|
||||
* @since 1.50
|
||||
*/
|
||||
public static String getTagName(String refName)
|
||||
{
|
||||
String tagName = null;
|
||||
if (refName.startsWith(PREFIX_TAG))
|
||||
{
|
||||
tagName = refName.substring(PREFIX_TAG.length());
|
||||
}
|
||||
|
||||
return tagName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
|
||||
@@ -0,0 +1,120 @@
|
||||
/**
|
||||
* Copyright (c) 2014, Sebastian Sdorra All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer. 2. Redistributions in
|
||||
* binary form must reproduce the above copyright notice, this list of
|
||||
* conditions and the following disclaimer in the documentation and/or other
|
||||
* materials provided with the distribution. 3. Neither the name of SCM-Manager;
|
||||
* nor the names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* http://bitbucket.org/sdorra/scm-manager
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
|
||||
package sonia.scm.repository.api;
|
||||
|
||||
//~--- non-JDK imports --------------------------------------------------------
|
||||
|
||||
import com.google.common.base.Strings;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableList.Builder;
|
||||
|
||||
import org.eclipse.jgit.transport.ReceiveCommand;
|
||||
import org.eclipse.jgit.transport.ReceiveCommand.Type;
|
||||
|
||||
import sonia.scm.repository.GitUtil;
|
||||
|
||||
//~--- JDK imports ------------------------------------------------------------
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Collects created, modified and deleted git branches during a hook.
|
||||
*
|
||||
* @author Sebastian Sdorra
|
||||
*/
|
||||
public class GitHookBranchProvider implements HookBranchProvider
|
||||
{
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(GitHookBranchProvider.class);
|
||||
|
||||
/**
|
||||
* Constructs a new instance.
|
||||
*
|
||||
*
|
||||
* @param commands received git commands
|
||||
*/
|
||||
public GitHookBranchProvider(List<ReceiveCommand> commands)
|
||||
{
|
||||
Builder<String> createdOrModifiedBuilder = ImmutableList.builder();
|
||||
Builder<String> deletedOrClosedBuilder = ImmutableList.builder();
|
||||
|
||||
for (ReceiveCommand command : commands)
|
||||
{
|
||||
Type type = command.getType();
|
||||
String ref = command.getRefName();
|
||||
String branch = GitUtil.getBranch(ref);
|
||||
|
||||
if (Strings.isNullOrEmpty(branch))
|
||||
{
|
||||
logger.debug("ref {} is not a branch", ref);
|
||||
}
|
||||
else if (isCreateOrUpdate(type))
|
||||
{
|
||||
createdOrModifiedBuilder.add(branch);
|
||||
}
|
||||
else if (command.getType() == Type.DELETE)
|
||||
{
|
||||
deletedOrClosedBuilder.add(branch);
|
||||
}
|
||||
}
|
||||
|
||||
createdOrModified = createdOrModifiedBuilder.build();
|
||||
deletedOrClosed = deletedOrClosedBuilder.build();
|
||||
}
|
||||
|
||||
private boolean isCreateOrUpdate(Type type){
|
||||
return type == Type.CREATE || type == Type.UPDATE || type == Type.UPDATE_NONFASTFORWARD;
|
||||
}
|
||||
|
||||
//~--- get methods ----------------------------------------------------------
|
||||
|
||||
@Override
|
||||
public List<String> getCreatedOrModified()
|
||||
{
|
||||
return createdOrModified;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getDeletedOrClosed()
|
||||
{
|
||||
return deletedOrClosed;
|
||||
}
|
||||
|
||||
//~--- fields ---------------------------------------------------------------
|
||||
|
||||
private final List<String> createdOrModified;
|
||||
|
||||
private final List<String> deletedOrClosed;
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
/***
|
||||
* Copyright (c) 2015, Sebastian Sdorra
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of SCM-Manager; nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* https://bitbucket.org/sdorra/scm-manager
|
||||
*
|
||||
*/
|
||||
|
||||
package sonia.scm.repository.api;
|
||||
|
||||
import com.google.common.base.Strings;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import java.util.List;
|
||||
import org.eclipse.jgit.transport.ReceiveCommand;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import sonia.scm.repository.GitUtil;
|
||||
import sonia.scm.repository.Tag;
|
||||
|
||||
/**
|
||||
* Git provider implementation of {@link HookTagProvider}.
|
||||
*
|
||||
* @since 1.50
|
||||
* @author Sebastian Sdorra
|
||||
*/
|
||||
public class GitHookTagProvider implements HookTagProvider {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(GitHookTagProvider.class);
|
||||
|
||||
private final List<Tag> createdTags;
|
||||
private final List<Tag> deletedTags;
|
||||
|
||||
/**
|
||||
* Constructs new instance.
|
||||
*
|
||||
* @param commands received commands
|
||||
*/
|
||||
public GitHookTagProvider(List<ReceiveCommand> commands) {
|
||||
ImmutableList.Builder<Tag> createdTagBuilder = ImmutableList.builder();
|
||||
ImmutableList.Builder<Tag> deletedTagBuilder = ImmutableList.builder();
|
||||
|
||||
for ( ReceiveCommand rc : commands ){
|
||||
String refName = rc.getRefName();
|
||||
String tag = GitUtil.getTagName(refName);
|
||||
|
||||
if (Strings.isNullOrEmpty(tag)){
|
||||
logger.debug("received ref name {} is not a tag", refName);
|
||||
} else if (rc.getType() == ReceiveCommand.Type.CREATE) {
|
||||
createdTagBuilder.add(new Tag(tag, GitUtil.getId(rc.getNewId())));
|
||||
} else if (rc.getType() == ReceiveCommand.Type.DELETE){
|
||||
deletedTagBuilder.add(new Tag(tag, GitUtil.getId(rc.getOldId())));
|
||||
}
|
||||
}
|
||||
|
||||
createdTags = createdTagBuilder.build();
|
||||
deletedTags = deletedTagBuilder.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Tag> getCreatedTags() {
|
||||
return createdTags;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Tag> getDeletedTags() {
|
||||
return deletedTags;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -34,11 +34,18 @@ package sonia.scm.repository.spi;
|
||||
|
||||
//~--- non-JDK imports --------------------------------------------------------
|
||||
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import com.google.common.base.Strings;
|
||||
import org.eclipse.jgit.lib.Repository;
|
||||
|
||||
//~--- JDK imports ------------------------------------------------------------
|
||||
|
||||
import java.io.IOException;
|
||||
import org.eclipse.jgit.lib.ObjectId;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import sonia.scm.repository.GitConstants;
|
||||
import sonia.scm.repository.GitUtil;
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -46,6 +53,11 @@ import java.io.IOException;
|
||||
*/
|
||||
public class AbstractGitCommand
|
||||
{
|
||||
|
||||
/**
|
||||
* the logger for AbstractGitCommand
|
||||
*/
|
||||
private static final Logger logger = LoggerFactory.getLogger(AbstractGitCommand.class);
|
||||
|
||||
/**
|
||||
* Constructs ...
|
||||
@@ -75,6 +87,38 @@ public class AbstractGitCommand
|
||||
{
|
||||
return context.open();
|
||||
}
|
||||
|
||||
protected ObjectId getCommitOrDefault(Repository gitRepository, String requestedCommit) throws IOException {
|
||||
ObjectId commit;
|
||||
if ( Strings.isNullOrEmpty(requestedCommit) ) {
|
||||
commit = getDefaultBranch(gitRepository);
|
||||
} else {
|
||||
commit = gitRepository.resolve(requestedCommit);
|
||||
}
|
||||
return commit;
|
||||
}
|
||||
|
||||
protected ObjectId getBranchOrDefault(Repository gitRepository, String requestedBranch) throws IOException {
|
||||
ObjectId head;
|
||||
if ( Strings.isNullOrEmpty(requestedBranch) ) {
|
||||
head = getDefaultBranch(gitRepository);
|
||||
} else {
|
||||
head = GitUtil.getBranchId(gitRepository, requestedBranch);
|
||||
}
|
||||
return head;
|
||||
}
|
||||
|
||||
protected ObjectId getDefaultBranch(Repository gitRepository) throws IOException {
|
||||
ObjectId head;
|
||||
String defaultBranchName = repository.getProperty(GitConstants.PROPERTY_DEFAULT_BRANCH);
|
||||
if (!Strings.isNullOrEmpty(defaultBranchName)) {
|
||||
head = GitUtil.getBranchId(gitRepository, defaultBranchName);
|
||||
} else {
|
||||
logger.trace("no default branch configured, use repository head as default");
|
||||
head = GitUtil.getRepositoryHead(gitRepository);
|
||||
}
|
||||
return head;
|
||||
}
|
||||
|
||||
//~--- fields ---------------------------------------------------------------
|
||||
|
||||
|
||||
@@ -138,7 +138,7 @@ public abstract class AbstractGitIncomingOutgoingCommand
|
||||
|
||||
GitUtil.fetch(git, handler.getDirectory(remoteRepository), remoteRepository);
|
||||
|
||||
ObjectId localId = GitUtil.getRepositoryHead(git.getRepository());
|
||||
ObjectId localId = getDefaultBranch(git.getRepository());
|
||||
ObjectId remoteId = null;
|
||||
|
||||
Ref remoteBranch = getRemoteBranch(git.getRepository(), localId,
|
||||
|
||||
@@ -124,7 +124,7 @@ public class GitBlameCommand extends AbstractGitCommand implements BlameCommand
|
||||
|
||||
blame.setFilePath(request.getPath());
|
||||
|
||||
ObjectId revId = GitUtil.getRevisionId(gr, request.getRevision());
|
||||
ObjectId revId = getCommitOrDefault(gr, request.getRevision());
|
||||
|
||||
blame.setStartCommit(revId);
|
||||
|
||||
|
||||
@@ -105,7 +105,7 @@ public class GitBranchesCommand extends AbstractGitCommand
|
||||
|
||||
if (branchName != null)
|
||||
{
|
||||
branch = new Branch(branchName);
|
||||
branch = new Branch(branchName, GitUtil.getId(ref.getObjectId()));
|
||||
}
|
||||
|
||||
return branch;
|
||||
|
||||
@@ -71,7 +71,6 @@ import java.io.IOException;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import sonia.scm.util.IOUtil;
|
||||
|
||||
/**
|
||||
@@ -96,8 +95,6 @@ public class GitBrowseCommand extends AbstractGitCommand
|
||||
/**
|
||||
* Constructs ...
|
||||
*
|
||||
*
|
||||
*
|
||||
* @param context
|
||||
* @param repository
|
||||
*/
|
||||
@@ -124,18 +121,15 @@ public class GitBrowseCommand extends AbstractGitCommand
|
||||
public BrowserResult getBrowserResult(BrowseCommandRequest request)
|
||||
throws IOException, RepositoryException
|
||||
{
|
||||
if (logger.isDebugEnabled())
|
||||
{
|
||||
logger.debug("try to create browse result for {}", request);
|
||||
}
|
||||
logger.debug("try to create browse result for {}", request);
|
||||
|
||||
BrowserResult result = null;
|
||||
BrowserResult result;
|
||||
org.eclipse.jgit.lib.Repository repo = open();
|
||||
ObjectId revId = null;
|
||||
ObjectId revId;
|
||||
|
||||
if (Util.isEmpty(request.getRevision()))
|
||||
{
|
||||
revId = GitUtil.getRepositoryHead(repo);
|
||||
revId = getDefaultBranch(repo);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -169,70 +163,6 @@ public class GitBrowseCommand extends AbstractGitCommand
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @param files
|
||||
* @param repo
|
||||
* @param revId
|
||||
* @param path
|
||||
*
|
||||
* @throws IOException
|
||||
* @throws RepositoryException
|
||||
*/
|
||||
private void appendSubModules(List<FileObject> files,
|
||||
org.eclipse.jgit.lib.Repository repo, ObjectId revId, String path)
|
||||
throws IOException, RepositoryException
|
||||
{
|
||||
path = Util.nonNull(path);
|
||||
|
||||
Map<String, SubRepository> subRepositories = subrepositoryCache.get(revId);
|
||||
|
||||
if (subRepositories == null)
|
||||
{
|
||||
subRepositories = getSubRepositories(repo, revId);
|
||||
subrepositoryCache.put(revId, subRepositories);
|
||||
}
|
||||
|
||||
if (subRepositories != null)
|
||||
{
|
||||
for (Entry<String, SubRepository> e : subRepositories.entrySet())
|
||||
{
|
||||
String p = e.getKey();
|
||||
|
||||
if (p.startsWith(path))
|
||||
{
|
||||
p = p.substring(path.length());
|
||||
|
||||
if (p.startsWith("/"))
|
||||
{
|
||||
p = p.substring(1);
|
||||
}
|
||||
|
||||
if (p.endsWith("/"))
|
||||
{
|
||||
p = p.substring(0, p.length() - 1);
|
||||
}
|
||||
|
||||
if (!p.contains("/"))
|
||||
{
|
||||
FileObject fo = new FileObject();
|
||||
|
||||
fo.setDirectory(true);
|
||||
fo.setPath(path);
|
||||
fo.setName(p);
|
||||
fo.setSubRepository(e.getValue());
|
||||
files.add(fo);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
* @param repo
|
||||
* @param request
|
||||
* @param revId
|
||||
@@ -244,9 +174,9 @@ public class GitBrowseCommand extends AbstractGitCommand
|
||||
*/
|
||||
private FileObject createFileObject(org.eclipse.jgit.lib.Repository repo,
|
||||
BrowseCommandRequest request, ObjectId revId, TreeWalk treeWalk)
|
||||
throws IOException
|
||||
throws IOException, RepositoryException
|
||||
{
|
||||
FileObject file = null;
|
||||
FileObject file;
|
||||
|
||||
try
|
||||
{
|
||||
@@ -257,26 +187,43 @@ public class GitBrowseCommand extends AbstractGitCommand
|
||||
file.setName(treeWalk.getNameString());
|
||||
file.setPath(path);
|
||||
|
||||
ObjectLoader loader = repo.open(treeWalk.getObjectId(0));
|
||||
SubRepository sub = null;
|
||||
|
||||
file.setDirectory(loader.getType() == Constants.OBJ_TREE);
|
||||
file.setLength(loader.getSize());
|
||||
|
||||
// don't show message and date for directories to improve performance
|
||||
if (!file.isDirectory() &&!request.isDisableLastCommit())
|
||||
if (!request.isDisableSubRepositoryDetection())
|
||||
{
|
||||
logger.trace("fetch last commit for {} at {}", path, revId.getName());
|
||||
sub = getSubRepository(repo, revId, path);
|
||||
}
|
||||
|
||||
RevCommit commit = getLatestCommit(repo, revId, path);
|
||||
if (sub != null)
|
||||
{
|
||||
logger.trace("{} seems to be a sub repository", path);
|
||||
file.setDirectory(true);
|
||||
file.setSubRepository(sub);
|
||||
}
|
||||
else
|
||||
{
|
||||
ObjectLoader loader = repo.open(treeWalk.getObjectId(0));
|
||||
|
||||
if (commit != null)
|
||||
file.setDirectory(loader.getType() == Constants.OBJ_TREE);
|
||||
file.setLength(loader.getSize());
|
||||
|
||||
// don't show message and date for directories to improve performance
|
||||
if (!file.isDirectory() &&!request.isDisableLastCommit())
|
||||
{
|
||||
file.setLastModified(GitUtil.getCommitTime(commit));
|
||||
file.setDescription(commit.getShortMessage());
|
||||
}
|
||||
else if (logger.isWarnEnabled())
|
||||
{
|
||||
logger.warn("could not find latest commit for {} on {}", path, revId);
|
||||
logger.trace("fetch last commit for {} at {}", path, revId.getName());
|
||||
|
||||
RevCommit commit = getLatestCommit(repo, revId, path);
|
||||
|
||||
if (commit != null)
|
||||
{
|
||||
file.setLastModified(GitUtil.getCommitTime(commit));
|
||||
file.setDescription(commit.getShortMessage());
|
||||
}
|
||||
else if (logger.isWarnEnabled())
|
||||
{
|
||||
logger.warn("could not find latest commit for {} on {}", path,
|
||||
revId);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -386,11 +333,6 @@ public class GitBrowseCommand extends AbstractGitCommand
|
||||
|
||||
String path = request.getPath();
|
||||
|
||||
if (!request.isDisableSubRepositoryDetection())
|
||||
{
|
||||
appendSubModules(files, repo, revId, path);
|
||||
}
|
||||
|
||||
if (Util.isEmpty(path))
|
||||
{
|
||||
while (treeWalk.next())
|
||||
@@ -496,6 +438,28 @@ public class GitBrowseCommand extends AbstractGitCommand
|
||||
return subRepositories;
|
||||
}
|
||||
|
||||
private SubRepository getSubRepository(org.eclipse.jgit.lib.Repository repo,
|
||||
ObjectId revId, String path)
|
||||
throws IOException, RepositoryException
|
||||
{
|
||||
Map<String, SubRepository> subRepositories = subrepositoryCache.get(revId);
|
||||
|
||||
if (subRepositories == null)
|
||||
{
|
||||
subRepositories = getSubRepositories(repo, revId);
|
||||
subrepositoryCache.put(revId, subRepositories);
|
||||
}
|
||||
|
||||
SubRepository sub = null;
|
||||
|
||||
if (subRepositories != null)
|
||||
{
|
||||
sub = subRepositories.get(path);
|
||||
}
|
||||
|
||||
return sub;
|
||||
}
|
||||
|
||||
//~--- fields ---------------------------------------------------------------
|
||||
|
||||
/** Field description */
|
||||
|
||||
@@ -34,6 +34,7 @@ package sonia.scm.repository.spi;
|
||||
|
||||
//~--- non-JDK imports --------------------------------------------------------
|
||||
|
||||
import com.google.common.base.Strings;
|
||||
import org.eclipse.jgit.lib.Constants;
|
||||
import org.eclipse.jgit.lib.ObjectId;
|
||||
import org.eclipse.jgit.lib.ObjectLoader;
|
||||
@@ -78,7 +79,6 @@ public class GitCatCommand extends AbstractGitCommand implements CatCommand
|
||||
*
|
||||
* @param context
|
||||
* @param repository
|
||||
* @param repositoryDirectory
|
||||
*/
|
||||
public GitCatCommand(GitContext context,
|
||||
sonia.scm.repository.Repository repository)
|
||||
@@ -102,17 +102,11 @@ public class GitCatCommand extends AbstractGitCommand implements CatCommand
|
||||
public void getCatResult(CatCommandRequest request, OutputStream output)
|
||||
throws IOException, RepositoryException
|
||||
{
|
||||
if (logger.isDebugEnabled())
|
||||
{
|
||||
logger.debug("try to read content for {}", request);
|
||||
}
|
||||
|
||||
org.eclipse.jgit.lib.Repository repo = null;
|
||||
|
||||
repo = open();
|
||||
|
||||
ObjectId revId = GitUtil.getRevisionId(repo, request.getRevision());
|
||||
logger.debug("try to read content for {}", request);
|
||||
|
||||
org.eclipse.jgit.lib.Repository repo = open();
|
||||
|
||||
ObjectId revId = getCommitOrDefault(repo, request.getRevision());
|
||||
getContent(repo, revId, request.getPath(), output);
|
||||
}
|
||||
|
||||
|
||||
@@ -79,7 +79,6 @@ public class GitDiffCommand extends AbstractGitCommand implements DiffCommand
|
||||
*
|
||||
* @param context
|
||||
* @param repository
|
||||
* @param repositoryDirectory
|
||||
*/
|
||||
public GitDiffCommand(GitContext context, Repository repository)
|
||||
{
|
||||
|
||||
@@ -36,7 +36,9 @@ package sonia.scm.repository.spi;
|
||||
import org.eclipse.jgit.transport.ReceiveCommand;
|
||||
import org.eclipse.jgit.transport.ReceivePack;
|
||||
|
||||
import sonia.scm.repository.api.GitHookBranchProvider;
|
||||
import sonia.scm.repository.api.GitHookMessageProvider;
|
||||
import sonia.scm.repository.api.HookBranchProvider;
|
||||
import sonia.scm.repository.api.HookFeature;
|
||||
import sonia.scm.repository.api.HookMessageProvider;
|
||||
|
||||
@@ -45,6 +47,8 @@ import sonia.scm.repository.api.HookMessageProvider;
|
||||
import java.util.EnumSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import sonia.scm.repository.api.GitHookTagProvider;
|
||||
import sonia.scm.repository.api.HookTagProvider;
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -55,33 +59,28 @@ public class GitHookContextProvider extends HookContextProvider
|
||||
|
||||
/** Field description */
|
||||
private static final Set<HookFeature> SUPPORTED_FEATURES =
|
||||
EnumSet.of(HookFeature.MESSAGE_PROVIDER, HookFeature.CHANGESET_PROVIDER);
|
||||
EnumSet.of(HookFeature.MESSAGE_PROVIDER, HookFeature.CHANGESET_PROVIDER,
|
||||
HookFeature.BRANCH_PROVIDER, HookFeature.TAG_PROVIDER);
|
||||
|
||||
//~--- constructors ---------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Constructs ...
|
||||
* Constructs a new instance
|
||||
*
|
||||
*
|
||||
* @param receivePack
|
||||
* @param receiveCommands
|
||||
* @param receivePack git receive pack
|
||||
* @param receiveCommands received commands
|
||||
*/
|
||||
public GitHookContextProvider(ReceivePack receivePack,
|
||||
List<ReceiveCommand> receiveCommands)
|
||||
{
|
||||
this.receivePack = receivePack;
|
||||
this.receiveCommands = receiveCommands;
|
||||
this.changesetProvider = new GitHookChangesetProvider(receivePack,
|
||||
receiveCommands);
|
||||
}
|
||||
|
||||
//~--- methods --------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public HookMessageProvider createMessageProvider()
|
||||
{
|
||||
@@ -90,24 +89,23 @@ public class GitHookContextProvider extends HookContextProvider
|
||||
|
||||
//~--- get methods ----------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public HookBranchProvider getBranchProvider()
|
||||
{
|
||||
return new GitHookBranchProvider(receiveCommands);
|
||||
}
|
||||
|
||||
@Override
|
||||
public HookTagProvider getTagProvider() {
|
||||
return new GitHookTagProvider(receiveCommands);
|
||||
}
|
||||
|
||||
@Override
|
||||
public HookChangesetProvider getChangesetProvider()
|
||||
{
|
||||
return changesetProvider;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public Set<HookFeature> getSupportedFeatures()
|
||||
{
|
||||
@@ -117,8 +115,11 @@ public class GitHookContextProvider extends HookContextProvider
|
||||
//~--- fields ---------------------------------------------------------------
|
||||
|
||||
/** Field description */
|
||||
private GitHookChangesetProvider changesetProvider;
|
||||
private final GitHookChangesetProvider changesetProvider;
|
||||
|
||||
/** Field description */
|
||||
private ReceivePack receivePack;
|
||||
private final List<ReceiveCommand> receiveCommands;
|
||||
|
||||
/** Field description */
|
||||
private final ReceivePack receivePack;
|
||||
}
|
||||
|
||||
@@ -221,17 +221,8 @@ public class GitLogCommand extends AbstractGitCommand implements LogCommand
|
||||
AndTreeFilter.create(
|
||||
PathFilter.create(request.getPath()), TreeFilter.ANY_DIFF));
|
||||
}
|
||||
|
||||
ObjectId head = null;
|
||||
|
||||
if (!Strings.isNullOrEmpty(request.getBranch()))
|
||||
{
|
||||
head = GitUtil.getBranchId(gr, request.getBranch());
|
||||
}
|
||||
else
|
||||
{
|
||||
head = GitUtil.getRepositoryHead(gr);
|
||||
}
|
||||
|
||||
ObjectId head = getBranchOrDefault(gr, request.getBranch());
|
||||
|
||||
if (head != null)
|
||||
{
|
||||
|
||||
@@ -0,0 +1,195 @@
|
||||
/**
|
||||
* Copyright (c) 2014, Sebastian Sdorra All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer. 2. Redistributions in
|
||||
* binary form must reproduce the above copyright notice, this list of
|
||||
* conditions and the following disclaimer in the documentation and/or other
|
||||
* materials provided with the distribution. 3. Neither the name of SCM-Manager;
|
||||
* nor the names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* http://bitbucket.org/sdorra/scm-manager
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
|
||||
package sonia.scm.web;
|
||||
|
||||
//~--- non-JDK imports --------------------------------------------------------
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
|
||||
import org.eclipse.jgit.lib.ObjectId;
|
||||
import org.eclipse.jgit.lib.ObjectIdSubclassMap;
|
||||
import org.eclipse.jgit.revwalk.RevObject;
|
||||
import org.eclipse.jgit.transport.BaseReceivePack;
|
||||
import org.eclipse.jgit.transport.BaseReceivePack.PackParserListener;
|
||||
import org.eclipse.jgit.transport.PackParser;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
//~--- JDK imports ------------------------------------------------------------
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Implementation of {@link PackParserListener} to collect every object which is
|
||||
* pushed with the reveive pack. The listener is used to find out which object
|
||||
* is new and which was already pushed.
|
||||
*
|
||||
* @author Sebastian Sdorra
|
||||
*/
|
||||
public class CollectingPackParserListener implements PackParserListener
|
||||
{
|
||||
|
||||
/**
|
||||
* the logger for CollectingPackParserListener
|
||||
*/
|
||||
private static final Logger logger =
|
||||
LoggerFactory.getLogger(CollectingPackParserListener.class);
|
||||
|
||||
//~--- get methods ----------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Returns the listener from the receive pack.
|
||||
*
|
||||
*
|
||||
* @param pack receive pack
|
||||
*
|
||||
* @return listener
|
||||
*/
|
||||
public static CollectingPackParserListener get(BaseReceivePack pack)
|
||||
{
|
||||
PackParserListener listener = pack.getPackParserListener();
|
||||
|
||||
if (listener == null)
|
||||
{
|
||||
throw new IllegalArgumentException(
|
||||
"receive pack does not contain a listener");
|
||||
}
|
||||
|
||||
Preconditions.checkArgument(
|
||||
listener instanceof CollectingPackParserListener,
|
||||
"listener is not a CollectingPackParserListener");
|
||||
|
||||
return (CollectingPackParserListener) listener;
|
||||
}
|
||||
|
||||
//~--- set methods ----------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Applies the listener to the receive pack.
|
||||
*
|
||||
*
|
||||
* @param pack receive pack
|
||||
*/
|
||||
public static void set(BaseReceivePack pack)
|
||||
{
|
||||
logger.trace("apply collecting listener to receive pack");
|
||||
pack.setPackParserListener(new CollectingPackParserListener());
|
||||
}
|
||||
|
||||
//~--- methods --------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Collects all new object ids.
|
||||
*
|
||||
*
|
||||
* @param parser pack parser
|
||||
*/
|
||||
@Override
|
||||
public void after(PackParser parser)
|
||||
{
|
||||
logger.trace("retrieve new object ids from pack parser");
|
||||
|
||||
ObjectIdSubclassMap<ObjectId> newObjectIdMap = parser.getNewObjectIds();
|
||||
|
||||
if (newObjectIdMap != null)
|
||||
{
|
||||
newObjectIds = ImmutableSet.copyOf(newObjectIdMap);
|
||||
}
|
||||
else
|
||||
{
|
||||
logger.warn("pack parser returned no newObjectIds");
|
||||
newObjectIds = ImmutableSet.of();
|
||||
}
|
||||
|
||||
if (newObjectIds.isEmpty())
|
||||
{
|
||||
logger.debug("new object ids are empty, we treat every commit as new");
|
||||
}
|
||||
else
|
||||
{
|
||||
logger.debug("collected {} new object ids", newObjectIds.size());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepares the pack parser to retrieve the new object ids.
|
||||
*
|
||||
*
|
||||
* @param parser pack parser
|
||||
*/
|
||||
@Override
|
||||
public void before(PackParser parser)
|
||||
{
|
||||
logger.trace("prepare pack parser to collect new object ids");
|
||||
parser.setNeedNewObjectIds(true);
|
||||
}
|
||||
|
||||
//~--- get methods ----------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Returns {@code true} if the object is a new object. The method will also
|
||||
* return {@code true}, if the pack parser does not return a list with new
|
||||
* object ids.
|
||||
*
|
||||
*
|
||||
* @param object rev object
|
||||
*
|
||||
* @return {@code true} if the object is new
|
||||
*/
|
||||
public boolean isNew(RevObject object)
|
||||
{
|
||||
ensureAfterWasCalled();
|
||||
|
||||
return newObjectIds.isEmpty() || newObjectIds.contains(object.getId());
|
||||
}
|
||||
|
||||
//~--- methods --------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Throws an {@link IllegalStateException} if the after method was not called.
|
||||
*/
|
||||
private void ensureAfterWasCalled()
|
||||
{
|
||||
if (newObjectIds == null)
|
||||
{
|
||||
throw new IllegalStateException( "Pack parser seem not to be finished. "
|
||||
+ "The receive pack has not called the after method of the listener.");
|
||||
}
|
||||
}
|
||||
|
||||
//~--- fields ---------------------------------------------------------------
|
||||
|
||||
/** set of new object ids */
|
||||
private Set<ObjectId> newObjectIds;
|
||||
}
|
||||
@@ -35,27 +35,18 @@ package sonia.scm.web;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
|
||||
import org.eclipse.jgit.http.server.GitSmartHttpTools;
|
||||
|
||||
import sonia.scm.ClientMessages;
|
||||
import sonia.scm.Priority;
|
||||
import sonia.scm.config.ScmConfiguration;
|
||||
import sonia.scm.filter.Filters;
|
||||
import sonia.scm.filter.WebElement;
|
||||
import sonia.scm.repository.GitUtil;
|
||||
import sonia.scm.web.filter.AuthenticationFilter;
|
||||
|
||||
//~--- JDK imports ------------------------------------------------------------
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
/**
|
||||
*
|
||||
* Handles git specific basic authentication.
|
||||
*
|
||||
* @author Sebastian Sdorra
|
||||
*/
|
||||
@Priority(Filters.PRIORITY_AUTHENTICATION)
|
||||
@@ -64,11 +55,10 @@ public class GitBasicAuthenticationFilter extends AuthenticationFilter
|
||||
{
|
||||
|
||||
/**
|
||||
* Constructs ...
|
||||
* Constructs a new instance.
|
||||
*
|
||||
*
|
||||
* @param configuration
|
||||
* @param webTokenGenerators
|
||||
* @param configuration scm-manager main configuration
|
||||
* @param webTokenGenerators web token generators
|
||||
*/
|
||||
@Inject
|
||||
public GitBasicAuthenticationFilter(ScmConfiguration configuration,
|
||||
@@ -76,32 +66,4 @@ public class GitBasicAuthenticationFilter extends AuthenticationFilter
|
||||
{
|
||||
super(configuration, webTokenGenerators);
|
||||
}
|
||||
|
||||
//~--- methods --------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @param request
|
||||
* @param response
|
||||
*
|
||||
* @throws IOException
|
||||
*/
|
||||
@Override
|
||||
protected void sendFailedAuthenticationError(HttpServletRequest request,
|
||||
HttpServletResponse response)
|
||||
throws IOException
|
||||
{
|
||||
if (GitUtil.isGitClient(request))
|
||||
{
|
||||
GitSmartHttpTools.sendError(request, response,
|
||||
HttpServletResponse.SC_FORBIDDEN,
|
||||
ClientMessages.get(request).failedAuthentication());
|
||||
}
|
||||
else
|
||||
{
|
||||
super.sendFailedAuthenticationError(request, response);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -96,7 +96,9 @@ public class GitReceivePackFactory
|
||||
|
||||
rpack.setPreReceiveHook(hook);
|
||||
rpack.setPostReceiveHook(hook);
|
||||
|
||||
// apply collecting listener, to be able to check which commits are new
|
||||
CollectingPackParserListener.set(rpack);
|
||||
|
||||
return rpack;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,97 @@
|
||||
/**
|
||||
* Copyright (c) 2010, Sebastian Sdorra All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer. 2. Redistributions in
|
||||
* binary form must reproduce the above copyright notice, this list of
|
||||
* conditions and the following disclaimer in the documentation and/or other
|
||||
* materials provided with the distribution. 3. Neither the name of SCM-Manager;
|
||||
* nor the names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* http://bitbucket.org/sdorra/scm-manager
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
|
||||
package sonia.scm.web;
|
||||
|
||||
//~--- non-JDK imports --------------------------------------------------------
|
||||
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import com.google.common.base.Charsets;
|
||||
|
||||
import sonia.scm.plugin.Extension;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Sebastian Sdorra <sebastian.sdorra@gmail.com>
|
||||
* @since 1.45
|
||||
*/
|
||||
@Extension
|
||||
public class GitUserAgentProvider implements UserAgentProvider
|
||||
{
|
||||
|
||||
/** Field description */
|
||||
@VisibleForTesting
|
||||
static final UserAgent GIT = UserAgent.builder("Git").browser(
|
||||
false).basicAuthenticationCharset(
|
||||
Charsets.UTF_8).build();
|
||||
|
||||
/** Field description */
|
||||
@VisibleForTesting
|
||||
static final UserAgent MSYSGIT = UserAgent.builder("msysGit").browser(
|
||||
false).basicAuthenticationCharset(
|
||||
Charsets.UTF_8).build();
|
||||
|
||||
/** Field description */
|
||||
private static final String PREFIX = "git/";
|
||||
|
||||
/** Field description */
|
||||
private static final String SUFFIX = "msysgit";
|
||||
|
||||
//~--- methods --------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @param userAgentString
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public UserAgent parseUserAgent(String userAgentString)
|
||||
{
|
||||
UserAgent ua = null;
|
||||
|
||||
if (userAgentString.startsWith(PREFIX))
|
||||
{
|
||||
if (userAgentString.contains(SUFFIX))
|
||||
{
|
||||
ua = MSYSGIT;
|
||||
}
|
||||
else
|
||||
{
|
||||
ua = GIT;
|
||||
}
|
||||
}
|
||||
|
||||
return ua;
|
||||
}
|
||||
}
|
||||
@@ -54,6 +54,7 @@ import java.io.IOException;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import sonia.scm.repository.RepositoryException;
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -170,7 +171,11 @@ public class ScmGitServlet extends GitServlet
|
||||
{
|
||||
repositoryViewer.handleRequest(request, response, scmRepository);
|
||||
}
|
||||
catch (Exception ex)
|
||||
catch (RepositoryException ex)
|
||||
{
|
||||
throw new ServletException("could not create repository view", ex);
|
||||
}
|
||||
catch (IOException ex)
|
||||
{
|
||||
throw new ServletException("could not create repository view", ex);
|
||||
}
|
||||
@@ -184,11 +189,11 @@ public class ScmGitServlet extends GitServlet
|
||||
//~--- fields ---------------------------------------------------------------
|
||||
|
||||
/** Field description */
|
||||
private RepositoryProvider repositoryProvider;
|
||||
private final RepositoryProvider repositoryProvider;
|
||||
|
||||
/** Field description */
|
||||
private RepositoryRequestListenerUtil repositoryRequestListenerUtil;
|
||||
private final RepositoryRequestListenerUtil repositoryRequestListenerUtil;
|
||||
|
||||
/** Field description */
|
||||
private GitRepositoryViewer repositoryViewer;
|
||||
private final GitRepositoryViewer repositoryViewer;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user