Merged in feature/repository_namespaces (pull request #52)

Feature/repository namespaces
This commit is contained in:
Johannes Schnatterer
2018-07-16 12:51:24 +00:00
58 changed files with 1299 additions and 2434 deletions

19
pom.xml
View File

@@ -225,6 +225,23 @@
</executions> </executions>
</plugin> </plugin>
<plugin>
<groupId>com.github.legman</groupId>
<artifactId>legman-maven-plugin</artifactId>
<version>${legman.version}</version>
<configuration>
<fail>true</fail>
</configuration>
<executions>
<execution>
<phase>process-classes</phase>
<goals>
<goal>guava-migration-check</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId> <artifactId>maven-compiler-plugin</artifactId>
@@ -513,7 +530,7 @@
<guice.version>4.0</guice.version> <guice.version>4.0</guice.version>
<!-- event bus --> <!-- event bus -->
<legman.version>1.2.0</legman.version> <legman.version>1.3.0</legman.version>
<!-- webserver --> <!-- webserver -->
<jetty.version>9.2.10.v20150310</jetty.version> <jetty.version>9.2.10.v20150310</jetty.version>

View File

@@ -1,10 +1,10 @@
/** /**
* Copyright (c) 2010, Sebastian Sdorra * Copyright (c) 2010, Sebastian Sdorra
* All rights reserved. * All rights reserved.
* * <p>
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met: * modification, are permitted provided that the following conditions are met:
* * <p>
* 1. Redistributions of source code must retain the above copyright notice, * 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer. * this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice, * 2. Redistributions in binary form must reproduce the above copyright notice,
@@ -13,7 +13,7 @@
* 3. Neither the name of SCM-Manager; nor the names of its * 3. Neither the name of SCM-Manager; nor the names of its
* contributors may be used to endorse or promote products derived from this * contributors may be used to endorse or promote products derived from this
* software without specific prior written permission. * software without specific prior written permission.
* * <p>
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
@@ -24,39 +24,32 @@
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * 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 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* * <p>
* http://bitbucket.org/sdorra/scm-manager * http://bitbucket.org/sdorra/scm-manager
*
*/ */
package sonia.scm.config; package sonia.scm.config;
//~--- non-JDK imports --------------------------------------------------------
import com.google.common.collect.Sets; import com.google.common.collect.Sets;
import com.google.inject.Singleton; import com.google.inject.Singleton;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import sonia.scm.event.ScmEventBus; import sonia.scm.event.ScmEventBus;
import sonia.scm.util.HttpUtil; import sonia.scm.util.HttpUtil;
import sonia.scm.xml.XmlSetStringAdapter; import sonia.scm.xml.XmlSetStringAdapter;
//~--- JDK imports ------------------------------------------------------------
import java.io.File;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import javax.xml.bind.annotation.XmlAccessType; import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType; import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement; import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement; import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter; import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
import java.io.File;
import java.util.Set;
import java.util.concurrent.TimeUnit;
//~--- JDK imports ------------------------------------------------------------
/** /**
* The main configuration object for SCM-Manager. * The main configuration object for SCM-Manager.
@@ -67,38 +60,137 @@ import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
@Singleton @Singleton
@XmlRootElement(name = "scm-config") @XmlRootElement(name = "scm-config")
@XmlAccessorType(XmlAccessType.FIELD) @XmlAccessorType(XmlAccessType.FIELD)
public class ScmConfiguration public class ScmConfiguration {
{
/** Default JavaScript date format */ /**
* Default JavaScript date format
*/
public static final String DEFAULT_DATEFORMAT = "YYYY-MM-DD HH:mm:ss"; public static final String DEFAULT_DATEFORMAT = "YYYY-MM-DD HH:mm:ss";
/** Default plugin url */ /**
* Default plugin url
*/
public static final String DEFAULT_PLUGINURL = public static final String DEFAULT_PLUGINURL =
"http://plugins.scm-manager.org/scm-plugin-backend/api/{version}/plugins?os={os}&arch={arch}&snapshot=false"; "http://plugins.scm-manager.org/scm-plugin-backend/api/{version}/plugins?os={os}&arch={arch}&snapshot=false";
/** Default plugin url from version 1.0 */ /**
* Default plugin url from version 1.0
*/
public static final String OLD_PLUGINURL = public static final String OLD_PLUGINURL =
"http://plugins.scm-manager.org/plugins.xml.gz"; "http://plugins.scm-manager.org/plugins.xml.gz";
/** Path to the configuration file */ /**
* Path to the configuration file
*/
public static final String PATH = public static final String PATH =
"config".concat(File.separator).concat("config.xml"); "config".concat(File.separator).concat("config.xml");
/** the logger for ScmConfiguration */ /**
* the logger for ScmConfiguration
*/
private static final Logger logger = private static final Logger logger =
LoggerFactory.getLogger(ScmConfiguration.class); LoggerFactory.getLogger(ScmConfiguration.class);
//~--- methods --------------------------------------------------------------
@XmlElement(name = "admin-groups")
@XmlJavaTypeAdapter(XmlSetStringAdapter.class)
private Set<String> adminGroups;
@XmlElement(name = "admin-users")
@XmlJavaTypeAdapter(XmlSetStringAdapter.class)
private Set<String> adminUsers;
@XmlElement(name = "base-url")
private String baseUrl;
@XmlElement(name = "force-base-url")
private boolean forceBaseUrl;
/**
* Maximum allowed login attempts.
*
* @since 1.34
*/
@XmlElement(name = "login-attempt-limit")
private int loginAttemptLimit = -1;
/**
* glob patterns for urls which are excluded from proxy
*/
@XmlElement(name = "proxy-excludes")
@XmlJavaTypeAdapter(XmlSetStringAdapter.class)
private Set<String> proxyExcludes;
private String proxyPassword;
private int proxyPort = 8080;
private String proxyServer = "proxy.mydomain.com";
private String proxyUser;
/**
* Skip failed authenticators.
*
* @since 1.36
*/
@XmlElement(name = "skip-failed-authenticators")
private boolean skipFailedAuthenticators = false;
@XmlElement(name = "plugin-url")
private String pluginUrl = DEFAULT_PLUGINURL;
/**
* Login attempt timeout.
*
* @since 1.34
*/
@XmlElement(name = "login-attempt-limit-timeout")
private long loginAttemptLimitTimeout = TimeUnit.MINUTES.toSeconds(5l);
private boolean enableProxy = false;
/**
* Authentication realm for basic authentication.
*/
private String realmDescription = HttpUtil.AUTHENTICATION_REALM;
private boolean enableRepositoryArchive = false;
private boolean disableGroupingGrid = false;
/**
* JavaScript date format from moment.js
*
* @see <a href="http://momentjs.com/docs/#/parsing/" target="_blank">http://momentjs.com/docs/#/parsing/</a>
*/
private String dateFormat = DEFAULT_DATEFORMAT;
private boolean anonymousAccessEnabled = false;
/**
* Enables xsrf cookie protection.
*
* @since 1.47
*/
@XmlElement(name = "xsrf-protection")
private boolean enabledXsrfProtection = true;
@XmlElement(name = "default-namespace-strategy")
private String defaultNamespaceStrategy = "sonia.scm.repository.DefaultNamespaceStrategy";
/** /**
* Calls the {@link sonia.scm.ConfigChangedListener#configChanged(Object)} * Calls the {@link sonia.scm.ConfigChangedListener#configChanged(Object)}
* method of all registered listeners. * method of all registered listeners.
*/ */
public void fireChangeEvent() public void fireChangeEvent() {
{ if (logger.isDebugEnabled()) {
if (logger.isDebugEnabled())
{
logger.debug("fire config changed event"); logger.debug("fire config changed event");
} }
@@ -109,12 +201,9 @@ public class ScmConfiguration
/** /**
* Load all properties from another {@link ScmConfiguration} object. * Load all properties from another {@link ScmConfiguration} object.
* *
*
*
* @param other * @param other
*/ */
public void load(ScmConfiguration other) public void load(ScmConfiguration other) {
{
this.realmDescription = other.realmDescription; this.realmDescription = other.realmDescription;
this.dateFormat = other.dateFormat; this.dateFormat = other.dateFormat;
this.pluginUrl = other.pluginUrl; this.pluginUrl = other.pluginUrl;
@@ -135,29 +224,14 @@ public class ScmConfiguration
this.loginAttemptLimit = other.loginAttemptLimit; this.loginAttemptLimit = other.loginAttemptLimit;
this.loginAttemptLimitTimeout = other.loginAttemptLimitTimeout; this.loginAttemptLimitTimeout = other.loginAttemptLimitTimeout;
this.enabledXsrfProtection = other.enabledXsrfProtection; this.enabledXsrfProtection = other.enabledXsrfProtection;
this.defaultNamespaceStrategy = other.defaultNamespaceStrategy;
} }
//~--- get methods ---------------------------------------------------------- public Set<String> getAdminGroups() {
/**
* Returns a set of admin group names.
*
*
* @return set of admin group names
*/
public Set<String> getAdminGroups()
{
return adminGroups; return adminGroups;
} }
/** public Set<String> getAdminUsers() {
* Returns a set of admin user names.
*
*
* @return set of admin user names
*/
public Set<String> getAdminUsers()
{
return adminUsers; return adminUsers;
} }
@@ -165,11 +239,10 @@ public class ScmConfiguration
* Returns the complete base url of the scm-manager including the context path. * Returns the complete base url of the scm-manager including the context path.
* For example http://localhost:8080/scm * For example http://localhost:8080/scm
* *
* @since 1.5
* @return complete base url of the scm-manager * @return complete base url of the scm-manager
* @since 1.5
*/ */
public String getBaseUrl() public String getBaseUrl() {
{
return baseUrl; return baseUrl;
} }
@@ -177,23 +250,14 @@ public class ScmConfiguration
* Returns the date format for the user interface. This format is a * Returns the date format for the user interface. This format is a
* JavaScript date format, from the library moment.js. * JavaScript date format, from the library moment.js.
* *
* @see <a href="http://momentjs.com/docs/#/parsing/" target="_blank">http://momentjs.com/docs/#/parsing/</a>
* @return moment.js date format * @return moment.js date format
* @see <a href="http://momentjs.com/docs/#/parsing/" target="_blank">http://momentjs.com/docs/#/parsing/</a>
*/ */
public String getDateFormat() public String getDateFormat() {
{
return dateFormat; return dateFormat;
} }
/** public int getLoginAttemptLimit() {
* Returns maximum allowed login attempts.
*
* @return maximum allowed login attempts
*
* @since 1.34
*/
public int getLoginAttemptLimit()
{
return loginAttemptLimit; return loginAttemptLimit;
} }
@@ -202,11 +266,9 @@ public class ScmConfiguration
* because of too many failed login attempts. * because of too many failed login attempts.
* *
* @return login attempt timeout in seconds * @return login attempt timeout in seconds
*
* @since 1.34 * @since 1.34
*/ */
public long getLoginAttemptLimitTimeout() public long getLoginAttemptLimitTimeout() {
{
return loginAttemptLimitTimeout; return loginAttemptLimitTimeout;
} }
@@ -222,8 +284,7 @@ public class ScmConfiguration
* *
* @return the complete plugin url. * @return the complete plugin url.
*/ */
public String getPluginUrl() public String getPluginUrl() {
{
return pluginUrl; return pluginUrl;
} }
@@ -231,289 +292,141 @@ public class ScmConfiguration
* Returns a set of glob patterns for urls which should excluded from * Returns a set of glob patterns for urls which should excluded from
* proxy settings. * proxy settings.
* *
*
* @return set of glob patterns * @return set of glob patterns
* @since 1.23 * @since 1.23
*/ */
public Set<String> getProxyExcludes() public Set<String> getProxyExcludes() {
{ if (proxyExcludes == null) {
if (proxyExcludes == null)
{
proxyExcludes = Sets.newHashSet(); proxyExcludes = Sets.newHashSet();
} }
return proxyExcludes; return proxyExcludes;
} }
/** public String getProxyPassword() {
* Method description
*
*
* @return
* @since 1.7
*/
public String getProxyPassword()
{
return proxyPassword; return proxyPassword;
} }
/** public int getProxyPort() {
* Returns the proxy port.
*
*
* @return proxy port
*/
public int getProxyPort()
{
return proxyPort; return proxyPort;
} }
/** /**
* Returns the servername or ip of the proxyserver. * Returns the servername or ip of the proxyserver.
* *
*
* @return servername or ip of the proxyserver * @return servername or ip of the proxyserver
*/ */
public String getProxyServer() public String getProxyServer() {
{
return proxyServer; return proxyServer;
} }
/** public String getProxyUser() {
* Method description
*
*
* @return
* @since 1.7
*/
public String getProxyUser()
{
return proxyUser; return proxyUser;
} }
/** public String getRealmDescription() {
* Returns the realm description.
*
*
* @return realm description
* @since 1.36
*/
public String getRealmDescription()
{
return realmDescription; return realmDescription;
} }
public boolean isAnonymousAccessEnabled() {
/**
* Returns true if the anonymous access to the SCM-Manager is enabled.
*
*
* @return true if the anonymous access to the SCM-Manager is enabled
*/
public boolean isAnonymousAccessEnabled()
{
return anonymousAccessEnabled; return anonymousAccessEnabled;
} }
/** public boolean isDisableGroupingGrid() {
* Method description
*
* @since 1.9
* @return
*/
public boolean isDisableGroupingGrid()
{
return disableGroupingGrid; return disableGroupingGrid;
} }
/** /**
* Returns {@code true} if the cookie xsrf protection is enabled. * Returns {@code true} if the cookie xsrf protection is enabled.
* *
* @see <a href="https://goo.gl/s67xO3">Issue 793</a>
* @return {@code true} if the cookie xsrf protection is enabled * @return {@code true} if the cookie xsrf protection is enabled
* * @see <a href="https://goo.gl/s67xO3">Issue 793</a>
* @since 1.47 * @since 1.47
*/ */
public boolean isEnabledXsrfProtection() public boolean isEnabledXsrfProtection() {
{
return enabledXsrfProtection; return enabledXsrfProtection;
} }
/** public boolean isEnableProxy() {
* Returns true if proxy is enabled.
*
*
* @return true if proxy is enabled
*/
public boolean isEnableProxy()
{
return enableProxy; return enableProxy;
} }
/** public boolean isEnableRepositoryArchive() {
* Returns true if the repository archive is enabled.
*
*
* @return true if the repository archive is enabled
* @since 1.14
*/
public boolean isEnableRepositoryArchive()
{
return enableRepositoryArchive; return enableRepositoryArchive;
} }
/** public boolean isForceBaseUrl() {
* Returns true if force base url is enabled.
*
* @since 1.5
* @return true if force base url is enabled
*/
public boolean isForceBaseUrl()
{
return forceBaseUrl; return forceBaseUrl;
} }
/** public boolean isLoginAttemptLimitEnabled() {
* Returns true if the login attempt limit is enabled.
*
*
* @return true if login attempt limit is enabled
*
* @since 1.37
*/
public boolean isLoginAttemptLimitEnabled()
{
return loginAttemptLimit > 0; return loginAttemptLimit > 0;
} }
public String getDefaultNamespaceStrategy() {
return defaultNamespaceStrategy;
}
/** /**
* Returns true if failed authenticators are skipped. * Returns true if failed authenticators are skipped.
* *
*
* @return true if failed authenticators are skipped * @return true if failed authenticators are skipped
*
* @since 1.36 * @since 1.36
*/ */
public boolean isSkipFailedAuthenticators() public boolean isSkipFailedAuthenticators() {
{
return skipFailedAuthenticators; return skipFailedAuthenticators;
} }
//~--- set methods ---------------------------------------------------------- public void setAdminGroups(Set<String> adminGroups) {
/**
* Method description
*
*
* @param adminGroups
*/
public void setAdminGroups(Set<String> adminGroups)
{
this.adminGroups = adminGroups; this.adminGroups = adminGroups;
} }
/** public void setAdminUsers(Set<String> adminUsers) {
* Method description
*
*
* @param adminUsers
*/
public void setAdminUsers(Set<String> adminUsers)
{
this.adminUsers = adminUsers; this.adminUsers = adminUsers;
} }
/** public void setAnonymousAccessEnabled(boolean anonymousAccessEnabled) {
* Method description
*
*
* @param anonymousAccessEnabled
*/
public void setAnonymousAccessEnabled(boolean anonymousAccessEnabled)
{
this.anonymousAccessEnabled = anonymousAccessEnabled; this.anonymousAccessEnabled = anonymousAccessEnabled;
} }
/** public void setBaseUrl(String baseUrl) {
* Method description
*
*
* @param baseUrl
* @since 1.5
*/
public void setBaseUrl(String baseUrl)
{
this.baseUrl = baseUrl; this.baseUrl = baseUrl;
} }
/** public void setDateFormat(String dateFormat) {
* Sets the date format for the ui.
*
*
* @param dateFormat date format for ui
*/
public void setDateFormat(String dateFormat)
{
this.dateFormat = dateFormat; this.dateFormat = dateFormat;
} }
/** public void setDisableGroupingGrid(boolean disableGroupingGrid) {
* Method description
*
* @since 1.9
*
* @param disableGroupingGrid
*/
public void setDisableGroupingGrid(boolean disableGroupingGrid)
{
this.disableGroupingGrid = disableGroupingGrid; this.disableGroupingGrid = disableGroupingGrid;
} }
/** public void setEnableProxy(boolean enableProxy) {
* Method description
*
*
* @param enableProxy
*/
public void setEnableProxy(boolean enableProxy)
{
this.enableProxy = enableProxy; this.enableProxy = enableProxy;
} }
/** /**
* Enable or disable the repository archive. Default is disabled. * Enable or disable the repository archive. Default is disabled.
* *
*
* @param enableRepositoryArchive true to disable the repository archive * @param enableRepositoryArchive true to disable the repository archive
* @since 1.14 * @since 1.14
*/ */
public void setEnableRepositoryArchive(boolean enableRepositoryArchive) public void setEnableRepositoryArchive(boolean enableRepositoryArchive) {
{
this.enableRepositoryArchive = enableRepositoryArchive; this.enableRepositoryArchive = enableRepositoryArchive;
} }
/** public void setForceBaseUrl(boolean forceBaseUrl) {
* Method description
*
*
* @param forceBaseUrl
* @since 1.5
*/
public void setForceBaseUrl(boolean forceBaseUrl)
{
this.forceBaseUrl = forceBaseUrl; this.forceBaseUrl = forceBaseUrl;
} }
/** /**
* Set maximum allowed login attempts. * Set maximum allowed login attempts.
* *
*
* @param loginAttemptLimit login attempt limit * @param loginAttemptLimit login attempt limit
*
* @since 1.34 * @since 1.34
*/ */
public void setLoginAttemptLimit(int loginAttemptLimit) public void setLoginAttemptLimit(int loginAttemptLimit) {
{
this.loginAttemptLimit = loginAttemptLimit; this.loginAttemptLimit = loginAttemptLimit;
} }
@@ -522,22 +435,13 @@ public class ScmConfiguration
* because of too many failed login attempts. * because of too many failed login attempts.
* *
* @param loginAttemptLimitTimeout login attempt timeout in seconds * @param loginAttemptLimitTimeout login attempt timeout in seconds
*
* @since 1.34 * @since 1.34
*/ */
public void setLoginAttemptLimitTimeout(long loginAttemptLimitTimeout) public void setLoginAttemptLimitTimeout(long loginAttemptLimitTimeout) {
{
this.loginAttemptLimitTimeout = loginAttemptLimitTimeout; this.loginAttemptLimitTimeout = loginAttemptLimitTimeout;
} }
/** public void setPluginUrl(String pluginUrl) {
* Method description
*
*
* @param pluginUrl
*/
public void setPluginUrl(String pluginUrl)
{
this.pluginUrl = pluginUrl; this.pluginUrl = pluginUrl;
} }
@@ -545,70 +449,30 @@ public class ScmConfiguration
* Set glob patterns for urls which are should be excluded from proxy * Set glob patterns for urls which are should be excluded from proxy
* settings. * settings.
* *
*
* @param proxyExcludes glob patterns * @param proxyExcludes glob patterns
* @since 1.23 * @since 1.23
*/ */
public void setProxyExcludes(Set<String> proxyExcludes) public void setProxyExcludes(Set<String> proxyExcludes) {
{
this.proxyExcludes = proxyExcludes; this.proxyExcludes = proxyExcludes;
} }
/** public void setProxyPassword(String proxyPassword) {
* Method description
*
*
* @param proxyPassword
* @since 1.7
*/
public void setProxyPassword(String proxyPassword)
{
this.proxyPassword = proxyPassword; this.proxyPassword = proxyPassword;
} }
/** public void setProxyPort(int proxyPort) {
* Method description
*
*
* @param proxyPort
*/
public void setProxyPort(int proxyPort)
{
this.proxyPort = proxyPort; this.proxyPort = proxyPort;
} }
/** public void setProxyServer(String proxyServer) {
* Method description
*
*
* @param proxyServer
*/
public void setProxyServer(String proxyServer)
{
this.proxyServer = proxyServer; this.proxyServer = proxyServer;
} }
/** public void setProxyUser(String proxyUser) {
* Method description
*
*
* @param proxyUser
* @since 1.7
*/
public void setProxyUser(String proxyUser)
{
this.proxyUser = proxyUser; this.proxyUser = proxyUser;
} }
/** public void setRealmDescription(String realmDescription) {
* Sets the realm description.
*
*
* @param realmDescription
* @since 1.36
*/
public void setRealmDescription(String realmDescription)
{
this.realmDescription = realmDescription; this.realmDescription = realmDescription;
} }
@@ -617,11 +481,9 @@ public class ScmConfiguration
* authenticator finds the user but fails to authenticate the user. * authenticator finds the user but fails to authenticate the user.
* *
* @param skipFailedAuthenticators true to skip failed authenticators * @param skipFailedAuthenticators true to skip failed authenticators
*
* @since 1.36 * @since 1.36
*/ */
public void setSkipFailedAuthenticators(boolean skipFailedAuthenticators) public void setSkipFailedAuthenticators(boolean skipFailedAuthenticators) {
{
this.skipFailedAuthenticators = skipFailedAuthenticators; this.skipFailedAuthenticators = skipFailedAuthenticators;
} }
@@ -630,109 +492,13 @@ public class ScmConfiguration
* *
* @param enabledXsrfProtection {@code true} to enable xsrf protection * @param enabledXsrfProtection {@code true} to enable xsrf protection
* @see <a href="https://goo.gl/s67xO3">Issue 793</a> * @see <a href="https://goo.gl/s67xO3">Issue 793</a>
*
* @since 1.47 * @since 1.47
*/ */
public void setEnabledXsrfProtection(boolean enabledXsrfProtection) public void setEnabledXsrfProtection(boolean enabledXsrfProtection) {
{
this.enabledXsrfProtection = enabledXsrfProtection; this.enabledXsrfProtection = enabledXsrfProtection;
} }
//~--- fields --------------------------------------------------------------- public void setDefaultNamespaceStrategy(String defaultNamespaceStrategy) {
this.defaultNamespaceStrategy = defaultNamespaceStrategy;
/** Field description */ }
@XmlElement(name = "admin-groups")
@XmlJavaTypeAdapter(XmlSetStringAdapter.class)
private Set<String> adminGroups;
/** Field description */
@XmlElement(name = "admin-users")
@XmlJavaTypeAdapter(XmlSetStringAdapter.class)
private Set<String> adminUsers;
/** Field description */
@XmlElement(name = "base-url")
private String baseUrl;
/** Field description */
@XmlElement(name = "force-base-url")
private boolean forceBaseUrl;
/**
* Maximum allowed login attempts.
*
* @since 1.34
*/
@XmlElement(name = "login-attempt-limit")
private int loginAttemptLimit = -1;
/** glob patterns for urls which are excluded from proxy */
@XmlElement(name = "proxy-excludes")
@XmlJavaTypeAdapter(XmlSetStringAdapter.class)
private Set<String> proxyExcludes;
/** Field description */
private String proxyPassword;
/** Field description */
private int proxyPort = 8080;
/** Field description */
private String proxyServer = "proxy.mydomain.com";
/** Field description */
private String proxyUser;
/**
* Skip failed authenticators.
*
* @since 1.36
*/
@XmlElement(name = "skip-failed-authenticators")
private boolean skipFailedAuthenticators = false;
/** Field description */
@XmlElement(name = "plugin-url")
private String pluginUrl = DEFAULT_PLUGINURL;
/**
* Login attempt timeout.
*
* @since 1.34
*/
@XmlElement(name = "login-attempt-limit-timeout")
private long loginAttemptLimitTimeout = TimeUnit.MINUTES.toSeconds(5l);
/** Field description */
private boolean enableProxy = false;
/**
*
* Authentication realm for basic authentication.
*
*/
private String realmDescription = HttpUtil.AUTHENTICATION_REALM;
/** Field description */
private boolean enableRepositoryArchive = false;
/** Field description */
private boolean disableGroupingGrid = false;
/**
* JavaScript date format from moment.js
* @see <a href="http://momentjs.com/docs/#/parsing/" target="_blank">http://momentjs.com/docs/#/parsing/</a>
*/
private String dateFormat = DEFAULT_DATEFORMAT;
/** Field description */
private boolean anonymousAccessEnabled = false;
/**
* Enables xsrf cookie protection.
*
* @since 1.47
*/
@XmlElement(name = "xsrf-protection")
private boolean enabledXsrfProtection = true;
} }

View File

@@ -36,19 +36,16 @@ package sonia.scm.repository;
//~--- non-JDK imports -------------------------------------------------------- //~--- non-JDK imports --------------------------------------------------------
import com.google.common.base.Throwables; import com.google.common.base.Throwables;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import sonia.scm.repository.ImportResult.Builder; import sonia.scm.repository.ImportResult.Builder;
//~--- JDK imports ------------------------------------------------------------
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.util.List; import java.util.List;
//~--- JDK imports ------------------------------------------------------------
/** /**
* Abstract base class for directory based {@link ImportHandler} and * Abstract base class for directory based {@link ImportHandler} and
* {@link AdvancedImportHandler}. * {@link AdvancedImportHandler}.
@@ -164,23 +161,24 @@ public abstract class AbstactImportHandler implements AdvancedImportHandler
logger.trace("search for repositories to import"); logger.trace("search for repositories to import");
try // TODO #8783
{ // try
// {
List<String> repositoryNames = //
RepositoryUtil.getRepositoryNames(getRepositoryHandler(), // List<String> repositoryNames =
getDirectoryNames()); // RepositoryUtil.getRepositoryNames(getRepositoryHandler(),
// getDirectoryNames());
for (String repositoryName : repositoryNames) //
{ // for (String repositoryName : repositoryNames)
importRepository(manager, builder, throwExceptions, repositoryName); // {
} // importRepository(manager, builder, throwExceptions, repositoryName);
// }
} //
catch (IOException ex) // }
{ // catch (IOException ex)
handleException(ex, throwExceptions); // {
} // handleException(ex, throwExceptions);
// }
return builder.build(); return builder.build();
} }
@@ -214,46 +212,48 @@ public abstract class AbstactImportHandler implements AdvancedImportHandler
* @param manager * @param manager
* @param builder * @param builder
* @param throwExceptions * @param throwExceptions
* @param repositoryName * @param directoryName
* *
* @throws IOException * @throws IOException
* @throws RepositoryException * @throws RepositoryException
*/ */
private void importRepository(RepositoryManager manager, Builder builder, private void importRepository(RepositoryManager manager, Builder builder,
boolean throwExceptions, String repositoryName) boolean throwExceptions, String directoryName)
throws IOException, RepositoryException throws IOException, RepositoryException
{ {
logger.trace("check repository {} for import", repositoryName); logger.trace("check repository {} for import", directoryName);
Repository repository = manager.get(getTypeName(), repositoryName); // TODO #8783
//
if (repository == null) // Repository repository = manager.get(namespaceAndName);
{ //
try // if (repository == null)
{ // {
importRepository(manager, repositoryName); // try
builder.addImportedDirectory(repositoryName); // {
} // importRepository(manager, repositoryName);
catch (IOException ex) // builder.addImportedDirectory(repositoryName);
{ // }
builder.addFailedDirectory(repositoryName); // catch (IOException ex)
handleException(ex, throwExceptions); // {
} // builder.addFailedDirectory(repositoryName);
catch (IllegalStateException ex) // handleException(ex, throwExceptions);
{ // }
builder.addFailedDirectory(repositoryName); // catch (IllegalStateException ex)
handleException(ex, throwExceptions); // {
} // builder.addFailedDirectory(repositoryName);
catch (RepositoryException ex) // handleException(ex, throwExceptions);
{ // }
builder.addFailedDirectory(repositoryName); // catch (RepositoryException ex)
handleException(ex, throwExceptions); // {
} // builder.addFailedDirectory(repositoryName);
} // handleException(ex, throwExceptions);
else if (logger.isDebugEnabled()) // }
{ // }
logger.debug("repository {} is allready managed", repositoryName); // else if (logger.isDebugEnabled())
} // {
// logger.debug("repository {} is already managed", repositoryName);
// }
} }
/** /**

View File

@@ -1,10 +1,10 @@
/** /**
* Copyright (c) 2010, Sebastian Sdorra * Copyright (c) 2010, Sebastian Sdorra
* All rights reserved. * All rights reserved.
* * <p>
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met: * modification, are permitted provided that the following conditions are met:
* * <p>
* 1. Redistributions of source code must retain the above copyright notice, * 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer. * this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice, * 2. Redistributions in binary form must reproduce the above copyright notice,
@@ -13,7 +13,7 @@
* 3. Neither the name of SCM-Manager; nor the names of its * 3. Neither the name of SCM-Manager; nor the names of its
* contributors may be used to endorse or promote products derived from this * contributors may be used to endorse or promote products derived from this
* software without specific prior written permission. * software without specific prior written permission.
* * <p>
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
@@ -24,13 +24,11 @@
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * 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 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* * <p>
* http://bitbucket.org/sdorra/scm-manager * http://bitbucket.org/sdorra/scm-manager
*
*/ */
package sonia.scm.repository; package sonia.scm.repository;
//~--- non-JDK imports -------------------------------------------------------- //~--- non-JDK imports --------------------------------------------------------
@@ -54,91 +52,56 @@ import java.net.URL;
//~--- JDK imports ------------------------------------------------------------ //~--- JDK imports ------------------------------------------------------------
/** /**
*
* @author Sebastian Sdorra
*
*
* @param <C> * @param <C>
* @author Sebastian Sdorra
*/ */
public abstract class AbstractSimpleRepositoryHandler<C extends SimpleRepositoryConfig> public abstract class AbstractSimpleRepositoryHandler<C extends SimpleRepositoryConfig>
extends AbstractRepositoryHandler<C> implements RepositoryDirectoryHandler extends AbstractRepositoryHandler<C> implements RepositoryDirectoryHandler {
{
/** Field description */
public static final String DEFAULT_VERSION_INFORMATION = "unknown"; public static final String DEFAULT_VERSION_INFORMATION = "unknown";
/** Field description */
public static final String DIRECTORY_REPOSITORY = "repositories"; public static final String DIRECTORY_REPOSITORY = "repositories";
/** Field description */
public static final String DOT = "."; public static final String DOT = ".";
/** the logger for AbstractSimpleRepositoryHandler */ /**
* the logger for AbstractSimpleRepositoryHandler
*/
private static final Logger logger = private static final Logger logger =
LoggerFactory.getLogger(AbstractSimpleRepositoryHandler.class); LoggerFactory.getLogger(AbstractSimpleRepositoryHandler.class);
//~--- constructors --------------------------------------------------------- private FileSystem fileSystem;
/**
* Constructs ...
*
*
* @param storeFactory
* @param fileSystem
*/
public AbstractSimpleRepositoryHandler(ConfigurationStoreFactory storeFactory, public AbstractSimpleRepositoryHandler(ConfigurationStoreFactory storeFactory,
FileSystem fileSystem) FileSystem fileSystem) {
{
super(storeFactory); super(storeFactory);
this.fileSystem = fileSystem; this.fileSystem = fileSystem;
} }
//~--- methods --------------------------------------------------------------
/**
* Method description
*
*
* @param repository
*
* @throws IOException
* @throws RepositoryException
*/
@Override @Override
public Repository create(Repository repository) public Repository create(Repository repository)
throws RepositoryException throws RepositoryException {
{
File directory = getDirectory(repository); File directory = getDirectory(repository);
if (directory.exists()) if (directory.exists()) {
{
throw RepositoryAlreadyExistsException.create(repository); throw RepositoryAlreadyExistsException.create(repository);
} }
checkPath(directory); checkPath(directory);
try try {
{
fileSystem.create(directory); fileSystem.create(directory);
create(repository, directory); create(repository, directory);
postCreate(repository, directory); postCreate(repository, directory);
return repository; return repository;
} } catch (Exception ex) {
catch (Exception ex) if (directory.exists()) {
{ logger.warn("delete repository directory {}, because of failed repository creation", directory);
if (directory.exists())
{
if (logger.isDebugEnabled())
{
logger.debug(
"delete repository directory {}, because of failed repository creation",
directory);
}
try { try {
fileSystem.destroy(directory); fileSystem.destroy(directory);
} catch (IOException e) { } catch (IOException e) {
logger.error("could not delete directory after failed repository creation: {}", directory, e); logger.error("Could not destroy directory", e);
} }
} }
@@ -148,40 +111,21 @@ public abstract class AbstractSimpleRepositoryHandler<C extends SimpleRepository
} }
} }
/**
* Method description
*
*
*
* @param repository
* @return
*/
@Override @Override
public String createResourcePath(Repository repository) public String createResourcePath(Repository repository) {
{
StringBuilder path = new StringBuilder("/"); StringBuilder path = new StringBuilder("/");
path.append(getType().getName()).append("/").append(repository.getName()); path.append(getType().getName()).append("/").append(repository.getId());
return path.toString(); return path.toString();
} }
/**
* Method description
*
*
* @param repository
*
* @throws IOException
* @throws RepositoryException
*/
@Override @Override
public void delete(Repository repository) throws RepositoryException public void delete(Repository repository)
{ throws RepositoryException {
File directory = getDirectory(repository); File directory = getDirectory(repository);
if (directory.exists()) if (directory.exists()) {
{
try { try {
fileSystem.destroy(directory); fileSystem.destroy(directory);
} catch (IOException e) { } catch (IOException e) {
@@ -189,32 +133,22 @@ public abstract class AbstractSimpleRepositoryHandler<C extends SimpleRepository
} }
cleanupEmptyDirectories(config.getRepositoryDirectory(), cleanupEmptyDirectories(config.getRepositoryDirectory(),
directory.getParentFile()); directory.getParentFile());
} } else {
else if (logger.isWarnEnabled()) logger.warn("repository {} not found", repository.getNamespaceAndName());
{
logger.warn("repository {} not found", repository);
} }
} }
/**
* Method description
*
*/
@Override @Override
public void loadConfig() public void loadConfig() {
{
super.loadConfig(); super.loadConfig();
if (config == null) if (config == null) {
{
config = createInitialConfig(); config = createInitialConfig();
if (config != null) if (config != null) {
{
File repositoryDirectory = config.getRepositoryDirectory(); File repositoryDirectory = config.getRepositoryDirectory();
if (repositoryDirectory == null) if (repositoryDirectory == null) {
{
repositoryDirectory = new File( repositoryDirectory = new File(
baseDirectory, baseDirectory,
DIRECTORY_REPOSITORY.concat(File.separator).concat( DIRECTORY_REPOSITORY.concat(File.separator).concat(
@@ -228,107 +162,51 @@ public abstract class AbstractSimpleRepositoryHandler<C extends SimpleRepository
} }
} }
/**
* Method description
*
*
* @param repository
*
* @throws IOException
* @throws RepositoryException
*/
@Override @Override
public void modify(Repository repository) throws RepositoryException public void modify(Repository repository) {
{
// nothing todo // nothing to do
} }
//~--- get methods ----------------------------------------------------------
/**
* Method description
*
*
* @param repository
*
* @return
*/
@Override @Override
public File getDirectory(Repository repository) public File getDirectory(Repository repository) {
{
File directory = null; File directory = null;
if (isConfigured()) if (isConfigured()) {
{
File repositoryDirectory = config.getRepositoryDirectory(); File repositoryDirectory = config.getRepositoryDirectory();
directory = new File(repositoryDirectory, repository.getName()); directory = new File(repositoryDirectory, repository.getId());
if (!IOUtil.isChild(repositoryDirectory, directory)) if (!IOUtil.isChild(repositoryDirectory, directory)) {
{
StringBuilder msg = new StringBuilder(directory.getPath()); StringBuilder msg = new StringBuilder(directory.getPath());
msg.append("is not a child of ").append(repositoryDirectory.getPath()); msg.append("is not a child of ").append(repositoryDirectory.getPath());
throw new ConfigurationException(msg.toString()); throw new ConfigurationException(msg.toString());
} }
} } else {
else
{
throw new ConfigurationException("RepositoryHandler is not configured"); throw new ConfigurationException("RepositoryHandler is not configured");
} }
return directory; return directory;
} }
/**
* Method description
*
*
* @return
*/
@Override @Override
public String getVersionInformation() public String getVersionInformation() {
{
return DEFAULT_VERSION_INFORMATION; return DEFAULT_VERSION_INFORMATION;
} }
//~--- methods --------------------------------------------------------------
/**
* Method description
*
*
* @param repository
* @param directory
*
* @return
*/
protected ExtendedCommand buildCreateCommand(Repository repository, protected ExtendedCommand buildCreateCommand(Repository repository,
File directory) File directory) {
{
throw new UnsupportedOperationException("method is not implemented"); throw new UnsupportedOperationException("method is not implemented");
} }
/**
* Method description
*
*
* @param repository
* @param directory
*
* @throws IOException
* @throws RepositoryException
*/
protected void create(Repository repository, File directory) protected void create(Repository repository, File directory)
throws RepositoryException, IOException throws RepositoryException, IOException {
{
ExtendedCommand cmd = buildCreateCommand(repository, directory); ExtendedCommand cmd = buildCreateCommand(repository, directory);
CommandResult result = cmd.execute(); CommandResult result = cmd.execute();
if (!result.isSuccessfull()) if (!result.isSuccessfull()) {
{
StringBuilder msg = new StringBuilder("command exit with error "); StringBuilder msg = new StringBuilder("command exit with error ");
msg.append(result.getReturnCode()).append(" and message: '"); msg.append(result.getReturnCode()).append(" and message: '");
@@ -338,56 +216,31 @@ public abstract class AbstractSimpleRepositoryHandler<C extends SimpleRepository
} }
} }
/** protected C createInitialConfig() {
* Method description
*
*
* @return
*/
protected C createInitialConfig()
{
return null; return null;
} }
/**
* Method description
*
*
* @param repository
* @param directory
*
* @throws IOException
* @throws RepositoryException
*/
protected void postCreate(Repository repository, File directory) protected void postCreate(Repository repository, File directory)
throws IOException, RepositoryException {} throws IOException, RepositoryException {
}
//~--- get methods ----------------------------------------------------------
/** /**
* Returns the content of a classpath resource or the given default content. * Returns the content of a classpath resource or the given default content.
* *
*
* @param resource path of a classpath resource * @param resource path of a classpath resource
* @param defaultContent default content to return * @param defaultContent default content to return
*
* @return content of a classpath resource or defaultContent * @return content of a classpath resource or defaultContent
*/ */
protected String getStringFromResource(String resource, String defaultContent) protected String getStringFromResource(String resource, String defaultContent) {
{
String content = defaultContent; String content = defaultContent;
try try {
{
URL url = Resources.getResource(resource); URL url = Resources.getResource(resource);
if (url != null) if (url != null) {
{
content = Resources.toString(url, Charsets.UTF_8); content = Resources.toString(url, Charsets.UTF_8);
} }
} } catch (IOException ex) {
catch (IOException ex)
{
logger.error("could not read resource", ex); logger.error("could not read resource", ex);
} }
@@ -397,45 +250,29 @@ public abstract class AbstractSimpleRepositoryHandler<C extends SimpleRepository
/** /**
* Returns true if the directory is a repository. * Returns true if the directory is a repository.
* *
*
* @param directory directory to check * @param directory directory to check
*
* @return true if the directory is a repository * @return true if the directory is a repository
* @since 1.9 * @since 1.9
*/ */
protected boolean isRepository(File directory) protected boolean isRepository(File directory) {
{
return new File(directory, DOT.concat(getType().getName())).exists(); return new File(directory, DOT.concat(getType().getName())).exists();
} }
//~--- methods --------------------------------------------------------------
/** /**
* Check path for existing repositories * Check path for existing repositories
* *
*
* @param directory repository target directory * @param directory repository target directory
*
* @throws RepositoryAlreadyExistsException * @throws RepositoryAlreadyExistsException
*/ */
private void checkPath(File directory) throws RepositoryAlreadyExistsException private void checkPath(File directory) throws RepositoryAlreadyExistsException {
{
File repositoryDirectory = config.getRepositoryDirectory(); File repositoryDirectory = config.getRepositoryDirectory();
File parent = directory.getParentFile(); File parent = directory.getParentFile();
while ((parent != null) &&!repositoryDirectory.equals(parent)) while ((parent != null) && !repositoryDirectory.equals(parent)) {
{
if (logger.isTraceEnabled())
{
logger.trace("check {} for existing repository", parent); logger.trace("check {} for existing repository", parent);
}
if (isRepository(parent)) if (isRepository(parent)) {
{
if (logger.isErrorEnabled())
{
logger.error("parent path {} is a repository", parent); logger.error("parent path {} is a repository", parent);
}
StringBuilder buffer = new StringBuilder("repository with name "); StringBuilder buffer = new StringBuilder("repository with name ");
buffer.append(directory.getName()).append(" already exists"); buffer.append(directory.getName()).append(" already exists");
@@ -446,49 +283,25 @@ public abstract class AbstractSimpleRepositoryHandler<C extends SimpleRepository
} }
} }
/** private void cleanupEmptyDirectories(File baseDirectory, File directory) {
* Method description if (IOUtil.isChild(baseDirectory, directory)) {
* if (IOUtil.isEmpty(directory)) {
*
* @param baseDirectory
* @param directory
*/
private void cleanupEmptyDirectories(File baseDirectory, File directory)
{
if (IOUtil.isChild(baseDirectory, directory))
{
if (IOUtil.isEmpty(directory))
{
// TODO use filesystem // TODO use filesystem
if (directory.delete()) if (directory.delete()) {
{
if (logger.isInfoEnabled())
{
logger.info("successfully deleted directory {}", directory); logger.info("successfully deleted directory {}", directory);
}
cleanupEmptyDirectories(baseDirectory, directory.getParentFile()); cleanupEmptyDirectories(baseDirectory, directory.getParentFile());
} } else {
else if (logger.isWarnEnabled())
{
logger.warn("could not delete directory {}", directory); logger.warn("could not delete directory {}", directory);
} }
}
else if (logger.isDebugEnabled()) } else {
{
logger.debug("could not remove non empty directory {}", directory); logger.debug("could not remove non empty directory {}", directory);
} }
} } else {
else if (logger.isWarnEnabled()) logger.warn("directory {} is not a child of {}", directory, baseDirectory);
{
logger.warn("directory {} is not a child of {}", directory,
baseDirectory);
} }
} }
//~--- fields ---------------------------------------------------------------
/** Field description */
private FileSystem fileSystem;
} }

View File

@@ -0,0 +1,50 @@
package sonia.scm.repository;
import com.google.common.base.Preconditions;
import com.google.common.base.Strings;
import java.util.Objects;
public class NamespaceAndName {
private final String namespace;
private final String name;
public NamespaceAndName(String namespace, String name) {
Preconditions.checkArgument(!Strings.isNullOrEmpty(namespace), "a non empty namespace is required");
Preconditions.checkArgument(!Strings.isNullOrEmpty(name), "a non empty name is required");
this.namespace = namespace;
this.name = name;
}
public String getNamespace() {
return namespace;
}
public String getName() {
return name;
}
@Override
public String toString() {
return getNamespace() + "/" + getName();
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
NamespaceAndName that = (NamespaceAndName) o;
return Objects.equals(namespace, that.namespace) &&
Objects.equals(name, that.name);
}
@Override
public int hashCode() {
return Objects.hash(namespace, name);
}
}

View File

@@ -0,0 +1,32 @@
package sonia.scm.repository;
import sonia.scm.config.ScmConfiguration;
import javax.inject.Inject;
import javax.inject.Provider;
import java.util.Set;
public class NamespaceStrategyProvider implements Provider<NamespaceStrategy> {
private final Set<NamespaceStrategy> strategies;
private final ScmConfiguration scmConfiguration;
@Inject
public NamespaceStrategyProvider(Set<NamespaceStrategy> strategies, ScmConfiguration scmConfiguration) {
this.strategies = strategies;
this.scmConfiguration = scmConfiguration;
}
@Override
public NamespaceStrategy get() {
String namespaceStrategy = scmConfiguration.getDefaultNamespaceStrategy();
for (NamespaceStrategy s : this.strategies) {
if (s.getClass().getCanonicalName().equals(namespaceStrategy)) {
return s;
}
}
return null;
}
}

View File

@@ -48,6 +48,7 @@ import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement; import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlElementWrapper; import javax.xml.bind.annotation.XmlElementWrapper;
import javax.xml.bind.annotation.XmlRootElement; import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlTransient;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
@@ -99,9 +100,10 @@ public class Repository extends BasicPropertiesAware implements ModelObject, Per
* @param type type of the {@link Repository} * @param type type of the {@link Repository}
* @param name name of the {@link Repository} * @param name name of the {@link Repository}
*/ */
public Repository(String id, String type, String name) { public Repository(String id, String type, String namespace, String name) {
this.id = id; this.id = id;
this.type = type; this.type = type;
this.namespace = namespace;
this.name = name; this.name = name;
} }
@@ -176,44 +178,28 @@ public class Repository extends BasicPropertiesAware implements ModelObject, Per
return healthCheckFailures; return healthCheckFailures;
} }
/**
* Returns the unique id of the {@link Repository}.
*
* @return unique id
*/
@Override @Override
public String getId() { public String getId() {
return id; return id;
} }
/**
* Returns the timestamp of the last modified date of the {@link Repository}.
*
* @return timestamp of the last modified date
*/
@Override @Override
public Long getLastModified() { public Long getLastModified() {
return lastModified; return lastModified;
} }
/**
* Returns the name of the {@link Repository}.
*
* @return name of the {@link Repository}
*/
public String getName() { public String getName() {
return name; return name;
} }
public String getNamespace() { public String getNamespace() { return namespace; }
return namespace;
@XmlTransient
public NamespaceAndName getNamespaceAndName() {
return new NamespaceAndName(getNamespace(), getName());
} }
/**
* Returns the access permissions of the {@link Repository}.
*
* @return access permissions
*/
public List<Permission> getPermissions() { public List<Permission> getPermissions() {
if (permissions == null) { if (permissions == null) {
permissions = Lists.newArrayList(); permissions = Lists.newArrayList();
@@ -370,9 +356,7 @@ public class Repository extends BasicPropertiesAware implements ModelObject, Per
* @since 1.17 * @since 1.17
*/ */
public String createUrl(String baseUrl) { public String createUrl(String baseUrl) {
String url = HttpUtil.append(baseUrl, type); return HttpUtil.concatenate(baseUrl, type, namespace, name);
return HttpUtil.append(url, name);
} }
/** /**

View File

@@ -49,27 +49,22 @@ public interface RepositoryDAO extends GenericDAO<Repository>
/** /**
* Returns true if a repository with specified * Returns true if a repository with specified
* type and name exists in the backend. * namespace and name exists in the backend.
* *
* *
* @param type type of the repository * @param namespaceAndName namespace and name of the repository
* @param name name of the repository
* *
* @return true if the repository exists * @return true if the repository exists
*/ */
public boolean contains(String type, String name); boolean contains(NamespaceAndName namespaceAndName);
//~--- get methods ---------------------------------------------------------- //~--- get methods ----------------------------------------------------------
/** /**
* Returns the repository with the specified type and name or null * Returns the repository with the specified namespace and name or null
* if no such repository exists in the backend. * if no such repository exists in the backend.
* *
* * @return repository with the specified namespace and name or null
* @param type
* @param name
*
* @return repository with the specified type and name or null
*/ */
public Repository get(String type, String name); Repository get(NamespaceAndName namespaceAndName);
} }

View File

@@ -43,13 +43,5 @@ import java.io.File;
public interface RepositoryDirectoryHandler extends RepositoryHandler public interface RepositoryDirectoryHandler extends RepositoryHandler
{ {
/**
* Method description
*
*
* @param repository
*
* @return
*/
public File getDirectory(Repository repository); public File getDirectory(Repository repository);
} }

View File

@@ -82,18 +82,17 @@ public interface RepositoryManager
//~--- get methods ---------------------------------------------------------- //~--- get methods ----------------------------------------------------------
/** /**
* Returns a {@link Repository} by its type and name or * Returns a {@link Repository} by its namespace and name or
* null if the {@link Repository} could not be found. * null if the {@link Repository} could not be found.
* *
* *
* @param type type of the {@link Repository} * @param namespaceAndName namespace and name of the {@link Repository}
* @param name name of the {@link Repository}
* *
* *
* @return {@link Repository} by its type and name or null * @return {@link Repository} by its namespace and name or null
* if the {@link Repository} could not be found * if the {@link Repository} could not be found
*/ */
public Repository get(String type, String name); public Repository get(NamespaceAndName namespaceAndName);
/** /**
* Returns all configured repository types. * Returns all configured repository types.
@@ -114,18 +113,6 @@ public interface RepositoryManager
*/ */
public Repository getFromRequest(HttpServletRequest request); public Repository getFromRequest(HttpServletRequest request);
/**
* Returns the {@link Repository} associated to the given type and path.
*
*
* @param type type of the repository (hg, git ...)
* @param uri
*
* @return the {@link Repository} associated to the given type and path
* @since 1.9
*/
public Repository getFromTypeAndUri(String type, String uri);
/** /**
* Returns the {@link Repository} associated to the request uri. * Returns the {@link Repository} associated to the request uri.
* *

View File

@@ -91,9 +91,9 @@ public class RepositoryManagerDecorator
//~--- get methods ---------------------------------------------------------- //~--- get methods ----------------------------------------------------------
@Override @Override
public Repository get(String namespace, String name) public Repository get(NamespaceAndName namespaceAndName)
{ {
return decorated.get(namespace, name); return decorated.get(namespaceAndName);
} }
/** /**
@@ -135,21 +135,6 @@ public class RepositoryManagerDecorator
return decorated.getFromRequest(request); return decorated.getFromRequest(request);
} }
/**
* {@inheritDoc}
*
*
* @param type
* @param uri
*
* @return
*/
@Override
public Repository getFromTypeAndUri(String type, String uri)
{
return decorated.getFromTypeAndUri(type, uri);
}
/** /**
* {@inheritDoc} * {@inheritDoc}
* *

View File

@@ -35,278 +35,86 @@ package sonia.scm.repository;
//~--- non-JDK imports -------------------------------------------------------- //~--- non-JDK imports --------------------------------------------------------
import org.slf4j.Logger; import com.google.common.base.Preconditions;
import org.slf4j.LoggerFactory;
import sonia.scm.io.DirectoryFileFilter; import sonia.scm.io.DirectoryFileFilter;
import sonia.scm.util.IOUtil; import sonia.scm.util.IOUtil;
//~--- JDK imports ------------------------------------------------------------
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
//~--- JDK imports ------------------------------------------------------------
/** /**
* *
* @author Sebastian Sdorra * @author Sebastian Sdorra
* @since 1.11 * @since 1.11
*/ */
public final class RepositoryUtil public final class RepositoryUtil {
{
/** the logger for RepositoryUtil */
private static final Logger logger =
LoggerFactory.getLogger(RepositoryUtil.class);
//~--- constructors ---------------------------------------------------------
/**
* Constructs ...
*
*/
private RepositoryUtil() {} private RepositoryUtil() {}
//~--- methods -------------------------------------------------------------- public static List<File> searchRepositoryDirectories(File directory, String... names) {
List<File> repositories = new ArrayList<>();
/**
* Method description
*
*
* @param directory
* @param names
*
* @return
*/
public static List<File> searchRepositoryDirectories(File directory,
String... names)
{
List<File> repositories = new ArrayList<File>();
searchRepositoryDirectories(repositories, directory, Arrays.asList(names)); searchRepositoryDirectories(repositories, directory, Arrays.asList(names));
return repositories; return repositories;
} }
//~--- get methods ---------------------------------------------------------- @SuppressWarnings("squid:S2083") // ignore, because the path is validated at {@link #getRepositoryId(File, File)}
public static String getRepositoryId(AbstractRepositoryHandler handler, String directoryPath) throws IOException {
/** return getRepositoryId(handler.getConfig().getRepositoryDirectory(), new File(directoryPath));
* Method description
*
*
*
* @param handler
* @param directoryPath
* @return
*
* @throws IOException
*/
public static String getRepositoryName(AbstractRepositoryHandler handler,
String directoryPath)
throws IOException
{
return getRepositoryName(handler.getConfig().getRepositoryDirectory(),
new File(directoryPath));
} }
/** public static String getRepositoryId(AbstractRepositoryHandler handler, File directory) throws IOException {
* Method description return getRepositoryId(handler.getConfig(), directory);
*
*
*
* @param config
* @param directoryPath
* @return
*
* @throws IOException
*/
public static String getRepositoryName(SimpleRepositoryConfig config,
String directoryPath)
throws IOException
{
return getRepositoryName(config.getRepositoryDirectory(),
new File(directoryPath));
} }
/** public static String getRepositoryId(SimpleRepositoryConfig config, File directory) throws IOException {
* Method description return getRepositoryId(config.getRepositoryDirectory(), directory);
*
*
*
* @param handler
* @param directory
* @return
*
* @throws IOException
*/
public static String getRepositoryName(AbstractRepositoryHandler handler,
File directory)
throws IOException
{
return getRepositoryName(handler.getConfig().getRepositoryDirectory(),
directory);
} }
/** public static String getRepositoryId(File baseDirectory, File directory) throws IOException {
* Method description
*
*
*
* @param config
* @param directory
* @return
*
* @throws IOException
*/
public static String getRepositoryName(SimpleRepositoryConfig config,
File directory)
throws IOException
{
return getRepositoryName(config.getRepositoryDirectory(), directory);
}
/**
* Method description
*
*
*
* @param baseDirectory
* @param directory
* @return
*
* @throws IOException
*/
public static String getRepositoryName(File baseDirectory, File directory)
throws IOException
{
String name = null;
String path = directory.getCanonicalPath(); String path = directory.getCanonicalPath();
int directoryLength = baseDirectory.getCanonicalPath().length(); String basePath = baseDirectory.getCanonicalPath();
if (directoryLength < path.length()) Preconditions.checkArgument(
{ path.startsWith(basePath),
name = IOUtil.trimSeperatorChars(path.substring(directoryLength)); "repository path %s is not in the main repository path %s", path, basePath
);
// replace windows path seperator String id = IOUtil.trimSeperatorChars(path.substring(basePath.length()));
name = name.replaceAll("\\\\", "/");
} Preconditions.checkArgument(
else if (logger.isWarnEnabled()) !id.contains("\\") && !id.contains("/"),
{ "got illegal repository directory with separators in id: %s", path
logger.warn("path is shorter as the main repository path"); );
return id;
} }
return name; private static void searchRepositoryDirectories(List<File> repositories, File directory, List<String> names) {
}
/**
* Method description
*
*
* @param handler
* @param directoryNames
*
* @return
*
* @throws IOException
*/
public static List<String> getRepositoryNames(
AbstractRepositoryHandler handler, String... directoryNames)
throws IOException
{
return getRepositoryNames(handler.getConfig(), directoryNames);
}
/**
* Method description
*
*
* @param config
* @param directoryNames
*
* @return
*
* @throws IOException
*/
public static List<String> getRepositoryNames(SimpleRepositoryConfig config,
String... directoryNames)
throws IOException
{
return getRepositoryNames(config.getRepositoryDirectory(), directoryNames);
}
/**
* Method description
*
*
* @param baseDirectory
* @param directoryNames
*
* @return
*
* @throws IOException
*/
public static List<String> getRepositoryNames(File baseDirectory,
String... directoryNames)
throws IOException
{
List<String> repositories = new ArrayList<String>();
List<File> repositoryFiles = searchRepositoryDirectories(baseDirectory,
directoryNames);
for (File file : repositoryFiles)
{
String name = getRepositoryName(baseDirectory, file);
if (name != null)
{
repositories.add(name);
}
}
return repositories;
}
//~--- methods --------------------------------------------------------------
/**
* Method description
*
*
* @param repositories
* @param directory
* @param names
*/
private static void searchRepositoryDirectories(List<File> repositories,
File directory, List<String> names)
{
boolean found = false; boolean found = false;
for (String name : names) for (String name : names) {
{ if (new File(directory, name).exists()) {
if (new File(directory, name).exists())
{
found = true; found = true;
break; break;
} }
} }
if (found) if (found) {
{
repositories.add(directory); repositories.add(directory);
} } else {
else
{
File[] directories = directory.listFiles(DirectoryFileFilter.instance); File[] directories = directory.listFiles(DirectoryFileFilter.instance);
if (directories != null) if (directories != null) {
{ for (File d : directories) {
for (File d : directories)
{
searchRepositoryDirectories(repositories, d, names); searchRepositoryDirectories(repositories, d, names);
} }
} }

View File

@@ -50,6 +50,7 @@ import sonia.scm.cache.CacheManager;
import sonia.scm.config.ScmConfiguration; import sonia.scm.config.ScmConfiguration;
import sonia.scm.event.ScmEventBus; import sonia.scm.event.ScmEventBus;
import sonia.scm.repository.ClearRepositoryCacheEvent; import sonia.scm.repository.ClearRepositoryCacheEvent;
import sonia.scm.repository.NamespaceAndName;
import sonia.scm.repository.PostReceiveRepositoryHookEvent; import sonia.scm.repository.PostReceiveRepositoryHookEvent;
import sonia.scm.repository.PreProcessorUtil; import sonia.scm.repository.PreProcessorUtil;
import sonia.scm.repository.Repository; import sonia.scm.repository.Repository;
@@ -186,8 +187,7 @@ public final class RepositoryServiceFactory
* Creates a new RepositoryService for the given repository. * Creates a new RepositoryService for the given repository.
* *
* *
* @param type type of the repository * @param namespaceAndName namespace and name of the repository
* @param name name of the repository
* *
* @return a implementation of RepositoryService * @return a implementation of RepositoryService
* for the given type of repository * for the given type of repository
@@ -200,24 +200,19 @@ public final class RepositoryServiceFactory
* @throws ScmSecurityException if current user has not read permissions * @throws ScmSecurityException if current user has not read permissions
* for that repository * for that repository
*/ */
public RepositoryService create(String type, String name) public RepositoryService create(NamespaceAndName namespaceAndName)
throws RepositoryNotFoundException throws RepositoryNotFoundException
{ {
Preconditions.checkArgument(!Strings.isNullOrEmpty(type), Preconditions.checkArgument(namespaceAndName != null,
"a non empty type is required"); "a non empty namespace and name is required");
Preconditions.checkArgument(!Strings.isNullOrEmpty(name),
"a non empty name is required");
Repository repository = repositoryManager.get(type, name); Repository repository = repositoryManager.get(namespaceAndName);
if (repository == null) if (repository == null)
{ {
StringBuilder msg = String msg = "could not find a repository with namespace/name " + namespaceAndName;
new StringBuilder("could not find a repository with type ");
msg.append(type).append(" and name ").append(name); throw new RepositoryNotFoundException(msg);
throw new RepositoryNotFoundException(msg.toString());
} }
return create(repository); return create(repository);

View File

@@ -35,7 +35,7 @@ package sonia.scm.repository.spi;
import com.google.inject.Inject; import com.google.inject.Inject;
import com.google.inject.Provider; import com.google.inject.Provider;
import sonia.scm.repository.NamespaceAndName;
import sonia.scm.repository.Repository; import sonia.scm.repository.Repository;
import sonia.scm.repository.RepositoryException; import sonia.scm.repository.RepositoryException;
import sonia.scm.repository.RepositoryHookEvent; import sonia.scm.repository.RepositoryHookEvent;
@@ -72,50 +72,15 @@ public final class HookEventFacade
//~--- methods -------------------------------------------------------------- //~--- methods --------------------------------------------------------------
/** public HookEventHandler handle(String id) throws RepositoryException {
* Method description
*
*
* @param id
*
* @return
*
* @throws RepositoryException
*/
public HookEventHandler handle(String id) throws RepositoryException
{
return handle(repositoryManagerProvider.get().get(id)); return handle(repositoryManagerProvider.get().get(id));
} }
/** public HookEventHandler handle(NamespaceAndName namespaceAndName) throws RepositoryException {
* Method description return handle(repositoryManagerProvider.get().get(namespaceAndName));
*
*
* @param type
* @param repositoryName
*
* @return
*
* @throws RepositoryException
*/
public HookEventHandler handle(String type, String repositoryName)
throws RepositoryException
{
return handle(repositoryManagerProvider.get().get(type, repositoryName));
} }
/** public HookEventHandler handle(Repository repository) throws RepositoryException
* Method description
*
*
* @param repository
*
* @return
*
* @throws RepositoryException
*/
public HookEventHandler handle(Repository repository)
throws RepositoryException
{ {
if (repository == null) if (repository == null)
{ {

View File

@@ -39,27 +39,23 @@ import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.CharMatcher; import com.google.common.base.CharMatcher;
import com.google.common.base.Objects; import com.google.common.base.Objects;
import com.google.common.base.Strings; import com.google.common.base.Strings;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import sonia.scm.config.ScmConfiguration; import sonia.scm.config.ScmConfiguration;
//~--- JDK imports ------------------------------------------------------------ import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.UnsupportedEncodingException; import java.io.UnsupportedEncodingException;
import java.net.URLDecoder; import java.net.URLDecoder;
import java.net.URLEncoder; import java.net.URLEncoder;
import java.util.Arrays;
import java.util.Locale; import java.util.Locale;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import javax.servlet.http.HttpServletRequest; //~--- JDK imports ------------------------------------------------------------
import javax.servlet.http.HttpServletResponse;
/** /**
* Util method for the http protocol. * Util method for the http protocol.
@@ -253,12 +249,22 @@ public final class HttpUtil
//~--- methods -------------------------------------------------------------- //~--- methods --------------------------------------------------------------
/** /**
* Appends the suffix to given uri. * Joins all path elements together separated by {@code {@link #SEPARATOR_PATH}}.
* *
* @param pathElements path elements
*
* @return concatenated path
* @since 2.0.0
*/
public static String concatenate(String... pathElements) {
return Arrays.stream(pathElements).reduce(HttpUtil::append).orElse("");
}
/**
* Appends the suffix to given uri.
* *
* @param uri uri * @param uri uri
* @param suffix suffix * @param suffix suffix
*
* @return * @return
* @since 1.9 * @since 1.9
*/ */

View File

@@ -1,133 +0,0 @@
/**
* 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.filter;
//~--- non-JDK imports --------------------------------------------------------
import sonia.scm.config.ScmConfiguration;
import sonia.scm.repository.Repository;
import sonia.scm.repository.RepositoryManager;
//~--- JDK imports ------------------------------------------------------------
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.servlet.http.HttpServletRequest;
/**
*
* @author Sebastian Sdorra
*/
public abstract class RegexPermissionFilter extends PermissionFilter
{
/** Field description */
public static final Pattern PATTERN_REPOSITORYNAME =
Pattern.compile("/[^/]+/([^/]+)(?:/.*)?");
//~--- constructors ---------------------------------------------------------
/**
* Constructs ...
*
*
*
* @param configuration
* @param repositoryManager
*/
public RegexPermissionFilter(ScmConfiguration configuration,
RepositoryManager repositoryManager)
{
super(configuration);
this.repositoryManager = repositoryManager;
}
//~--- get methods ----------------------------------------------------------
/**
* Method description
*
*
* @return
*/
protected abstract String getType();
/**
* Method description
*
*
* @param request
*
* @return
*/
@Override
protected Repository getRepository(HttpServletRequest request)
{
Repository repository = null;
String uri = request.getRequestURI();
uri = uri.substring(request.getContextPath().length());
Matcher m = PATTERN_REPOSITORYNAME.matcher(uri);
if (m.matches())
{
String repositoryname = m.group(1);
repository = getRepository(repositoryname);
}
return repository;
}
/**
* Method description
*
*
* @param name
*
* @return
*/
protected Repository getRepository(String name)
{
return repositoryManager.get(getType(), name);
}
//~--- fields ---------------------------------------------------------------
/** Field description */
private RepositoryManager repositoryManager;
}

View File

@@ -34,7 +34,7 @@ package sonia.scm.repository;
import org.junit.Test; import org.junit.Test;
import static org.junit.Assert.*; import static org.junit.Assert.assertEquals;
/** /**
* *
@@ -50,7 +50,7 @@ public class RepositoryTest
@Test @Test
public void testCreateUrl() public void testCreateUrl()
{ {
Repository repository = new Repository("123", "hg", "test/repo"); Repository repository = new Repository("123", "hg", "test", "repo");
assertEquals("http://localhost:8080/scm/hg/test/repo", assertEquals("http://localhost:8080/scm/hg/test/repo",
repository.createUrl("http://localhost:8080/scm")); repository.createUrl("http://localhost:8080/scm"));

View File

@@ -0,0 +1,73 @@
package sonia.scm.repository;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
import java.io.File;
import java.io.IOException;
import static org.junit.Assert.*;
import static org.mockito.Mockito.*;
@RunWith(MockitoJUnitRunner.class)
public class RepositoryUtilTest {
@Rule
public TemporaryFolder temporaryFolder = new TemporaryFolder();
@Mock
private AbstractRepositoryHandler<SimpleRepositoryConfig> repositoryHandler;
private SimpleRepositoryConfig repositoryConfig = new SimpleRepositoryConfig();
@Before
public void setUpMocks() {
when(repositoryHandler.getConfig()).thenReturn(repositoryConfig);
}
@Test
public void testGetRepositoryId() throws IOException {
File repositoryTypeRoot = temporaryFolder.newFolder();
repositoryConfig.setRepositoryDirectory(repositoryTypeRoot);
File repository = new File(repositoryTypeRoot, "abc");
String id = RepositoryUtil.getRepositoryId(repositoryHandler, repository.getPath());
assertEquals("abc", id);
}
@Test(expected = IllegalArgumentException.class)
public void testGetRepositoryIdWithInvalidPath() throws IOException {
File repositoryTypeRoot = temporaryFolder.newFolder();
repositoryConfig.setRepositoryDirectory(repositoryTypeRoot);
File repository = new File("/etc/abc");
String id = RepositoryUtil.getRepositoryId(repositoryHandler, repository.getPath());
assertEquals("abc", id);
}
@Test(expected = IllegalArgumentException.class)
public void testGetRepositoryIdWithInvalidPathButSameLength() throws IOException {
File repositoryTypeRoot = temporaryFolder.newFolder();
repositoryConfig.setRepositoryDirectory(repositoryTypeRoot);
File repository = new File(temporaryFolder.newFolder(), "abc");
String id = RepositoryUtil.getRepositoryId(repositoryHandler, repository.getPath());
assertEquals("abc", id);
}
@Test(expected = IllegalArgumentException.class)
public void testGetRepositoryIdWithInvalidId() throws IOException {
File repositoryTypeRoot = temporaryFolder.newFolder();
repositoryConfig.setRepositoryDirectory(repositoryTypeRoot);
File repository = new File(repositoryTypeRoot, "abc/123");
RepositoryUtil.getRepositoryId(repositoryHandler, repository.getPath());
}
}

View File

@@ -54,6 +54,18 @@ import javax.servlet.http.HttpServletRequest;
public class HttpUtilTest public class HttpUtilTest
{ {
@Test
public void concatenateTest() {
assertEquals(
"/scm/git/hitchhiker/tricia",
HttpUtil.concatenate("/scm", "git", "hitchhiker", "tricia")
);
assertEquals(
"scm/git/hitchhiker/tricia",
HttpUtil.concatenate("scm", "git", "hitchhiker", "tricia")
);
}
/** /**
* Method description * Method description
* *

View File

@@ -36,11 +36,11 @@ package sonia.scm.repository.xml;
import com.google.inject.Inject; import com.google.inject.Inject;
import com.google.inject.Singleton; import com.google.inject.Singleton;
import sonia.scm.repository.NamespaceAndName;
import sonia.scm.repository.Repository; import sonia.scm.repository.Repository;
import sonia.scm.repository.RepositoryDAO; import sonia.scm.repository.RepositoryDAO;
import sonia.scm.xml.AbstractXmlDAO;
import sonia.scm.store.ConfigurationStoreFactory; import sonia.scm.store.ConfigurationStoreFactory;
import sonia.scm.xml.AbstractXmlDAO;
/** /**
* *
@@ -71,36 +71,18 @@ public class XmlRepositoryDAO
//~--- methods -------------------------------------------------------------- //~--- methods --------------------------------------------------------------
/**
* Method description
*
*
* @param type
* @param name
*
* @return
*/
@Override @Override
public boolean contains(String type, String name) public boolean contains(NamespaceAndName namespaceAndName)
{ {
return db.contains(type, name); return db.contains(namespaceAndName);
} }
//~--- get methods ---------------------------------------------------------- //~--- get methods ----------------------------------------------------------
/**
* Method description
*
*
* @param type
* @param name
*
* @return
*/
@Override @Override
public Repository get(String type, String name) public Repository get(NamespaceAndName namespaceAndName)
{ {
return db.get(type, name); return db.get(namespaceAndName);
} }
//~--- methods -------------------------------------------------------------- //~--- methods --------------------------------------------------------------

View File

@@ -35,34 +35,26 @@ package sonia.scm.repository.xml;
//~--- non-JDK imports -------------------------------------------------------- //~--- non-JDK imports --------------------------------------------------------
import sonia.scm.repository.NamespaceAndName;
import sonia.scm.repository.Repository; import sonia.scm.repository.Repository;
import sonia.scm.xml.XmlDatabase; import sonia.scm.xml.XmlDatabase;
//~--- JDK imports ------------------------------------------------------------
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.Map;
import javax.xml.bind.annotation.XmlAccessType; import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType; import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement; import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement; import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter; import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.Map;
//~--- JDK imports ------------------------------------------------------------
/**
*
* @author Sebastian Sdorra
*/
@XmlRootElement(name = "repository-db") @XmlRootElement(name = "repository-db")
@XmlAccessorType(XmlAccessType.FIELD) @XmlAccessorType(XmlAccessType.FIELD)
public class XmlRepositoryDatabase implements XmlDatabase<Repository> public class XmlRepositoryDatabase implements XmlDatabase<Repository>
{ {
/**
* Constructs ...
*
*/
public XmlRepositoryDatabase() public XmlRepositoryDatabase()
{ {
long c = System.currentTimeMillis(); long c = System.currentTimeMillis();
@@ -71,108 +63,43 @@ public class XmlRepositoryDatabase implements XmlDatabase<Repository>
lastModified = c; lastModified = c;
} }
//~--- methods -------------------------------------------------------------- static String createKey(NamespaceAndName namespaceAndName)
/**
* Method description
*
*
* @param type
* @param name
*
* @return
*/
static String createKey(String type, String name)
{ {
return type.concat(":").concat(name); return namespaceAndName.getNamespace() + ":" + namespaceAndName.getName();
} }
/**
* Method description
*
*
* @param repository
*
* @return
*/
static String createKey(Repository repository) static String createKey(Repository repository)
{ {
return createKey(repository.getType(), repository.getName()); return createKey(repository.getNamespaceAndName());
} }
/**
* Method description
*
*
* @param repository
*/
@Override @Override
public void add(Repository repository) public void add(Repository repository)
{ {
repositoryMap.put(createKey(repository), repository); repositoryMap.put(createKey(repository), repository);
} }
/** public boolean contains(NamespaceAndName namespaceAndName)
* Method description
*
*
*
* @param type
* @param name
*
* @return
*/
public boolean contains(String type, String name)
{ {
return repositoryMap.containsKey(createKey(type, name)); return repositoryMap.containsKey(createKey(namespaceAndName));
} }
/**
* Method description
*
*
* @param id
*
* @return
*/
@Override @Override
public boolean contains(String id) public boolean contains(String id)
{ {
return get(id) != null; return get(id) != null;
} }
/**
* Method description
*
*
* @param repository
*
* @return
*/
public boolean contains(Repository repository) public boolean contains(Repository repository)
{ {
return repositoryMap.containsKey(createKey(repository)); return repositoryMap.containsKey(createKey(repository));
} }
/**
* Method description
*
*
* @param repository
*/
public void remove(Repository repository) public void remove(Repository repository)
{ {
repositoryMap.remove(createKey(repository)); repositoryMap.remove(createKey(repository));
} }
/**
* Method description
*
*
* @param id
*
* @return
*/
@Override @Override
public Repository remove(String id) public Repository remove(String id)
{ {
@@ -183,12 +110,6 @@ public class XmlRepositoryDatabase implements XmlDatabase<Repository>
return r; return r;
} }
/**
* Method description
*
*
* @return
*/
@Override @Override
public Collection<Repository> values() public Collection<Repository> values()
{ {
@@ -197,18 +118,9 @@ public class XmlRepositoryDatabase implements XmlDatabase<Repository>
//~--- get methods ---------------------------------------------------------- //~--- get methods ----------------------------------------------------------
/** public Repository get(NamespaceAndName namespaceAndName)
* Method description
*
*
* @param type
* @param name
*
* @return
*/
public Repository get(String type, String name)
{ {
return repositoryMap.get(createKey(type, name)); return repositoryMap.get(createKey(namespaceAndName));
} }
/** /**
@@ -298,6 +210,5 @@ public class XmlRepositoryDatabase implements XmlDatabase<Repository>
/** Field description */ /** Field description */
@XmlJavaTypeAdapter(XmlRepositoryMapAdapter.class) @XmlJavaTypeAdapter(XmlRepositoryMapAdapter.class)
@XmlElement(name = "repositories") @XmlElement(name = "repositories")
private Map<String, Repository> repositoryMap = new LinkedHashMap<String, private Map<String, Repository> repositoryMap = new LinkedHashMap<>();
Repository>();
} }

View File

@@ -37,57 +37,28 @@ package sonia.scm.repository.xml;
import sonia.scm.repository.Repository; import sonia.scm.repository.Repository;
//~--- JDK imports ------------------------------------------------------------ import javax.xml.bind.annotation.adapters.XmlAdapter;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
import java.util.Map; import java.util.Map;
import javax.xml.bind.annotation.adapters.XmlAdapter; //~--- JDK imports ------------------------------------------------------------
/** /**
* *
* @author Sebastian Sdorra * @author Sebastian Sdorra
*/ */
public class XmlRepositoryMapAdapter public class XmlRepositoryMapAdapter extends XmlAdapter<XmlRepositoryList, Map<String, Repository>> {
extends XmlAdapter<XmlRepositoryList, Map<String, Repository>>
{
/**
* Method description
*
*
* @param repositoryMap
*
* @return
*
* @throws Exception
*/
@Override @Override
public XmlRepositoryList marshal(Map<String, Repository> repositoryMap) public XmlRepositoryList marshal(Map<String, Repository> repositoryMap) {
throws Exception
{
return new XmlRepositoryList(repositoryMap); return new XmlRepositoryList(repositoryMap);
} }
/**
* Method description
*
*
* @param repositories
*
* @return
*
* @throws Exception
*/
@Override @Override
public Map<String, Repository> unmarshal(XmlRepositoryList repositories) public Map<String, Repository> unmarshal(XmlRepositoryList repositories) {
throws Exception Map<String, Repository> repositoryMap = new LinkedHashMap<>();
{
Map<String, Repository> repositoryMap = new LinkedHashMap<String,
Repository>();
for (Repository repository : repositories) for (Repository repository : repositories) {
{
repositoryMap.put(XmlRepositoryDatabase.createKey(repository), repositoryMap.put(XmlRepositoryDatabase.createKey(repository),
repository); repository);
} }

View File

@@ -30,9 +30,9 @@
*/ */
package sonia.scm.repository; package sonia.scm.repository;
import com.github.legman.Subscribe;
import com.google.common.annotations.VisibleForTesting; import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Objects; import com.google.common.base.Objects;
import com.google.common.eventbus.Subscribe;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import sonia.scm.EagerSingleton; import sonia.scm.EagerSingleton;

View File

@@ -40,24 +40,21 @@ import org.eclipse.jgit.transport.PostReceiveHook;
import org.eclipse.jgit.transport.PreReceiveHook; import org.eclipse.jgit.transport.PreReceiveHook;
import org.eclipse.jgit.transport.ReceiveCommand; import org.eclipse.jgit.transport.ReceiveCommand;
import org.eclipse.jgit.transport.ReceivePack; import org.eclipse.jgit.transport.ReceivePack;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import sonia.scm.repository.GitRepositoryHandler; import sonia.scm.repository.GitRepositoryHandler;
import sonia.scm.repository.RepositoryHookType; import sonia.scm.repository.RepositoryHookType;
import sonia.scm.repository.RepositoryUtil; import sonia.scm.repository.RepositoryUtil;
import sonia.scm.repository.spi.GitHookContextProvider; import sonia.scm.repository.spi.GitHookContextProvider;
import sonia.scm.repository.spi.HookEventFacade; import sonia.scm.repository.spi.HookEventFacade;
//~--- JDK imports ------------------------------------------------------------
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.util.Collection; import java.util.Collection;
import java.util.List; import java.util.List;
//~--- JDK imports ------------------------------------------------------------
/** /**
* *
* @author Sebastian Sdorra * @author Sebastian Sdorra
@@ -131,15 +128,14 @@ public class GitReceiveHook implements PreReceiveHook, PostReceiveHook
try try
{ {
Repository repository = rpack.getRepository(); Repository repository = rpack.getRepository();
String repositoryName = resolveRepositoryName(repository); String id = resolveRepositoryId(repository);
logger.trace("resolved repository name to {}", repositoryName); logger.trace("resolved repository to id {}", id);
GitHookContextProvider context = new GitHookContextProvider(rpack, GitHookContextProvider context = new GitHookContextProvider(rpack,
receiveCommands); receiveCommands);
hookEventFacade.handle(GitRepositoryHandler.TYPE_NAME, hookEventFacade.handle(id).fireHookEvent(type, context);
repositoryName).fireHookEvent(type, context);
} }
catch (Exception ex) catch (Exception ex)
@@ -191,7 +187,7 @@ public class GitReceiveHook implements PreReceiveHook, PostReceiveHook
* *
* @throws IOException * @throws IOException
*/ */
private String resolveRepositoryName(Repository repository) throws IOException private String resolveRepositoryId(Repository repository) throws IOException
{ {
File directory; File directory;
@@ -204,7 +200,7 @@ public class GitReceiveHook implements PreReceiveHook, PostReceiveHook
directory = repository.getWorkTree(); directory = repository.getWorkTree();
} }
return RepositoryUtil.getRepositoryName(handler, directory); return RepositoryUtil.getRepositoryId(handler, directory);
} }
//~--- fields --------------------------------------------------------------- //~--- fields ---------------------------------------------------------------

View File

@@ -36,8 +36,8 @@ package sonia.scm.web;
//~--- non-JDK imports -------------------------------------------------------- //~--- non-JDK imports --------------------------------------------------------
import com.google.common.annotations.VisibleForTesting; import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Preconditions;
import com.google.inject.Inject; import com.google.inject.Inject;
import org.eclipse.jgit.errors.RepositoryNotFoundException; import org.eclipse.jgit.errors.RepositoryNotFoundException;
import org.eclipse.jgit.lib.Repository; import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.lib.RepositoryCache; import org.eclipse.jgit.lib.RepositoryCache;
@@ -46,19 +46,17 @@ import org.eclipse.jgit.transport.resolver.RepositoryResolver;
import org.eclipse.jgit.transport.resolver.ServiceNotAuthorizedException; import org.eclipse.jgit.transport.resolver.ServiceNotAuthorizedException;
import org.eclipse.jgit.transport.resolver.ServiceNotEnabledException; import org.eclipse.jgit.transport.resolver.ServiceNotEnabledException;
import org.eclipse.jgit.util.FS; import org.eclipse.jgit.util.FS;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import sonia.scm.repository.GitConfig; import sonia.scm.repository.GitConfig;
import sonia.scm.repository.GitRepositoryHandler; import sonia.scm.repository.GitRepositoryHandler;
import sonia.scm.repository.RepositoryProvider;
//~--- JDK imports ------------------------------------------------------------ import javax.servlet.http.HttpServletRequest;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import javax.servlet.http.HttpServletRequest; //~--- JDK imports ------------------------------------------------------------
/** /**
* *
@@ -72,17 +70,11 @@ public class GitRepositoryResolver implements RepositoryResolver<HttpServletRequ
//~--- constructors --------------------------------------------------------- //~--- constructors ---------------------------------------------------------
/**
* Constructs ...
*
*
*
* @param handler
*/
@Inject @Inject
public GitRepositoryResolver(GitRepositoryHandler handler) public GitRepositoryResolver(GitRepositoryHandler handler, RepositoryProvider repositoryProvider)
{ {
this.handler = handler; this.handler = handler;
this.repositoryProvider = repositoryProvider;
} }
//~--- methods -------------------------------------------------------------- //~--- methods --------------------------------------------------------------
@@ -101,26 +93,27 @@ public class GitRepositoryResolver implements RepositoryResolver<HttpServletRequ
* @throws ServiceNotEnabledException * @throws ServiceNotEnabledException
*/ */
@Override @Override
public Repository open(HttpServletRequest request, String repositoryName) public Repository open(HttpServletRequest request, String repositoryName) throws RepositoryNotFoundException, ServiceNotEnabledException
throws RepositoryNotFoundException, ServiceNotAuthorizedException,
ServiceNotEnabledException
{ {
Repository repository = null;
try try
{ {
sonia.scm.repository.Repository repo = repositoryProvider.get();
Preconditions.checkState(repo != null, "repository to handle not found");
Preconditions.checkState(GitRepositoryHandler.TYPE_NAME.equals(repo.getType()), "got a non git repository in GitRepositoryResolver of type " + repo.getType());
GitConfig config = handler.getConfig(); GitConfig config = handler.getConfig();
if (config.isValid()) if (config.isValid())
{ {
File gitdir = findRepository(config.getRepositoryDirectory(), repositoryName); File gitdir = findRepository(config.getRepositoryDirectory(), repo.getId());
if (gitdir == null) { if (gitdir == null) {
throw new RepositoryNotFoundException(repositoryName); throw new RepositoryNotFoundException(repositoryName);
} }
logger.debug("try to open git repository at {}", gitdir); logger.debug("try to open git repository at {}", gitdir);
repository = RepositoryCache.open(FileKey.lenient(gitdir, FS.DETECTED), true); return RepositoryCache.open(FileKey.lenient(gitdir, FS.DETECTED), true);
} }
else else
{ {
@@ -136,8 +129,6 @@ public class GitRepositoryResolver implements RepositoryResolver<HttpServletRequ
{ {
throw new RepositoryNotFoundException(repositoryName, e); throw new RepositoryNotFoundException(repositoryName, e);
} }
return repository;
} }
@VisibleForTesting @VisibleForTesting
@@ -168,6 +159,6 @@ public class GitRepositoryResolver implements RepositoryResolver<HttpServletRequ
//~--- fields --------------------------------------------------------------- //~--- fields ---------------------------------------------------------------
/** Field description */ private final GitRepositoryHandler handler;
private GitRepositoryHandler handler; private final RepositoryProvider repositoryProvider;
} }

View File

@@ -32,7 +32,7 @@
package sonia.scm.web.lfs; package sonia.scm.web.lfs;
import com.google.common.eventbus.Subscribe; import com.github.legman.Subscribe;
import com.google.inject.Inject; import com.google.inject.Inject;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;

View File

@@ -1,10 +1,10 @@
/** /**
* Copyright (c) 2010, Sebastian Sdorra * Copyright (c) 2010, Sebastian Sdorra
* All rights reserved. * All rights reserved.
* * <p>
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met: * modification, are permitted provided that the following conditions are met:
* * <p>
* 1. Redistributions of source code must retain the above copyright notice, * 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer. * this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice, * 2. Redistributions in binary form must reproduce the above copyright notice,
@@ -13,7 +13,7 @@
* 3. Neither the name of SCM-Manager; nor the names of its * 3. Neither the name of SCM-Manager; nor the names of its
* contributors may be used to endorse or promote products derived from this * contributors may be used to endorse or promote products derived from this
* software without specific prior written permission. * software without specific prior written permission.
* * <p>
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
@@ -24,50 +24,45 @@
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * 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 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* * <p>
* http://bitbucket.org/sdorra/scm-manager * http://bitbucket.org/sdorra/scm-manager
*
*/ */
package sonia.scm.repository; package sonia.scm.repository;
//~--- non-JDK imports -------------------------------------------------------- //~--- non-JDK imports --------------------------------------------------------
import sonia.scm.io.DefaultFileSystem; import org.junit.Test;
import static org.junit.Assert.*;
//~--- JDK imports ------------------------------------------------------------
import java.io.File;
import sonia.scm.store.ConfigurationStoreFactory;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.mockito.Mock; import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner; import org.mockito.runners.MockitoJUnitRunner;
import sonia.scm.io.DefaultFileSystem;
import sonia.scm.schedule.Scheduler; import sonia.scm.schedule.Scheduler;
import sonia.scm.store.ConfigurationStoreFactory;
import java.io.File;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
//~--- JDK imports ------------------------------------------------------------
/** /**
* *
* @author Sebastian Sdorra * @author Sebastian Sdorra
*/ */
@RunWith(MockitoJUnitRunner.class) @RunWith(MockitoJUnitRunner.class)
public class GitRepositoryHandlerTest extends SimpleRepositoryHandlerTestBase public class GitRepositoryHandlerTest extends SimpleRepositoryHandlerTestBase {
{
@Mock @Mock
private Scheduler scheduler; private Scheduler scheduler;
/** @Mock
* Method description private ConfigurationStoreFactory factory;
*
*
* @param directory
*/
@Override @Override
protected void checkDirectory(File directory) protected void checkDirectory(File directory) {
{
File head = new File(directory, "HEAD"); File head = new File(directory, "HEAD");
assertTrue(head.exists()); assertTrue(head.exists());
@@ -84,19 +79,10 @@ public class GitRepositoryHandlerTest extends SimpleRepositoryHandlerTestBase
assertTrue(refs.isDirectory()); assertTrue(refs.isDirectory());
} }
/**
* Method description
*
*
* @param factory
* @param directory
*
* @return
*/
@Override @Override
protected RepositoryHandler createRepositoryHandler(ConfigurationStoreFactory factory, protected RepositoryHandler createRepositoryHandler(ConfigurationStoreFactory factory,
File directory) File directory) {
{
GitRepositoryHandler repositoryHandler = new GitRepositoryHandler(factory, GitRepositoryHandler repositoryHandler = new GitRepositoryHandler(factory,
new DefaultFileSystem(), scheduler); new DefaultFileSystem(), scheduler);
@@ -110,4 +96,19 @@ public class GitRepositoryHandlerTest extends SimpleRepositoryHandlerTestBase
return repositoryHandler; return repositoryHandler;
} }
@Test
public void getDirectory() {
GitRepositoryHandler repositoryHandler = new GitRepositoryHandler(factory,
new DefaultFileSystem(), scheduler);
GitConfig gitConfig = new GitConfig();
gitConfig.setRepositoryDirectory(new File("/path"));
repositoryHandler.setConfig(gitConfig);
Repository repository = new Repository("id", "git", "Space", "Name");
File path = repositoryHandler.getDirectory(repository);
assertEquals("/path/id", path.getAbsolutePath());
}
} }

View File

@@ -31,7 +31,9 @@
package sonia.scm.repository; package sonia.scm.repository;
import org.junit.Test; import org.junit.Test;
import static org.junit.Assert.*;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
/** /**
* Unit tests for {@link GitRepositoryPathMatcher}. * Unit tests for {@link GitRepositoryPathMatcher}.
@@ -45,18 +47,18 @@ public class GitRepositoryPathMatcherTest {
@Test @Test
public void testIsPathMatching() { public void testIsPathMatching() {
assertFalse(pathMatcher.isPathMatching(repository("my-repo"), "my-repoo")); assertFalse(pathMatcher.isPathMatching(repository("space", "my-repo"), "my-repoo"));
assertFalse(pathMatcher.isPathMatching(repository("my"), "my-repo")); assertFalse(pathMatcher.isPathMatching(repository("space", "my"), "my-repo"));
assertFalse(pathMatcher.isPathMatching(repository("my"), "my-repo/with/path")); assertFalse(pathMatcher.isPathMatching(repository("space", "my"), "my-repo/with/path"));
assertTrue(pathMatcher.isPathMatching(repository("my-repo"), "my-repo")); assertTrue(pathMatcher.isPathMatching(repository("space", "my-repo"), "my-repo"));
assertTrue(pathMatcher.isPathMatching(repository("my-repo"), "my-repo.git")); assertTrue(pathMatcher.isPathMatching(repository("space", "my-repo"), "my-repo.git"));
assertTrue(pathMatcher.isPathMatching(repository("my-repo"), "my-repo/with/path")); assertTrue(pathMatcher.isPathMatching(repository("space", "my-repo"), "my-repo/with/path"));
assertTrue(pathMatcher.isPathMatching(repository("my-repo"), "my-repo.git/with/path")); assertTrue(pathMatcher.isPathMatching(repository("space", "my-repo"), "my-repo.git/with/path"));
} }
private Repository repository(String name) { private Repository repository(String namespace, String name) {
return new Repository(name, GitRepositoryHandler.TYPE_NAME, name); return new Repository(name, GitRepositoryHandler.TYPE_NAME, namespace, name);
} }
} }

View File

@@ -38,34 +38,31 @@ package sonia.scm.repository.spi;
import com.google.common.base.Charsets; import com.google.common.base.Charsets;
import com.google.common.io.Files; import com.google.common.io.Files;
import com.google.inject.Provider; import com.google.inject.Provider;
import org.eclipse.jgit.api.CommitCommand; import org.eclipse.jgit.api.CommitCommand;
import org.eclipse.jgit.api.Git; import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.api.errors.GitAPIException; import org.eclipse.jgit.api.errors.GitAPIException;
import org.eclipse.jgit.revwalk.RevCommit; import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.transport.ScmTransportProtocol; import org.eclipse.jgit.transport.ScmTransportProtocol;
import org.eclipse.jgit.transport.Transport; import org.eclipse.jgit.transport.Transport;
import org.junit.After; import org.junit.After;
import org.junit.Before; import org.junit.Before;
import org.junit.Rule; import org.junit.Rule;
import org.junit.rules.TemporaryFolder; import org.junit.rules.TemporaryFolder;
import sonia.scm.repository.Changeset; import sonia.scm.repository.Changeset;
import sonia.scm.repository.GitRepositoryHandler; import sonia.scm.repository.GitRepositoryHandler;
import sonia.scm.repository.Repository; import sonia.scm.repository.Repository;
import sonia.scm.user.User; import sonia.scm.user.User;
import sonia.scm.user.UserTestData; import sonia.scm.user.UserTestData;
import static org.junit.Assert.*;
import static org.mockito.Mockito.*;
//~--- JDK imports ------------------------------------------------------------
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import static org.junit.Assert.assertEquals;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
//~--- JDK imports ------------------------------------------------------------
/** /**
* *
* @author Sebastian Sdorra * @author Sebastian Sdorra
@@ -88,8 +85,8 @@ public class AbstractRemoteCommandTestBase
outgoingDirectory = tempFolder.newFile("outgoing"); outgoingDirectory = tempFolder.newFile("outgoing");
outgoingDirectory.delete(); outgoingDirectory.delete();
incomgingRepository = new Repository("1", "git", "incoming"); incomgingRepository = new Repository("1", "git", "space", "incoming");
outgoingRepository = new Repository("2", "git", "outgoing"); outgoingRepository = new Repository("2", "git", "space", "outgoing");
incoming = Git.init().setDirectory(incomingDirectory).setBare(false).call(); incoming = Git.init().setDirectory(incomingDirectory).setBare(false).call();
outgoing = Git.init().setDirectory(outgoingDirectory).setBare(false).call(); outgoing = Git.init().setDirectory(outgoingDirectory).setBare(false).call();

View File

@@ -35,14 +35,15 @@ package sonia.scm.web.lfs;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.mockito.InjectMocks; import org.mockito.InjectMocks;
import static org.mockito.Matchers.matches;
import org.mockito.Mock; import org.mockito.Mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import org.mockito.runners.MockitoJUnitRunner; import org.mockito.runners.MockitoJUnitRunner;
import sonia.scm.repository.Repository; import sonia.scm.repository.Repository;
import sonia.scm.store.BlobStoreFactory; import sonia.scm.store.BlobStoreFactory;
import static org.mockito.Matchers.matches;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
/** /**
* Unit tests for {@link LfsBlobStoreFactory}. * Unit tests for {@link LfsBlobStoreFactory}.
* *
@@ -59,7 +60,7 @@ public class LfsBlobStoreFactoryTest {
@Test @Test
public void getBlobStore() throws Exception { public void getBlobStore() throws Exception {
lfsBlobStoreFactory.getLfsBlobStore(new Repository("the-id", "GIT", "the-name")); lfsBlobStoreFactory.getLfsBlobStore(new Repository("the-id", "GIT", "space", "the-name"));
// just make sure the right parameter is passed, as properly validating the return value is nearly impossible with // just make sure the right parameter is passed, as properly validating the return value is nearly impossible with
// the return value (and should not be part of this test) // the return value (and should not be part of this test)

View File

@@ -7,8 +7,9 @@ import javax.servlet.http.HttpServletRequest;
import static org.hamcrest.CoreMatchers.equalTo; import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.*; import static org.junit.Assert.assertThat;
import static org.mockito.Mockito.*; import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
/** /**
* Created by omilke on 18.05.2017. * Created by omilke on 18.05.2017.
@@ -18,14 +19,15 @@ public class LfsServletFactoryTest {
@Test @Test
public void buildBaseUri() throws Exception { public void buildBaseUri() throws Exception {
String repositoryNamespace = "space";
String repositoryName = "git-lfs-demo"; String repositoryName = "git-lfs-demo";
String result = LfsServletFactory.buildBaseUri(new Repository("", "GIT", repositoryName), RequestWithUri(repositoryName, true)); String result = LfsServletFactory.buildBaseUri(new Repository("", "GIT", repositoryNamespace, repositoryName), RequestWithUri(repositoryName, true));
assertThat(result, is(equalTo("http://localhost:8081/scm/git/git-lfs-demo.git/info/lfs/objects/"))); assertThat(result, is(equalTo("http://localhost:8081/scm/git/git-lfs-demo.git/info/lfs/objects/")));
//result will be with dot-gix suffix, ide //result will be with dot-gix suffix, ide
result = LfsServletFactory.buildBaseUri(new Repository("", "GIT", repositoryName), RequestWithUri(repositoryName, false)); result = LfsServletFactory.buildBaseUri(new Repository("", "GIT", repositoryNamespace, repositoryName), RequestWithUri(repositoryName, false));
assertThat(result, is(equalTo("http://localhost:8081/scm/git/git-lfs-demo.git/info/lfs/objects/"))); assertThat(result, is(equalTo("http://localhost:8081/scm/git/git-lfs-demo.git/info/lfs/objects/")));
} }

View File

@@ -34,20 +34,18 @@ package sonia.scm.repository.spi;
//~--- non-JDK imports -------------------------------------------------------- //~--- non-JDK imports --------------------------------------------------------
import com.aragost.javahg.Repository; import com.aragost.javahg.Repository;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import sonia.scm.repository.HgHookManager; import sonia.scm.repository.HgHookManager;
import sonia.scm.repository.HgRepositoryHandler; import sonia.scm.repository.HgRepositoryHandler;
import sonia.scm.repository.RepositoryHookType; import sonia.scm.repository.RepositoryHookType;
import sonia.scm.repository.spi.javahg.HgLogChangesetCommand; import sonia.scm.repository.spi.javahg.HgLogChangesetCommand;
import sonia.scm.web.HgUtil; import sonia.scm.web.HgUtil;
//~--- JDK imports ------------------------------------------------------------
import java.io.File; import java.io.File;
//~--- JDK imports ------------------------------------------------------------
/** /**
* *
* @author Sebastian Sdorra * @author Sebastian Sdorra
@@ -63,22 +61,12 @@ public class HgHookChangesetProvider implements HookChangesetProvider
//~--- constructors --------------------------------------------------------- //~--- constructors ---------------------------------------------------------
/**
* Constructs ...
*
*
* @param handler
* @param repositoryName
* @param hookManager
* @param startRev
* @param type
*/
public HgHookChangesetProvider(HgRepositoryHandler handler, public HgHookChangesetProvider(HgRepositoryHandler handler,
String repositoryName, HgHookManager hookManager, String startRev, String id, HgHookManager hookManager, String startRev,
RepositoryHookType type) RepositoryHookType type)
{ {
this.handler = handler; this.handler = handler;
this.repositoryName = repositoryName; this.id = id;
this.hookManager = hookManager; this.hookManager = hookManager;
this.startRev = startRev; this.startRev = startRev;
this.type = type; this.type = type;
@@ -136,7 +124,7 @@ public class HgHookChangesetProvider implements HookChangesetProvider
private Repository open() private Repository open()
{ {
File directory = handler.getConfig().getRepositoryDirectory(); File directory = handler.getConfig().getRepositoryDirectory();
File repositoryDirectory = new File(directory, repositoryName); File repositoryDirectory = new File(directory, id);
// use HG_PENDING only for pre receive hooks // use HG_PENDING only for pre receive hooks
boolean pending = type == RepositoryHookType.PRE_RECEIVE; boolean pending = type == RepositoryHookType.PRE_RECEIVE;
@@ -155,7 +143,7 @@ public class HgHookChangesetProvider implements HookChangesetProvider
private HgHookManager hookManager; private HgHookManager hookManager;
/** Field description */ /** Field description */
private String repositoryName; private String id;
/** Field description */ /** Field description */
private HookChangesetResponse response; private HookChangesetResponse response;

View File

@@ -38,16 +38,16 @@ import sonia.scm.repository.HgRepositoryHandler;
import sonia.scm.repository.RepositoryHookType; import sonia.scm.repository.RepositoryHookType;
import sonia.scm.repository.api.HgHookBranchProvider; import sonia.scm.repository.api.HgHookBranchProvider;
import sonia.scm.repository.api.HgHookMessageProvider; import sonia.scm.repository.api.HgHookMessageProvider;
import sonia.scm.repository.api.HgHookTagProvider;
import sonia.scm.repository.api.HookBranchProvider; import sonia.scm.repository.api.HookBranchProvider;
import sonia.scm.repository.api.HookFeature; import sonia.scm.repository.api.HookFeature;
import sonia.scm.repository.api.HookMessageProvider; import sonia.scm.repository.api.HookMessageProvider;
import sonia.scm.repository.api.HookTagProvider;
//~--- JDK imports ------------------------------------------------------------
import java.util.EnumSet; import java.util.EnumSet;
import java.util.Set; import java.util.Set;
import sonia.scm.repository.api.HgHookTagProvider;
import sonia.scm.repository.api.HookTagProvider; //~--- JDK imports ------------------------------------------------------------
/** /**
* Mercurial implementation of {@link HookContextProvider}. * Mercurial implementation of {@link HookContextProvider}.
@@ -67,17 +67,16 @@ public class HgHookContextProvider extends HookContextProvider
* Constructs a new instance. * Constructs a new instance.
* *
* @param handler mercurial repository handler * @param handler mercurial repository handler
* @param repositoryName name of changed repository * @param namespaceAndName namespace and name of changed repository
* @param hookManager mercurial hook manager * @param hookManager mercurial hook manager
* @param startRev start revision * @param startRev start revision
* @param type type of hook * @param type type of hook
*/ */
public HgHookContextProvider(HgRepositoryHandler handler, public HgHookContextProvider(HgRepositoryHandler handler,
String repositoryName, HgHookManager hookManager, String startRev, String id, HgHookManager hookManager, String startRev,
RepositoryHookType type) RepositoryHookType type)
{ {
this.hookChangesetProvider = new HgHookChangesetProvider(handler, this.hookChangesetProvider = new HgHookChangesetProvider(handler, id, hookManager, startRev, type);
repositoryName, hookManager, startRev, type);
} }
//~--- get methods ---------------------------------------------------------- //~--- get methods ----------------------------------------------------------

View File

@@ -39,10 +39,8 @@ import com.google.common.base.Stopwatch;
import com.google.common.base.Strings; import com.google.common.base.Strings;
import com.google.inject.Inject; import com.google.inject.Inject;
import com.google.inject.Singleton; import com.google.inject.Singleton;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import sonia.scm.SCMContext; import sonia.scm.SCMContext;
import sonia.scm.config.ScmConfiguration; import sonia.scm.config.ScmConfiguration;
import sonia.scm.repository.HgConfig; import sonia.scm.repository.HgConfig;
@@ -60,19 +58,17 @@ import sonia.scm.web.cgi.CGIExecutor;
import sonia.scm.web.cgi.CGIExecutorFactory; import sonia.scm.web.cgi.CGIExecutorFactory;
import sonia.scm.web.cgi.EnvList; import sonia.scm.web.cgi.EnvList;
//~--- JDK imports ------------------------------------------------------------
import java.io.File;
import java.io.IOException;
import java.util.Base64;
import java.util.Enumeration;
import javax.servlet.ServletException; import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession; import javax.servlet.http.HttpSession;
import java.io.File;
import java.io.IOException;
import java.util.Base64;
import java.util.Enumeration;
//~--- JDK imports ------------------------------------------------------------
/** /**
* *
@@ -305,7 +301,7 @@ public class HgCGIServlet extends HttpServlet
executor.setExceptionHandler(exceptionHandler); executor.setExceptionHandler(exceptionHandler);
executor.setStatusCodeHandler(exceptionHandler); executor.setStatusCodeHandler(exceptionHandler);
executor.setContentLengthWorkaround(true); executor.setContentLengthWorkaround(true);
executor.getEnvironment().set(ENV_REPOSITORY_NAME, name); executor.getEnvironment().set(ENV_REPOSITORY_NAME, repository.getNamespace() + "/" + repository.getName());
executor.getEnvironment().set(ENV_REPOSITORY_PATH, executor.getEnvironment().set(ENV_REPOSITORY_PATH,
directory.getAbsolutePath()); directory.getAbsolutePath());

View File

@@ -40,13 +40,10 @@ import com.google.common.io.Closeables;
import com.google.inject.Inject; import com.google.inject.Inject;
import com.google.inject.Provider; import com.google.inject.Provider;
import com.google.inject.Singleton; import com.google.inject.Singleton;
import org.apache.shiro.SecurityUtils; import org.apache.shiro.SecurityUtils;
import org.apache.shiro.subject.Subject; import org.apache.shiro.subject.Subject;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import sonia.scm.repository.HgContext; import sonia.scm.repository.HgContext;
import sonia.scm.repository.HgHookManager; import sonia.scm.repository.HgHookManager;
import sonia.scm.repository.HgRepositoryHandler; import sonia.scm.repository.HgRepositoryHandler;
@@ -62,19 +59,17 @@ import sonia.scm.security.Tokens;
import sonia.scm.util.HttpUtil; import sonia.scm.util.HttpUtil;
import sonia.scm.util.Util; import sonia.scm.util.Util;
//~--- JDK imports ------------------------------------------------------------
import java.io.IOException;
import java.io.PrintWriter;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.servlet.ServletException; import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
//~--- JDK imports ------------------------------------------------------------
/** /**
* *
@@ -167,27 +162,24 @@ public class HgHookCallbackServlet extends HttpServlet
} }
} }
/**
* Method description
*
*
* @param request
* @param response
*
* @throws IOException
* @throws ServletException
*/
@Override @Override
protected void doPost(HttpServletRequest request, protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
HttpServletResponse response) try {
throws ServletException, IOException handlePostRequest(request, response);
} catch (IOException ex) {
logger.warn("error in hook callback execution, sending internal server error", ex);
response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
}
}
private void handlePostRequest(HttpServletRequest request, HttpServletResponse response) throws IOException
{ {
String strippedURI = HttpUtil.getStrippedURI(request); String strippedURI = HttpUtil.getStrippedURI(request);
Matcher m = REGEX_URL.matcher(strippedURI); Matcher m = REGEX_URL.matcher(strippedURI);
if (m.matches()) if (m.matches())
{ {
String repositoryId = getRepositoryName(request); String id = getRepositoryId(request);
String type = m.group(1); String type = m.group(1);
String challenge = request.getParameter(PARAM_CHALLENGE); String challenge = request.getParameter(PARAM_CHALLENGE);
@@ -204,7 +196,7 @@ public class HgHookCallbackServlet extends HttpServlet
authenticate(request, credentials); authenticate(request, credentials);
} }
hookCallback(response, repositoryId, type, challenge, node); hookCallback(response, id, type, challenge, node);
} }
else if (logger.isDebugEnabled()) else if (logger.isDebugEnabled())
{ {
@@ -227,13 +219,6 @@ public class HgHookCallbackServlet extends HttpServlet
} }
} }
/**
* Method description
*
*
* @param request
* @param credentials
*/
private void authenticate(HttpServletRequest request, String credentials) private void authenticate(HttpServletRequest request, String credentials)
{ {
try try
@@ -270,18 +255,7 @@ public class HgHookCallbackServlet extends HttpServlet
} }
} }
/** private void fireHook(HttpServletResponse response, String id,
* Method description
*
*
* @param response
* @param repositoryName
* @param node
* @param type
*
* @throws IOException
*/
private void fireHook(HttpServletResponse response, String repositoryName,
String node, RepositoryHookType type) String node, RepositoryHookType type)
throws IOException throws IOException
{ {
@@ -294,11 +268,10 @@ public class HgHookCallbackServlet extends HttpServlet
contextProvider.get().setPending(true); contextProvider.get().setPending(true);
} }
context = new HgHookContextProvider(handler, repositoryName, hookManager, context = new HgHookContextProvider(handler, id, hookManager,
node, type); node, type);
hookEventFacade.handle(HgRepositoryHandler.TYPE_NAME, hookEventFacade.handle(id).fireHookEvent(type, context);
repositoryName).fireHookEvent(type, context);
printMessages(response, context); printMessages(response, context);
} }
@@ -306,7 +279,7 @@ public class HgHookCallbackServlet extends HttpServlet
{ {
if (logger.isErrorEnabled()) if (logger.isErrorEnabled())
{ {
logger.error("could not find repository {}", repositoryName); logger.error("could not find repository with id {}", id);
if (logger.isTraceEnabled()) if (logger.isTraceEnabled())
{ {
@@ -322,22 +295,7 @@ public class HgHookCallbackServlet extends HttpServlet
} }
} }
/** private void hookCallback(HttpServletResponse response, String id, String typeName, String challenge, String node) throws IOException {
* Method description
*
*
* @param response
* @param repositoryName
* @param typeName
* @param challenge
* @param node
*
* @throws IOException
*/
private void hookCallback(HttpServletResponse response,
String repositoryName, String typeName, String challenge, String node)
throws IOException
{
if (hookManager.isAcceptAble(challenge)) if (hookManager.isAcceptAble(challenge))
{ {
RepositoryHookType type = null; RepositoryHookType type = null;
@@ -353,7 +311,7 @@ public class HgHookCallbackServlet extends HttpServlet
if (type != null) if (type != null)
{ {
fireHook(response, repositoryName, node, type); fireHook(response, id, node, type);
} }
else else
{ {
@@ -403,12 +361,12 @@ public class HgHookCallbackServlet extends HttpServlet
* Method description * Method description
* *
* *
* @param resonse * @param response
* @param context * @param context
* *
* @throws IOException * @throws IOException
*/ */
private void printMessages(HttpServletResponse resonse, private void printMessages(HttpServletResponse response,
HgHookContextProvider context) HgHookContextProvider context)
throws IOException throws IOException
{ {
@@ -420,7 +378,7 @@ public class HgHookCallbackServlet extends HttpServlet
try try
{ {
writer = resonse.getWriter(); writer = response.getWriter();
printMessages(writer, msgs); printMessages(writer, msgs);
} }
@@ -506,9 +464,9 @@ public class HgHookCallbackServlet extends HttpServlet
* *
* @return * @return
*/ */
private String getRepositoryName(HttpServletRequest request) private String getRepositoryId(HttpServletRequest request)
{ {
String name = null; String id = null;
String path = request.getParameter(PARAM_REPOSITORYPATH); String path = request.getParameter(PARAM_REPOSITORYPATH);
if (Util.isNotEmpty(path)) if (Util.isNotEmpty(path))
@@ -520,11 +478,11 @@ public class HgHookCallbackServlet extends HttpServlet
*/ */
try try
{ {
name = RepositoryUtil.getRepositoryName(handler, path); id = RepositoryUtil.getRepositoryId(handler, path);
} }
catch (IOException ex) catch (IOException ex)
{ {
logger.error("could not find name of repository", ex); logger.error("could not find namespace and name of repository", ex);
} }
} }
else if (logger.isWarnEnabled()) else if (logger.isWarnEnabled())
@@ -532,7 +490,7 @@ public class HgHookCallbackServlet extends HttpServlet
logger.warn("no repository path parameter found"); logger.warn("no repository path parameter found");
} }
return name; return id;
} }
//~--- fields --------------------------------------------------------------- //~--- fields ---------------------------------------------------------------

View File

@@ -1,10 +1,10 @@
/** /**
* Copyright (c) 2010, Sebastian Sdorra * Copyright (c) 2010, Sebastian Sdorra
* All rights reserved. * All rights reserved.
* * <p>
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met: * modification, are permitted provided that the following conditions are met:
* * <p>
* 1. Redistributions of source code must retain the above copyright notice, * 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer. * this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice, * 2. Redistributions in binary form must reproduce the above copyright notice,
@@ -13,7 +13,7 @@
* 3. Neither the name of SCM-Manager; nor the names of its * 3. Neither the name of SCM-Manager; nor the names of its
* contributors may be used to endorse or promote products derived from this * contributors may be used to endorse or promote products derived from this
* software without specific prior written permission. * software without specific prior written permission.
* * <p>
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
@@ -24,43 +24,45 @@
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * 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 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* * <p>
* http://bitbucket.org/sdorra/scm-manager * http://bitbucket.org/sdorra/scm-manager
*
*/ */
package sonia.scm.repository; package sonia.scm.repository;
//~--- non-JDK imports -------------------------------------------------------- //~--- non-JDK imports --------------------------------------------------------
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
import sonia.scm.io.DefaultFileSystem; import sonia.scm.io.DefaultFileSystem;
import sonia.scm.store.ConfigurationStoreFactory;
import static org.junit.Assert.*;
//~--- JDK imports ------------------------------------------------------------
import java.io.File; import java.io.File;
import sonia.scm.store.ConfigurationStoreFactory;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
//~--- JDK imports ------------------------------------------------------------
/** /**
* *
* @author Sebastian Sdorra * @author Sebastian Sdorra
*/ */
public class HgRepositoryHandlerTest extends SimpleRepositoryHandlerTestBase @RunWith(MockitoJUnitRunner.class)
{ public class HgRepositoryHandlerTest extends SimpleRepositoryHandlerTestBase {
@Mock
private ConfigurationStoreFactory factory;
@Mock
private com.google.inject.Provider<HgContext> provider;
/**
* Method description
*
*
* @param directory
*/
@Override @Override
protected void checkDirectory(File directory) protected void checkDirectory(File directory) {
{
File hgDirectory = new File(directory, ".hg"); File hgDirectory = new File(directory, ".hg");
assertTrue(hgDirectory.exists()); assertTrue(hgDirectory.exists());
@@ -73,19 +75,9 @@ public class HgRepositoryHandlerTest extends SimpleRepositoryHandlerTestBase
assertTrue(hgrc.length() > 0); assertTrue(hgrc.length() > 0);
} }
/**
* Method description
*
*
* @param factory
* @param directory
*
* @return
*/
@Override @Override
protected RepositoryHandler createRepositoryHandler(ConfigurationStoreFactory factory, protected RepositoryHandler createRepositoryHandler(ConfigurationStoreFactory factory,
File directory) File directory) {
{
HgRepositoryHandler handler = new HgRepositoryHandler(factory, HgRepositoryHandler handler = new HgRepositoryHandler(factory,
new DefaultFileSystem(), new DefaultFileSystem(),
new HgContextProvider()); new HgContextProvider());
@@ -97,5 +89,21 @@ public class HgRepositoryHandlerTest extends SimpleRepositoryHandlerTestBase
return handler; return handler;
} }
@Test
public void getDirectory() {
HgRepositoryHandler repositoryHandler = new HgRepositoryHandler(factory,
new DefaultFileSystem(), provider);
HgConfig hgConfig = new HgConfig();
hgConfig.setRepositoryDirectory(new File("/path"));
hgConfig.setHgBinary("hg");
hgConfig.setPythonBinary("python");
repositoryHandler.setConfig(hgConfig);
Repository repository = new Repository("id", "git", "Space", "Name");
File path = repositoryHandler.getDirectory(repository);
assertEquals("/path/id", path.getAbsolutePath());
}
} }
//~--- non-JDK imports --------------------------------------------------------

View File

@@ -41,14 +41,11 @@ import com.aragost.javahg.Repository;
import com.aragost.javahg.RepositoryConfiguration; import com.aragost.javahg.RepositoryConfiguration;
import com.aragost.javahg.commands.AddCommand; import com.aragost.javahg.commands.AddCommand;
import com.aragost.javahg.commands.CommitCommand; import com.aragost.javahg.commands.CommitCommand;
import com.google.common.base.Charsets; import com.google.common.base.Charsets;
import com.google.common.io.Files; import com.google.common.io.Files;
import org.junit.Before; import org.junit.Before;
import org.junit.Rule; import org.junit.Rule;
import org.junit.rules.TemporaryFolder; import org.junit.rules.TemporaryFolder;
import sonia.scm.AbstractTestBase; import sonia.scm.AbstractTestBase;
import sonia.scm.repository.HgConfig; import sonia.scm.repository.HgConfig;
import sonia.scm.repository.HgContext; import sonia.scm.repository.HgContext;
@@ -58,15 +55,15 @@ import sonia.scm.user.User;
import sonia.scm.user.UserTestData; import sonia.scm.user.UserTestData;
import sonia.scm.util.MockUtil; import sonia.scm.util.MockUtil;
import static org.junit.Assert.*;
import static org.mockito.Mockito.*;
//~--- JDK imports ------------------------------------------------------------
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import static org.junit.Assert.assertEquals;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
//~--- JDK imports ------------------------------------------------------------
/** /**
* *
* @author Sebastian Sdorra * @author Sebastian Sdorra
@@ -90,10 +87,8 @@ public abstract class IncomingOutgoingTestBase extends AbstractTestBase
incomingDirectory = tempFolder.newFolder("incoming"); incomingDirectory = tempFolder.newFolder("incoming");
outgoingDirectory = tempFolder.newFolder("outgoing"); outgoingDirectory = tempFolder.newFolder("outgoing");
incomingRepository = new sonia.scm.repository.Repository("1", "hg", incomingRepository = new sonia.scm.repository.Repository("1", "hg", "space", "incoming");
"incoming"); outgoingRepository = new sonia.scm.repository.Repository("2", "hg", "space", "outgoing");
outgoingRepository = new sonia.scm.repository.Repository("2", "hg",
"outgoing");
incoming = Repository.create(createConfig(temp), incomingDirectory); incoming = Repository.create(createConfig(temp), incomingDirectory);
outgoing = Repository.create(createConfig(temp), outgoingDirectory); outgoing = Repository.create(createConfig(temp), outgoingDirectory);

View File

@@ -0,0 +1,41 @@
package sonia.scm.web;
import org.junit.Test;
import sonia.scm.repository.HgConfig;
import sonia.scm.repository.HgRepositoryHandler;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import static org.mockito.Matchers.anyInt;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import static sonia.scm.web.HgHookCallbackServlet.PARAM_REPOSITORYPATH;
public class HgHookCallbackServletTest {
@Test
public void shouldExtractCorrectRepositoryId() throws ServletException, IOException {
HgRepositoryHandler handler = mock(HgRepositoryHandler.class);
HgHookCallbackServlet servlet = new HgHookCallbackServlet(null, handler, null, null);
HttpServletRequest request = mock(HttpServletRequest.class);
HttpServletResponse response = mock(HttpServletResponse.class);
HgConfig config = mock(HgConfig.class);
when(request.getContextPath()).thenReturn("http://example.com/scm");
when(request.getRequestURI()).thenReturn("http://example.com/scm/hook/hg/pretxnchangegroup");
when(request.getParameter(PARAM_REPOSITORYPATH)).thenReturn("/tmp/hg/12345");
when(handler.getConfig()).thenReturn(config);
when(config.getRepositoryDirectory()).thenReturn(new File("/tmp/hg"));
servlet.doPost(request, response);
verify(response, never()).sendError(anyInt());
}
}

View File

@@ -37,7 +37,6 @@ package sonia.scm.repository;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.tmatesoft.svn.core.SVNCancelException; import org.tmatesoft.svn.core.SVNCancelException;
import org.tmatesoft.svn.core.SVNErrorCode; import org.tmatesoft.svn.core.SVNErrorCode;
import org.tmatesoft.svn.core.SVNErrorMessage; import org.tmatesoft.svn.core.SVNErrorMessage;
@@ -45,21 +44,19 @@ import org.tmatesoft.svn.core.SVNException;
import org.tmatesoft.svn.core.internal.io.fs.FSHook; import org.tmatesoft.svn.core.internal.io.fs.FSHook;
import org.tmatesoft.svn.core.internal.io.fs.FSHookEvent; import org.tmatesoft.svn.core.internal.io.fs.FSHookEvent;
import org.tmatesoft.svn.core.internal.io.fs.FSHooks; import org.tmatesoft.svn.core.internal.io.fs.FSHooks;
import sonia.scm.repository.spi.AbstractSvnHookChangesetProvider; import sonia.scm.repository.spi.AbstractSvnHookChangesetProvider;
import sonia.scm.repository.spi.HookEventFacade; import sonia.scm.repository.spi.HookEventFacade;
import sonia.scm.repository.spi.SvnHookContextProvider; import sonia.scm.repository.spi.SvnHookContextProvider;
import sonia.scm.repository.spi.SvnPostReceiveHookChangesetProvier; import sonia.scm.repository.spi.SvnPostReceiveHookChangesetProvier;
import sonia.scm.repository.spi.SvnPreReceiveHookChangesetProvier; import sonia.scm.repository.spi.SvnPreReceiveHookChangesetProvier;
import sonia.scm.util.AssertUtil; import sonia.scm.util.AssertUtil;
import sonia.scm.util.IOUtil;
import sonia.scm.util.Util; import sonia.scm.util.Util;
//~--- JDK imports ------------------------------------------------------------
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
//~--- JDK imports ------------------------------------------------------------
/** /**
* *
* @author Sebastian Sdorra * @author Sebastian Sdorra
@@ -166,12 +163,10 @@ public class SvnRepositoryHook implements FSHook
{ {
try try
{ {
String name = getRepositoryName(directory); String id = getRepositoryId(directory);
name = IOUtil.trimSeperatorChars(name);
//J- //J-
hookEventFacade.handle(SvnRepositoryHandler.TYPE_NAME, name) hookEventFacade.handle(id)
.fireHookEvent( .fireHookEvent(
changesetProvider.getType(), changesetProvider.getType(),
new SvnHookContextProvider(changesetProvider) new SvnHookContextProvider(changesetProvider)
@@ -202,11 +197,11 @@ public class SvnRepositoryHook implements FSHook
* *
* @throws IOException * @throws IOException
*/ */
private String getRepositoryName(File directory) throws IOException private String getRepositoryId(File directory) throws IOException
{ {
AssertUtil.assertIsNotNull(directory); AssertUtil.assertIsNotNull(directory);
return RepositoryUtil.getRepositoryName(handler, directory); return RepositoryUtil.getRepositoryId(handler, directory);
} }
//~--- fields --------------------------------------------------------------- //~--- fields ---------------------------------------------------------------

View File

@@ -37,13 +37,10 @@ package sonia.scm.web;
import com.google.inject.Inject; import com.google.inject.Inject;
import com.google.inject.Singleton; import com.google.inject.Singleton;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.tmatesoft.svn.core.internal.server.dav.DAVConfig; import org.tmatesoft.svn.core.internal.server.dav.DAVConfig;
import org.tmatesoft.svn.core.internal.server.dav.DAVServlet; import org.tmatesoft.svn.core.internal.server.dav.DAVServlet;
import sonia.scm.repository.Repository; import sonia.scm.repository.Repository;
import sonia.scm.repository.RepositoryProvider; import sonia.scm.repository.RepositoryProvider;
import sonia.scm.repository.RepositoryRequestListenerUtil; import sonia.scm.repository.RepositoryRequestListenerUtil;
@@ -51,14 +48,13 @@ import sonia.scm.repository.SvnRepositoryHandler;
import sonia.scm.util.AssertUtil; import sonia.scm.util.AssertUtil;
import sonia.scm.util.HttpUtil; import sonia.scm.util.HttpUtil;
//~--- JDK imports ------------------------------------------------------------
import java.io.IOException;
import javax.servlet.ServletException; import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper; import javax.servlet.http.HttpServletRequestWrapper;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
//~--- JDK imports ------------------------------------------------------------
/** /**
* *
@@ -224,7 +220,7 @@ public class SvnDAVServlet extends DAVServlet
pathInfo = pathInfo.substring(1); pathInfo = pathInfo.substring(1);
} }
pathInfo = pathInfo.substring(repository.getName().length()); pathInfo = pathInfo.substring(repository.getNamespace().length() + 1 + repository.getName().length());
} }
return pathInfo; return pathInfo;
@@ -249,7 +245,7 @@ public class SvnDAVServlet extends DAVServlet
servletPath = servletPath.concat(HttpUtil.SEPARATOR_PATH); servletPath = servletPath.concat(HttpUtil.SEPARATOR_PATH);
} }
servletPath = servletPath.concat(repository.getName()); servletPath = servletPath + repository.getNamespace() + "/" + repository.getName();
} }
return servletPath; return servletPath;

View File

@@ -1,10 +1,10 @@
/** /**
* Copyright (c) 2010, Sebastian Sdorra * Copyright (c) 2010, Sebastian Sdorra
* All rights reserved. * All rights reserved.
* * <p>
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met: * modification, are permitted provided that the following conditions are met:
* * <p>
* 1. Redistributions of source code must retain the above copyright notice, * 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer. * this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice, * 2. Redistributions in binary form must reproduce the above copyright notice,
@@ -13,7 +13,7 @@
* 3. Neither the name of SCM-Manager; nor the names of its * 3. Neither the name of SCM-Manager; nor the names of its
* contributors may be used to endorse or promote products derived from this * contributors may be used to endorse or promote products derived from this
* software without specific prior written permission. * software without specific prior written permission.
* * <p>
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
@@ -24,42 +24,56 @@
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * 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 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* * <p>
* http://bitbucket.org/sdorra/scm-manager * http://bitbucket.org/sdorra/scm-manager
*
*/ */
package sonia.scm.repository; package sonia.scm.repository;
//~--- non-JDK imports --------------------------------------------------------
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
import sonia.scm.io.DefaultFileSystem; import sonia.scm.io.DefaultFileSystem;
import sonia.scm.repository.api.HookContextFactory;
import static org.junit.Assert.*; import sonia.scm.repository.spi.HookEventFacade;
import sonia.scm.store.ConfigurationStore;
//~--- JDK imports ------------------------------------------------------------ import sonia.scm.store.ConfigurationStoreFactory;
import java.io.File; import java.io.File;
import sonia.scm.store.ConfigurationStoreFactory;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.mockito.Matchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
//~--- JDK imports ------------------------------------------------------------
/** /**
* *
* @author Sebastian Sdorra * @author Sebastian Sdorra
*/ */
public class SvnRepositoryHandlerTest extends SimpleRepositoryHandlerTestBase @RunWith(MockitoJUnitRunner.class)
{ public class SvnRepositoryHandlerTest extends SimpleRepositoryHandlerTestBase {
@Mock
private ConfigurationStoreFactory factory;
@Mock
private ConfigurationStore store;
@Mock
private com.google.inject.Provider<RepositoryManager> repositoryManagerProvider;
private HookContextFactory hookContextFactory = new HookContextFactory(mock(PreProcessorUtil.class));
private HookEventFacade facade = new HookEventFacade(repositoryManagerProvider, hookContextFactory);
/**
* Method description
*
*
* @param directory
*/
@Override @Override
protected void checkDirectory(File directory) protected void checkDirectory(File directory) {
{
File format = new File(directory, "format"); File format = new File(directory, "format");
assertTrue(format.exists()); assertTrue(format.exists());
@@ -71,19 +85,9 @@ public class SvnRepositoryHandlerTest extends SimpleRepositoryHandlerTestBase
assertTrue(db.isDirectory()); assertTrue(db.isDirectory());
} }
/**
* Method description
*
*
* @param factory
* @param directory
*
* @return
*/
@Override @Override
protected RepositoryHandler createRepositoryHandler(ConfigurationStoreFactory factory, protected RepositoryHandler createRepositoryHandler(ConfigurationStoreFactory factory,
File directory) File directory) {
{
SvnRepositoryHandler handler = new SvnRepositoryHandler(factory, SvnRepositoryHandler handler = new SvnRepositoryHandler(factory,
new DefaultFileSystem(), null); new DefaultFileSystem(), null);
@@ -98,4 +102,20 @@ public class SvnRepositoryHandlerTest extends SimpleRepositoryHandlerTestBase
return handler; return handler;
} }
@Test
public void getDirectory() {
when(factory.getStore(any(), any())).thenReturn(store);
SvnRepositoryHandler repositoryHandler = new SvnRepositoryHandler(factory,
new DefaultFileSystem(), facade);
SvnConfig svnConfig = new SvnConfig();
svnConfig.setRepositoryDirectory(new File("/path"));
repositoryHandler.setConfig(svnConfig);
Repository repository = new Repository("id", "svn", "Space", "Name");
File path = repositoryHandler.getDirectory(repository);
assertEquals("/path/id", path.getAbsolutePath());
}
} }

View File

@@ -1,10 +1,10 @@
/** /**
* Copyright (c) 2010, Sebastian Sdorra * Copyright (c) 2010, Sebastian Sdorra
* All rights reserved. * All rights reserved.
* * <p>
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met: * modification, are permitted provided that the following conditions are met:
* * <p>
* 1. Redistributions of source code must retain the above copyright notice, * 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer. * this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice, * 2. Redistributions in binary form must reproduce the above copyright notice,
@@ -13,7 +13,7 @@
* 3. Neither the name of SCM-Manager; nor the names of its * 3. Neither the name of SCM-Manager; nor the names of its
* contributors may be used to endorse or promote products derived from this * contributors may be used to endorse or promote products derived from this
* software without specific prior written permission. * software without specific prior written permission.
* * <p>
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
@@ -24,113 +24,67 @@
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * 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 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* * <p>
* http://bitbucket.org/sdorra/scm-manager * http://bitbucket.org/sdorra/scm-manager
*
*/ */
package sonia.scm.repository; package sonia.scm.repository;
//~--- non-JDK imports -------------------------------------------------------- //~--- non-JDK imports --------------------------------------------------------
import sonia.scm.Type; import sonia.scm.Type;
import sonia.scm.io.DefaultFileSystem; import sonia.scm.io.DefaultFileSystem;
import sonia.scm.store.ConfigurationStoreFactory;
//~--- JDK imports ------------------------------------------------------------
import java.io.File; import java.io.File;
import java.io.IOException; import java.util.HashSet;
import sonia.scm.store.ConfigurationStoreFactory; import java.util.Set;
//~--- JDK imports ------------------------------------------------------------
/** /**
* *
* @author Sebastian Sdorra * @author Sebastian Sdorra
*/ */
public class DummyRepositoryHandler public class DummyRepositoryHandler
extends AbstractSimpleRepositoryHandler<SimpleRepositoryConfig> extends AbstractSimpleRepositoryHandler<SimpleRepositoryConfig> {
{
/** Field description */
public static final String TYPE_DISPLAYNAME = "Dummy"; public static final String TYPE_DISPLAYNAME = "Dummy";
/** Field description */
public static final String TYPE_NAME = "dummy"; public static final String TYPE_NAME = "dummy";
/** Field description */
public static final Type TYPE = new Type(TYPE_NAME, TYPE_DISPLAYNAME); public static final Type TYPE = new Type(TYPE_NAME, TYPE_DISPLAYNAME);
//~--- constructors --------------------------------------------------------- private final Set<String> existingRepoNames = new HashSet<>();
/** public DummyRepositoryHandler(ConfigurationStoreFactory storeFactory) {
* Constructs ...
*
*
* @param storeFactory
*/
public DummyRepositoryHandler(ConfigurationStoreFactory storeFactory)
{
super(storeFactory, new DefaultFileSystem()); super(storeFactory, new DefaultFileSystem());
} }
//~--- get methods ----------------------------------------------------------
/**
* Method description
*
*
* @return
*/
@Override @Override
public Type getType() public Type getType() {
{
return TYPE; return TYPE;
} }
//~--- methods --------------------------------------------------------------
/**
* Method description
*
*
* @param repository
* @param directory
*
* @throws IOException
* @throws RepositoryException
*/
@Override @Override
protected void create(Repository repository, File directory) protected void create(Repository repository, File directory) throws RepositoryException {
throws RepositoryException, IOException String key = repository.getNamespace() + "/" + repository.getName();
{ if (existingRepoNames.contains(key)) {
throw new RepositoryAlreadyExistsException("Repo exists");
// do nothing } else {
existingRepoNames.add(key);
}
} }
/**
* Method description
*
*
* @return
*/
@Override @Override
protected SimpleRepositoryConfig createInitialConfig() protected SimpleRepositoryConfig createInitialConfig() {
{
return new SimpleRepositoryConfig(); return new SimpleRepositoryConfig();
} }
//~--- get methods ----------------------------------------------------------
/**
* Method description
*
*
* @return
*/
@Override @Override
protected Class<SimpleRepositoryConfig> getConfigClass() protected Class<SimpleRepositoryConfig> getConfigClass() {
{
return SimpleRepositoryConfig.class; return SimpleRepositoryConfig.class;
} }
} }

View File

@@ -0,0 +1,49 @@
package sonia.scm.repository;
public class RepositoryBuilder {
private String id = "id-" + ++nextID;
private String contact = "test@example.com";
private String description = "";
private String namespace = "test";
private String name = "name";
private String type = "git";
private static int nextID = 0;
public RepositoryBuilder type(String type) {
this.type = type;
return this;
}
public RepositoryBuilder contact(String contact) {
this.contact = contact;
return this;
}
public RepositoryBuilder namespace(String namespace) {
this.namespace = namespace;
return this;
}
public RepositoryBuilder name(String name) {
this.name = name;
return this;
}
public RepositoryBuilder description(String description) {
this.description = description;
return this;
}
public Repository build() {
Repository repository = new Repository();
repository.setId(id);
repository.setType(type);
repository.setContact(contact);
repository.setNamespace(namespace);
repository.setName(name);
repository.setDescription(description);
return repository;
}
}

View File

@@ -26,154 +26,68 @@
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* *
* http://bitbucket.org/sdorra/scm-manager * http://bitbucket.org/sdorra/scm-manager
*
*/ */
package sonia.scm.repository; package sonia.scm.repository;
/** public final class RepositoryTestData {
*
* @author Sebastian Sdorra
*/
public final class RepositoryTestData
{
/** private RepositoryTestData() {
* Constructs ... }
*
*/
private RepositoryTestData() {}
//~--- methods -------------------------------------------------------------- public static Repository create42Puzzle() {
/**
* Method description
*
*
* @return
*/
public static Repository create42Puzzle()
{
return create42Puzzle(DummyRepositoryHandler.TYPE_NAME); return create42Puzzle(DummyRepositoryHandler.TYPE_NAME);
} }
/** public static Repository create42Puzzle(String type) {
* Method description return new RepositoryBuilder()
* .type(type)
* .contact("douglas.adams@hitchhiker.com")
* @param type .name("42Puzzle")
* .description("The 42 Puzzle")
* @return .build();
*/
public static Repository create42Puzzle(String type)
{
Repository repository = new Repository();
repository.setType(type);
repository.setContact("douglas.adams@hitchhiker.com");
repository.setName("42Puzzle");
repository.setDescription("The 42 Puzzle");
return repository;
} }
/** public static Repository createHappyVerticalPeopleTransporter() {
* Method description
*
*
* @return
*/
public static Repository createHappyVerticalPeopleTransporter()
{
return createHappyVerticalPeopleTransporter( return createHappyVerticalPeopleTransporter(
DummyRepositoryHandler.TYPE_NAME); DummyRepositoryHandler.TYPE_NAME);
} }
/** public static Repository createHappyVerticalPeopleTransporter(String type) {
* Method description return new RepositoryBuilder()
* .type(type)
* .contact("zaphod.beeblebrox@hitchhiker.com")
* .name("happyVerticalPeopleTransporter")
* @param type .description("Happy Vertical People Transporter")
* @return .build();
*/
public static Repository createHappyVerticalPeopleTransporter(String type)
{
Repository happyVerticalPeopleTransporter = new Repository();
happyVerticalPeopleTransporter.setType(type);
happyVerticalPeopleTransporter.setContact(
"zaphod.beeblebrox@hitchhiker.com");
happyVerticalPeopleTransporter.setName("happyVerticalPeopleTransporter");
happyVerticalPeopleTransporter.setDescription(
"Happy Vertical People Transporter");
return happyVerticalPeopleTransporter;
} }
/** public static Repository createHeartOfGold() {
* Method description
*
*
* @return
*/
public static Repository createHeartOfGold()
{
return createHeartOfGold(DummyRepositoryHandler.TYPE_NAME); return createHeartOfGold(DummyRepositoryHandler.TYPE_NAME);
} }
/** public static Repository createHeartOfGold(String type) {
* Method description return new RepositoryBuilder()
* .type(type)
* .contact("zaphod.beeblebrox@hitchhiker.com")
* .name("HeartOfGold")
* @param type .description(
* @return "Heart of Gold is the first prototype ship to successfully utilise the revolutionary Infinite Improbability Drive")
*/ .build();
public static Repository createHeartOfGold(String type)
{
Repository heartOfGold = new Repository();
heartOfGold.setType(type);
heartOfGold.setContact("zaphod.beeblebrox@hitchhiker.com");
heartOfGold.setName("HeartOfGold");
heartOfGold.setDescription(
"Heart of Gold is the first prototype ship to successfully utilise the revolutionary Infinite Improbability Drive");
return heartOfGold;
} }
/** public static Repository createRestaurantAtTheEndOfTheUniverse() {
* Method description
*
*
* @return
*/
public static Repository createRestaurantAtTheEndOfTheUniverse()
{
return createRestaurantAtTheEndOfTheUniverse( return createRestaurantAtTheEndOfTheUniverse(
DummyRepositoryHandler.TYPE_NAME); DummyRepositoryHandler.TYPE_NAME);
} }
/** public static Repository createRestaurantAtTheEndOfTheUniverse(String type) {
* Method description return new RepositoryBuilder()
* .type(type)
* .contact("douglas.adams@hitchhiker.com")
* @param type .name("RestaurantAtTheEndOfTheUniverse")
* .description("The Restaurant at the End of the Universe")
* @return .build();
*/
public static Repository createRestaurantAtTheEndOfTheUniverse(String type)
{
Repository repository = new Repository();
repository.setType(type);
repository.setContact("douglas.adams@hitchhiker.com");
repository.setName("RestaurantAtTheEndOfTheUniverse");
repository.setDescription("The Restaurant at the End of the Universe");
return repository;
} }
} }

View File

@@ -1,10 +1,10 @@
/** /**
* Copyright (c) 2010, Sebastian Sdorra * Copyright (c) 2010, Sebastian Sdorra
* All rights reserved. * All rights reserved.
* * <p>
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met: * modification, are permitted provided that the following conditions are met:
* * <p>
* 1. Redistributions of source code must retain the above copyright notice, * 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer. * this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice, * 2. Redistributions in binary form must reproduce the above copyright notice,
@@ -13,7 +13,7 @@
* 3. Neither the name of SCM-Manager; nor the names of its * 3. Neither the name of SCM-Manager; nor the names of its
* contributors may be used to endorse or promote products derived from this * contributors may be used to endorse or promote products derived from this
* software without specific prior written permission. * software without specific prior written permission.
* * <p>
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
@@ -24,169 +24,88 @@
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * 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 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* * <p>
* http://bitbucket.org/sdorra/scm-manager * http://bitbucket.org/sdorra/scm-manager
*
*/ */
package sonia.scm.repository; package sonia.scm.repository;
//~--- non-JDK imports -------------------------------------------------------- //~--- non-JDK imports --------------------------------------------------------
import org.junit.Test; import org.junit.Test;
import sonia.scm.AbstractTestBase; import sonia.scm.AbstractTestBase;
import sonia.scm.store.ConfigurationStoreFactory;
import sonia.scm.store.InMemoryConfigurationStoreFactory; import sonia.scm.store.InMemoryConfigurationStoreFactory;
import sonia.scm.util.IOUtil; import sonia.scm.util.IOUtil;
import static org.junit.Assert.*; import java.io.File;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
//~--- JDK imports ------------------------------------------------------------ //~--- JDK imports ------------------------------------------------------------
import java.io.File;
import java.io.IOException;
import sonia.scm.store.ConfigurationStoreFactory;
/** /**
* *
* @author Sebastian Sdorra * @author Sebastian Sdorra
*/ */
public abstract class SimpleRepositoryHandlerTestBase extends AbstractTestBase public abstract class SimpleRepositoryHandlerTestBase extends AbstractTestBase {
{
/**
* Method description
*
*
* @param directory
*/
protected abstract void checkDirectory(File directory); protected abstract void checkDirectory(File directory);
/**
* Method description
*
*
* @param factory
* @param directory
*
* @return
*/
protected abstract RepositoryHandler createRepositoryHandler( protected abstract RepositoryHandler createRepositoryHandler(
ConfigurationStoreFactory factory, File directory); ConfigurationStoreFactory factory, File directory);
/**
* Method description
*
*
* @throws IOException
* @throws RepositoryException
*/
@Test @Test
public void testCreate() throws RepositoryException, IOException public void testCreate() throws RepositoryException {
{
createRepository(); createRepository();
} }
/**
* Method description
*
*
* @throws IOException
* @throws RepositoryException
*/
@Test(expected = RepositoryAlreadyExistsException.class)
public void testCreateExisitingRepository()
throws RepositoryException, IOException
{
createRepository();
createRepository();
}
/**
* Method description
*
*
* @throws IOException
* @throws RepositoryException
*/
@Test @Test
public void testCreateResourcePath() throws RepositoryException, IOException public void testCreateResourcePath() throws RepositoryException {
{
Repository repository = createRepository(); Repository repository = createRepository();
String path = handler.createResourcePath(repository); String path = handler.createResourcePath(repository);
assertNotNull(path); assertNotNull(path);
assertTrue(path.trim().length() > 0); assertTrue(path.trim().length() > 0);
assertTrue(path.contains(repository.getName())); assertTrue(path.contains(repository.getId()));
} }
/**
* Method description
*
*
* @throws IOException
* @throws RepositoryException
*/
@Test @Test
public void testDelete() throws RepositoryException, IOException public void testDelete() throws RepositoryException {
{
Repository repository = createRepository(); Repository repository = createRepository();
handler.delete(repository); handler.delete(repository);
File directory = new File(baseDirectory, repository.getName()); File directory = new File(baseDirectory, repository.getId());
assertFalse(directory.exists()); assertFalse(directory.exists());
} }
/**
* Method description
*
*
* @throws Exception
*/
@Override @Override
protected void postSetUp() throws Exception protected void postSetUp() {
{
InMemoryConfigurationStoreFactory storeFactory = new InMemoryConfigurationStoreFactory(); InMemoryConfigurationStoreFactory storeFactory = new InMemoryConfigurationStoreFactory();
baseDirectory = new File(contextProvider.getBaseDirectory(), "repositories"); baseDirectory = new File(contextProvider.getBaseDirectory(), "repositories");
IOUtil.mkdirs(baseDirectory); IOUtil.mkdirs(baseDirectory);
handler = createRepositoryHandler(storeFactory, baseDirectory); handler = createRepositoryHandler(storeFactory, baseDirectory);
} }
/**
* Method description
*
*
* @throws Exception
*/
@Override @Override
protected void preTearDown() throws Exception protected void preTearDown() throws Exception {
{ if (handler != null) {
if (handler != null)
{
handler.close(); handler.close();
} }
} }
/** private Repository createRepository() throws RepositoryException {
* Method description
*
*
* @return
*
* @throws IOException
* @throws RepositoryException
*/
private Repository createRepository() throws RepositoryException, IOException
{
Repository repository = RepositoryTestData.createHeartOfGold(); Repository repository = RepositoryTestData.createHeartOfGold();
handler.create(repository); handler.create(repository);
File directory = new File(baseDirectory, repository.getName()); File directory = new File(baseDirectory, repository.getId());
assertTrue(directory.exists()); assertTrue(directory.exists());
assertTrue(directory.isDirectory()); assertTrue(directory.isDirectory());
@@ -195,11 +114,7 @@ public abstract class SimpleRepositoryHandlerTestBase extends AbstractTestBase
return repository; return repository;
} }
//~--- fields ---------------------------------------------------------------
/** Field description */
protected File baseDirectory; protected File baseDirectory;
/** Field description */
private RepositoryHandler handler; private RepositoryHandler handler;
} }

View File

@@ -57,16 +57,8 @@ import sonia.scm.group.xml.XmlGroupDAO;
import sonia.scm.io.DefaultFileSystem; import sonia.scm.io.DefaultFileSystem;
import sonia.scm.io.FileSystem; import sonia.scm.io.FileSystem;
import sonia.scm.net.SSLContextProvider; import sonia.scm.net.SSLContextProvider;
import sonia.scm.net.ahc.AdvancedHttpClient; import sonia.scm.net.ahc.*;
import sonia.scm.net.ahc.ContentTransformer; import sonia.scm.plugin.*;
import sonia.scm.net.ahc.DefaultAdvancedHttpClient;
import sonia.scm.net.ahc.JsonContentTransformer;
import sonia.scm.net.ahc.XmlContentTransformer;
import sonia.scm.plugin.DefaultPluginLoader;
import sonia.scm.plugin.DefaultPluginManager;
import sonia.scm.plugin.ExtensionProcessor;
import sonia.scm.plugin.PluginLoader;
import sonia.scm.plugin.PluginManager;
import sonia.scm.repository.*; import sonia.scm.repository.*;
import sonia.scm.repository.api.HookContextFactory; import sonia.scm.repository.api.HookContextFactory;
import sonia.scm.repository.api.RepositoryServiceFactory; import sonia.scm.repository.api.RepositoryServiceFactory;
@@ -78,32 +70,13 @@ import sonia.scm.resources.ResourceManager;
import sonia.scm.resources.ScriptResourceServlet; import sonia.scm.resources.ScriptResourceServlet;
import sonia.scm.schedule.QuartzScheduler; import sonia.scm.schedule.QuartzScheduler;
import sonia.scm.schedule.Scheduler; import sonia.scm.schedule.Scheduler;
import sonia.scm.security.AuthorizationChangedEventProducer; import sonia.scm.security.*;
import sonia.scm.security.CipherHandler; import sonia.scm.store.*;
import sonia.scm.security.CipherUtil;
import sonia.scm.security.ConfigurableLoginAttemptHandler;
import sonia.scm.security.DefaultKeyGenerator;
import sonia.scm.security.DefaultSecuritySystem;
import sonia.scm.security.KeyGenerator;
import sonia.scm.security.LoginAttemptHandler;
import sonia.scm.security.SecuritySystem;
import sonia.scm.store.BlobStoreFactory;
import sonia.scm.store.ConfigurationEntryStoreFactory;
import sonia.scm.store.ConfigurationStoreFactory;
import sonia.scm.store.DataStoreFactory;
import sonia.scm.store.FileBlobStoreFactory;
import sonia.scm.store.JAXBConfigurationEntryStoreFactory;
import sonia.scm.store.JAXBConfigurationStoreFactory;
import sonia.scm.store.JAXBDataStoreFactory;
import sonia.scm.template.MustacheTemplateEngine; import sonia.scm.template.MustacheTemplateEngine;
import sonia.scm.template.TemplateEngine; import sonia.scm.template.TemplateEngine;
import sonia.scm.template.TemplateEngineFactory; import sonia.scm.template.TemplateEngineFactory;
import sonia.scm.template.TemplateServlet; import sonia.scm.template.TemplateServlet;
import sonia.scm.url.RestJsonUrlProvider; import sonia.scm.url.*;
import sonia.scm.url.RestXmlUrlProvider;
import sonia.scm.url.UrlProvider;
import sonia.scm.url.UrlProviderFactory;
import sonia.scm.url.WebUIUrlProvider;
import sonia.scm.user.DefaultUserManager; import sonia.scm.user.DefaultUserManager;
import sonia.scm.user.UserDAO; import sonia.scm.user.UserDAO;
import sonia.scm.user.UserManager; import sonia.scm.user.UserManager;
@@ -224,6 +197,8 @@ public class ScmServletModule extends ServletModule
ScmConfiguration config = getScmConfiguration(); ScmConfiguration config = getScmConfiguration();
CipherUtil cu = CipherUtil.getInstance(); CipherUtil cu = CipherUtil.getInstance();
bind(NamespaceStrategy.class).toProvider(NamespaceStrategyProvider.class);
// bind repository provider // bind repository provider
ThrowingProviderBinder.create(binder()).bind( ThrowingProviderBinder.create(binder()).bind(
RepositoryProvider.class, Repository.class).to( RepositoryProvider.class, Repository.class).to(
@@ -351,10 +326,10 @@ public class ScmServletModule extends ServletModule
// bind events // bind events
// bind(LastModifiedUpdateListener.class); // bind(LastModifiedUpdateListener.class);
Class<? extends NamespaceStrategy> namespaceStrategy = extensionProcessor.byExtensionPoint(NamespaceStrategy.class).iterator().next();
bind(NamespaceStrategy.class, namespaceStrategy);
} }
/** /**
* Method description * Method description
* *

View File

@@ -543,7 +543,8 @@ public class RepositoryImportResource
try try
{ {
repository = new Repository(null, type, name); // TODO #8783
// repository = new Repository(null, type, name);
manager.create(repository); manager.create(repository);
} }
catch (RepositoryAlreadyExistsException ex) catch (RepositoryAlreadyExistsException ex)
@@ -738,7 +739,8 @@ public class RepositoryImportResource
{ {
for (String repositoryName : repositoryNames) for (String repositoryName : repositoryNames)
{ {
Repository repository = manager.get(type, repositoryName); // TODO #8783
/*Repository repository = null; //manager.get(type, repositoryName);
if (repository != null) if (repository != null)
{ {
@@ -748,7 +750,7 @@ public class RepositoryImportResource
{ {
logger.warn("could not find imported repository {}", logger.warn("could not find imported repository {}",
repositoryName); repositoryName);
} }*/
} }
} }
} }

View File

@@ -556,42 +556,6 @@ public class RepositoryResource extends AbstractManagerResource<Repository, Repo
return response; return response;
} }
/**
* Returns the {@link Repository} with the specified type and name.
*
* @param type the type of the repository
* @param name the name of the repository
*
* @return the {@link Repository} with the specified type and name
*/
@GET
@Path("{type: [a-z]+}/{name: .*}")
@StatusCodes({
@ResponseCode(code = 200, condition = "success"),
@ResponseCode(code = 404, condition = "not found, no repository with the specified type and name available"),
@ResponseCode(code = 500, condition = "internal server error")
})
@TypeHint(Repository.class)
@Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
public Response getByTypeAndName(@PathParam("type") String type,
@PathParam("name") String name)
{
Response response;
Repository repository = repositoryManager.get(type, name);
if (repository != null)
{
prepareForReturn(repository);
response = Response.ok(repository).build();
}
else
{
response = Response.status(Response.Status.NOT_FOUND).build();
}
return response;
}
/** /**
* Returns the {@link Changeset} from the given repository * Returns the {@link Changeset} from the given repository
* with the specified revision. * with the specified revision.

View File

@@ -1,11 +1,17 @@
package sonia.scm.repository; package sonia.scm.repository;
import org.apache.shiro.SecurityUtils;
import sonia.scm.plugin.Extension; import sonia.scm.plugin.Extension;
/**
* The DefaultNamespaceStrategy returns the username of the currently logged in user as namespace.
* @since 2.0.0
*/
@Extension @Extension
public class DefaultNamespaceStrategy implements NamespaceStrategy{ public class DefaultNamespaceStrategy implements NamespaceStrategy {
@Override @Override
public String getNamespace() { public String getNamespace() {
return "42"; return SecurityUtils.getSubject().getPrincipal().toString();
} }
} }

View File

@@ -126,7 +126,7 @@ public class DefaultRepositoryManager extends AbstractRepositoryManager {
@Override @Override
public void close() throws IOException { public void close() {
executorService.shutdown(); executorService.shutdown();
for (RepositoryHandler handler : handlerMap.values()) { for (RepositoryHandler handler : handlerMap.values()) {
@@ -177,40 +177,16 @@ public class DefaultRepositoryManager extends AbstractRepositoryManager {
getHandler(toDelete).delete(toDelete); getHandler(toDelete).delete(toDelete);
} }
/**
* Method description
*
*
* @param repository
*
* @throws IOException
* @throws RepositoryException
*/
@Override @Override
public void importRepository(Repository repository) public void importRepository(Repository repository)
throws RepositoryException, IOException { throws RepositoryException, IOException {
create(repository, false); create(repository, false);
} }
/**
* Method description
*
*
* @param context
*/
@Override @Override
public void init(SCMContextProvider context) { public void init(SCMContextProvider context) {
} }
/**
* Method description
*
*
* @param repository
*
* @throws IOException
* @throws RepositoryException
*/
@Override @Override
public void modify(Repository repository) throws RepositoryException { public void modify(Repository repository) throws RepositoryException {
logger.info("modify repository {} of type {}", repository.getName(), repository.getType()); logger.info("modify repository {} of type {}", repository.getName(), repository.getType());
@@ -226,23 +202,13 @@ public class DefaultRepositoryManager extends AbstractRepositoryManager {
); );
} }
/**
* Method description
*
*
* @param repository
*
* @throws IOException
* @throws RepositoryException
*/
@Override @Override
public void refresh(Repository repository) public void refresh(Repository repository)
throws RepositoryException { throws RepositoryException {
AssertUtil.assertIsNotNull(repository); AssertUtil.assertIsNotNull(repository);
RepositoryPermissions.read(repository).check(); RepositoryPermissions.read(repository).check();
Repository fresh = repositoryDAO.get(repository.getType(), Repository fresh = repositoryDAO.get(repository.getNamespaceAndName());
repository.getName());
if (fresh != null) { if (fresh != null) {
fresh.copyProperties(repository); fresh.copyProperties(repository);
@@ -251,16 +217,7 @@ public class DefaultRepositoryManager extends AbstractRepositoryManager {
} }
} }
//~--- get methods ----------------------------------------------------------
/**
* Method description
*
*
* @param id
*
* @return
*/
@Override @Override
public Repository get(String id) { public Repository get(String id) {
AssertUtil.assertIsNotEmpty(id); AssertUtil.assertIsNotEmpty(id);
@@ -276,21 +233,13 @@ public class DefaultRepositoryManager extends AbstractRepositoryManager {
return repository; return repository;
} }
/**
* Method description
*
*
* @param type
* @param name
*
* @return
*/
@Override @Override
public Repository get(String type, String name) { public Repository get(NamespaceAndName namespaceAndName) {
AssertUtil.assertIsNotEmpty(type); AssertUtil.assertIsNotNull(namespaceAndName);
AssertUtil.assertIsNotEmpty(name); AssertUtil.assertIsNotEmpty(namespaceAndName.getNamespace());
AssertUtil.assertIsNotEmpty(namespaceAndName.getName());
Repository repository = repositoryDAO.get(type, name); Repository repository = repositoryDAO.get(namespaceAndName);
if (repository != null) { if (repository != null) {
RepositoryPermissions.read(repository).check(); RepositoryPermissions.read(repository).check();
@@ -300,14 +249,6 @@ public class DefaultRepositoryManager extends AbstractRepositoryManager {
return repository; return repository;
} }
/**
* Method description
*
*
*
* @param comparator
* @return
*/
@Override @Override
public Collection<Repository> getAll(Comparator<Repository> comparator) { public Collection<Repository> getAll(Comparator<Repository> comparator) {
List<Repository> repositories = Lists.newArrayList(); List<Repository> repositories = Lists.newArrayList();
@@ -330,28 +271,12 @@ public class DefaultRepositoryManager extends AbstractRepositoryManager {
return repositories; return repositories;
} }
/**
* Method description
*
*
* @return
*/
@Override @Override
public Collection<Repository> getAll() { public Collection<Repository> getAll() {
return getAll(null); return getAll(null);
} }
/**
* Method description
*
*
*
* @param comparator
* @param start
* @param limit
*
* @return
*/
@Override @Override
public Collection<Repository> getAll(Comparator<Repository> comparator, public Collection<Repository> getAll(Comparator<Repository> comparator,
int start, int limit) { int start, int limit) {
@@ -369,26 +294,11 @@ public class DefaultRepositoryManager extends AbstractRepositoryManager {
}, start, limit); }, start, limit);
} }
/**
* Method description
*
*
* @param start
* @param limit
*
* @return
*/
@Override @Override
public Collection<Repository> getAll(int start, int limit) { public Collection<Repository> getAll(int start, int limit) {
return getAll(null, start, limit); return getAll(null, start, limit);
} }
/**
* Method description
*
*
* @return
*/
@Override @Override
public Collection<Type> getConfiguredTypes() { public Collection<Type> getConfiguredTypes() {
List<Type> validTypes = Lists.newArrayList(); List<Type> validTypes = Lists.newArrayList();
@@ -402,14 +312,6 @@ public class DefaultRepositoryManager extends AbstractRepositoryManager {
return validTypes; return validTypes;
} }
/**
* Method description
*
*
* @param request
*
* @return
*/
@Override @Override
public Repository getFromRequest(HttpServletRequest request) { public Repository getFromRequest(HttpServletRequest request) {
AssertUtil.assertIsNotNull(request); AssertUtil.assertIsNotNull(request);
@@ -417,17 +319,28 @@ public class DefaultRepositoryManager extends AbstractRepositoryManager {
return getFromUri(HttpUtil.getStrippedURI(request)); return getFromUri(HttpUtil.getStrippedURI(request));
} }
/**
* Method description
*
*
* @param type
* @param uri
*
* @return
*/
@Override @Override
public Repository getFromTypeAndUri(String type, String uri) { public Repository getFromUri(String uri) {
AssertUtil.assertIsNotEmpty(uri);
if (uri.startsWith(HttpUtil.SEPARATOR_PATH)) {
uri = uri.substring(1);
}
int typeSeparator = uri.indexOf(HttpUtil.SEPARATOR_PATH);
Repository repository = null;
if (typeSeparator > 0) {
String type = uri.substring(0, typeSeparator);
uri = uri.substring(typeSeparator + 1);
repository = getFromTypeAndUri(type, uri);
}
return repository;
}
private Repository getFromTypeAndUri(String type, String uri) {
if (Strings.isNullOrEmpty(type)) { if (Strings.isNullOrEmpty(type)) {
throw new ArgumentIsInvalidException("argument type is required"); throw new ArgumentIsInvalidException("argument type is required");
} }
@@ -464,80 +377,21 @@ public class DefaultRepositoryManager extends AbstractRepositoryManager {
return repository; return repository;
} }
/**
* Method description
*
*
* @param uri
*
* @return
*/
@Override
public Repository getFromUri(String uri) {
AssertUtil.assertIsNotEmpty(uri);
if (uri.startsWith(HttpUtil.SEPARATOR_PATH)) {
uri = uri.substring(1);
}
int typeSeperator = uri.indexOf(HttpUtil.SEPARATOR_PATH);
Repository repository = null;
if (typeSeperator > 0) {
String type = uri.substring(0, typeSeperator);
uri = uri.substring(typeSeperator + 1);
repository = getFromTypeAndUri(type, uri);
}
return repository;
}
/**
* Method description
*
*
* @param type
*
* @return
*/
@Override @Override
public RepositoryHandler getHandler(String type) { public RepositoryHandler getHandler(String type) {
return handlerMap.get(type); return handlerMap.get(type);
} }
/**
* Method description
*
*
* @return
*/
@Override @Override
public Long getLastModified() { public Long getLastModified() {
return repositoryDAO.getLastModified(); return repositoryDAO.getLastModified();
} }
/**
* Method description
*
*
* @return
*/
@Override @Override
public Collection<Type> getTypes() { public Collection<Type> getTypes() {
return types; return types;
} }
//~--- methods --------------------------------------------------------------
/**
* Method description
*
*
*
* @param contextProvider
* @param handler
*/
private void addHandler(SCMContextProvider contextProvider, private void addHandler(SCMContextProvider contextProvider,
RepositoryHandler handler) { RepositoryHandler handler) {
AssertUtil.assertIsNotNull(handler); AssertUtil.assertIsNotNull(handler);
@@ -561,19 +415,6 @@ public class DefaultRepositoryManager extends AbstractRepositoryManager {
types.add(type); types.add(type);
} }
//~--- get methods ----------------------------------------------------------
/**
* Method description
*
*
* @param repository
*
* @return
*
*
* @throws RepositoryException
*/
private RepositoryHandler getHandler(Repository repository) private RepositoryHandler getHandler(Repository repository)
throws RepositoryException { throws RepositoryException {
String type = repository.getType(); String type = repository.getType();

View File

@@ -33,7 +33,7 @@ package sonia.scm.repository;
//~--- non-JDK imports -------------------------------------------------------- //~--- non-JDK imports --------------------------------------------------------
import com.google.common.eventbus.Subscribe; import com.github.legman.Subscribe;
import com.google.inject.Inject; import com.google.inject.Inject;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;

View File

@@ -32,14 +32,15 @@
package sonia.scm.repository; package sonia.scm.repository;
import com.google.common.collect.Maps; import com.google.common.collect.Maps;
import java.util.Map; import org.slf4j.Logger;
import java.util.Set; import org.slf4j.LoggerFactory;
import javax.inject.Inject; import sonia.scm.util.HttpUtil;
import org.slf4j.Logger; import sonia.scm.util.Util;
import org.slf4j.LoggerFactory;
import sonia.scm.util.HttpUtil; import javax.inject.Inject;
import sonia.scm.util.Util; import java.util.Map;
import java.util.Set;
/** /**
* RepositoryMatcher is able to check if a repository matches the requested path. * RepositoryMatcher is able to check if a repository matches the requested path.
@@ -83,7 +84,22 @@ public final class RepositoryMatcher {
} }
private boolean isPathMatching(Repository repository, String path) { private boolean isPathMatching(Repository repository, String path) {
return getPathMatcherForType(repository.getType()).isPathMatching(repository, path);
String namespace = extractNamespace(path);
String remainingPath = path.substring(namespace.length() + 1);
return getPathMatcherForType(repository.getType()).isPathMatching(repository, remainingPath);
}
private String extractNamespace(String path) {
if (path.startsWith(HttpUtil.SEPARATOR_PATH)) {
path = path.substring(1);
}
int namespaceSeparator = path.indexOf(HttpUtil.SEPARATOR_PATH);
if (namespaceSeparator > 0) {
return path.substring(0, namespaceSeparator);
}
throw new IllegalArgumentException("no namespace in path " + path);
} }
private RepositoryPathMatcher getPathMatcherForType(String type) { private RepositoryPathMatcher getPathMatcherForType(String type) {

View File

@@ -30,8 +30,8 @@
*/ */
package sonia.scm.security; package sonia.scm.security;
import com.github.legman.Subscribe;
import com.google.common.annotations.VisibleForTesting; import com.google.common.annotations.VisibleForTesting;
import com.google.common.eventbus.Subscribe;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import sonia.scm.EagerSingleton; import sonia.scm.EagerSingleton;

View File

@@ -0,0 +1,24 @@
package sonia.scm.repository;
import com.github.sdorra.shiro.ShiroRule;
import com.github.sdorra.shiro.SubjectAware;
import org.junit.Rule;
import org.junit.Test;
import static org.junit.Assert.*;
@SubjectAware(configuration = "classpath:sonia/scm/shiro-001.ini")
public class DefaultNamespaceStrategyTest {
@Rule
public ShiroRule shiroRule = new ShiroRule();
private DefaultNamespaceStrategy namespaceStrategy = new DefaultNamespaceStrategy();
@Test
@SubjectAware(username = "trillian", password = "secret")
public void testNamespaceStrategy() {
assertEquals("trillian", namespaceStrategy.getNamespace());
}
}

View File

@@ -96,8 +96,6 @@ public class DefaultRepositoryManagerPerfTest {
private final KeyGenerator keyGenerator = new DefaultKeyGenerator(); private final KeyGenerator keyGenerator = new DefaultKeyGenerator();
private final NamespaceStrategy namespaceStrategy = new DefaultNamespaceStrategy();
@Mock @Mock
private RepositoryHandler repositoryHandler; private RepositoryHandler repositoryHandler;
@@ -114,7 +112,7 @@ public class DefaultRepositoryManagerPerfTest {
when(repositoryHandler.getType()).thenReturn(new Type(REPOSITORY_TYPE, REPOSITORY_TYPE)); when(repositoryHandler.getType()).thenReturn(new Type(REPOSITORY_TYPE, REPOSITORY_TYPE));
Set<RepositoryHandler> handlerSet = ImmutableSet.of(repositoryHandler); Set<RepositoryHandler> handlerSet = ImmutableSet.of(repositoryHandler);
RepositoryMatcher repositoryMatcher = new RepositoryMatcher(Collections.<RepositoryPathMatcher>emptySet()); RepositoryMatcher repositoryMatcher = new RepositoryMatcher(Collections.<RepositoryPathMatcher>emptySet());
NamespaceStrategy namespaceStrategy = mock(NamespaceStrategy.class);
repositoryManager = new DefaultRepositoryManager( repositoryManager = new DefaultRepositoryManager(
configuration, configuration,
contextProvider, contextProvider,
@@ -133,9 +131,6 @@ public class DefaultRepositoryManagerPerfTest {
ThreadContext.bind(securityManager); ThreadContext.bind(securityManager);
} }
/**
* Tear down test objects.
*/
@After @After
public void tearDown(){ public void tearDown(){
ThreadContext.unbindSecurityManager(); ThreadContext.unbindSecurityManager();
@@ -188,8 +183,8 @@ private long calculateAverage(List<Long> times) {
when(repositoryDAO.getAll()).thenReturn(repositories.values()); when(repositoryDAO.getAll()).thenReturn(repositories.values());
} }
private Repository createTestRepository(int number){ private Repository createTestRepository(int number) {
Repository repository = new Repository(keyGenerator.createKey(), REPOSITORY_TYPE, "repo-" + number); Repository repository = new Repository(keyGenerator.createKey(), REPOSITORY_TYPE, "namespace", "repo-" + number);
repository.getPermissions().add(new Permission("trillian", PermissionType.READ)); repository.getPermissions().add(new Permission("trillian", PermissionType.READ));
return repository; return repository;
} }

View File

@@ -77,6 +77,7 @@ import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertThat; import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when; import static org.mockito.Mockito.when;
//~--- JDK imports ------------------------------------------------------------ //~--- JDK imports ------------------------------------------------------------
@@ -101,9 +102,8 @@ public class DefaultRepositoryManagerTest extends ManagerTestBase<Repository, Re
private ScmConfiguration configuration; private ScmConfiguration configuration;
/** private String mockedNamespace = "default_namespace";
* Tests {@link RepositoryManager#create(TypedObject)}.
*/
@Test @Test
public void testCreate() throws RepositoryException { public void testCreate() throws RepositoryException {
Repository heartOfGold = createTestRepository(); Repository heartOfGold = createTestRepository();
@@ -113,9 +113,6 @@ public class DefaultRepositoryManagerTest extends ManagerTestBase<Repository, Re
assertRepositoriesEquals(dbRepo, heartOfGold); assertRepositoriesEquals(dbRepo, heartOfGold);
} }
/**
* Tests {@link RepositoryManager#create(TypedObject)} without the required permissions.
*/
@SubjectAware( @SubjectAware(
username = "unpriv" username = "unpriv"
) )
@@ -124,26 +121,17 @@ public class DefaultRepositoryManagerTest extends ManagerTestBase<Repository, Re
createTestRepository(); createTestRepository();
} }
/**
* Tests {@link RepositoryManager#create(TypedObject)} with a already existing repository.
*/
@Test(expected = RepositoryAlreadyExistsException.class) @Test(expected = RepositoryAlreadyExistsException.class)
public void testCreateExisting() throws RepositoryException { public void testCreateExisting() throws RepositoryException {
createTestRepository(); createTestRepository();
createTestRepository(); createTestRepository();
} }
/**
* Tests {@link RepositoryManager#delete(TypedObject)}.
*/
@Test @Test
public void testDelete() throws RepositoryException { public void testDelete() throws RepositoryException {
delete(manager, createTestRepository()); delete(manager, createTestRepository());
} }
/**
* Tests {@link RepositoryManager#delete(TypedObject)} without the required permissions.
*/
@SubjectAware( @SubjectAware(
username = "unpriv" username = "unpriv"
) )
@@ -152,27 +140,17 @@ public class DefaultRepositoryManagerTest extends ManagerTestBase<Repository, Re
delete(manager, createTestRepository()); delete(manager, createTestRepository());
} }
/**
* Tests {@link RepositoryManager#delete(TypedObject)} with a non archived repository and with
* enabled archive mode.
*/
@Test(expected = RepositoryIsNotArchivedException.class) @Test(expected = RepositoryIsNotArchivedException.class)
public void testDeleteNonArchived() throws RepositoryException { public void testDeleteNonArchived() throws RepositoryException {
configuration.setEnableRepositoryArchive(true); configuration.setEnableRepositoryArchive(true);
delete(manager, createTestRepository()); delete(manager, createTestRepository());
} }
/**
* Tests {@link RepositoryManager#delete(TypedObject)} with a non existing repository.
*/
@Test(expected = RepositoryNotFoundException.class) @Test(expected = RepositoryNotFoundException.class)
public void testDeleteNotFound() throws RepositoryException { public void testDeleteNotFound() throws RepositoryException {
manager.delete(createRepositoryWithId()); manager.delete(createRepositoryWithId());
} }
/**
* Tests {@link RepositoryManager#delete(TypedObject)} with enabled archive mode.
*/
@Test @Test
public void testDeleteWithEnabledArchive() public void testDeleteWithEnabledArchive()
throws RepositoryException { throws RepositoryException {
@@ -184,9 +162,6 @@ public class DefaultRepositoryManagerTest extends ManagerTestBase<Repository, Re
delete(drm, repository); delete(drm, repository);
} }
/**
* Tests {@link RepositoryManager#get(java.lang.String)} .
*/
@Test @Test
public void testGet() throws RepositoryException { public void testGet() throws RepositoryException {
Repository heartOfGold = createTestRepository(); Repository heartOfGold = createTestRepository();
@@ -202,9 +177,6 @@ public class DefaultRepositoryManagerTest extends ManagerTestBase<Repository, Re
assertEquals(description, heartOfGold.getDescription()); assertEquals(description, heartOfGold.getDescription());
} }
/**
* Tests {@link RepositoryManager#get(java.lang.String)} without required privileges.
*/
@Test @Test
@SubjectAware( @SubjectAware(
username = "crato" username = "crato"
@@ -217,9 +189,6 @@ public class DefaultRepositoryManagerTest extends ManagerTestBase<Repository, Re
manager.get(heartOfGold.getId()); manager.get(heartOfGold.getId());
} }
/**
* Tests {@link RepositoryManager#getAll()}.
*/
@Test @Test
public void testGetAll() throws RepositoryException { public void testGetAll() throws RepositoryException {
Repository heartOfGold = createTestRepository(); Repository heartOfGold = createTestRepository();
@@ -256,13 +225,10 @@ public class DefaultRepositoryManagerTest extends ManagerTestBase<Repository, Re
heartOfGold.getDescription().equals(heartReference.getDescription())); heartOfGold.getDescription().equals(heartReference.getDescription()));
} }
/**
* Tests {@link RepositoryManager#getAll()} with permission for 2 of 3 repositories.
*/
@Test @Test
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
@SubjectAware(username = "dent") @SubjectAware(username = "dent")
public void testGetAllWithPermissions() throws RepositoryException { public void testGetAllWithPermissionsForTwoOrThreeRepos() throws RepositoryException {
// mock key generator // mock key generator
KeyGenerator keyGenerator = mock(KeyGenerator.class); KeyGenerator keyGenerator = mock(KeyGenerator.class);
Stack<String> keys = new Stack<>(); Stack<String> keys = new Stack<>();
@@ -302,9 +268,6 @@ public class DefaultRepositoryManagerTest extends ManagerTestBase<Repository, Re
); );
} }
/**
* Tests repository manager events.
*/
@Test @Test
public void testEvents() throws RepositoryException { public void testEvents() throws RepositoryException {
RepositoryManager repoManager = createRepositoryManager(false); RepositoryManager repoManager = createRepositoryManager(false);
@@ -336,9 +299,6 @@ public class DefaultRepositoryManagerTest extends ManagerTestBase<Repository, Re
assertSame(HandlerEventType.DELETE, listener.postEvent); assertSame(HandlerEventType.DELETE, listener.postEvent);
} }
/**
* Tests {@link RepositoryManager#modify(TypedObject)}.
*/
@Test @Test
public void testModify() throws RepositoryException { public void testModify() throws RepositoryException {
Repository heartOfGold = createTestRepository(); Repository heartOfGold = createTestRepository();
@@ -352,10 +312,6 @@ public class DefaultRepositoryManagerTest extends ManagerTestBase<Repository, Re
assertEquals(hearReference.getDescription(), "prototype ship"); assertEquals(hearReference.getDescription(), "prototype ship");
} }
/**
* Tests {@link RepositoryManager#modify(TypedObject)} without
* the required permissions.
*/
@Test @Test
@SubjectAware(username = "crato") @SubjectAware(username = "crato")
public void testModifyWithoutRequiredPermissions() throws RepositoryException { public void testModifyWithoutRequiredPermissions() throws RepositoryException {
@@ -367,18 +323,11 @@ public class DefaultRepositoryManagerTest extends ManagerTestBase<Repository, Re
manager.modify(heartOfGold); manager.modify(heartOfGold);
} }
/**
* Tests {@link RepositoryManager#modify(TypedObject)} with a non
* existing repository.
*/
@Test(expected = RepositoryNotFoundException.class) @Test(expected = RepositoryNotFoundException.class)
public void testModifyNotFound() throws RepositoryException { public void testModifyNotFound() throws RepositoryException {
manager.modify(createRepositoryWithId()); manager.modify(createRepositoryWithId());
} }
/**
* Tests {@link RepositoryManager#refresh(ModelObject)}.
*/
@Test @Test
public void testRefresh() throws RepositoryException { public void testRefresh() throws RepositoryException {
Repository heartOfGold = createTestRepository(); Repository heartOfGold = createTestRepository();
@@ -389,10 +338,6 @@ public class DefaultRepositoryManagerTest extends ManagerTestBase<Repository, Re
assertEquals(description, heartOfGold.getDescription()); assertEquals(description, heartOfGold.getDescription());
} }
/**
* Tests {@link RepositoryManager#refresh(ModelObject)} without
* required permissions.
*/
@Test @Test
@SubjectAware(username = "crato") @SubjectAware(username = "crato")
public void testRefreshWithoutRequiredPermissions() throws RepositoryException { public void testRefreshWithoutRequiredPermissions() throws RepositoryException {
@@ -404,18 +349,11 @@ public class DefaultRepositoryManagerTest extends ManagerTestBase<Repository, Re
manager.refresh(heartOfGold); manager.refresh(heartOfGold);
} }
/**
* Tests {@link RepositoryManager#refresh(ModelObject)} with a non existing
* repository.
*/
@Test(expected = RepositoryNotFoundException.class) @Test(expected = RepositoryNotFoundException.class)
public void testRefreshNotFound() throws RepositoryException { public void testRefreshNotFound() throws RepositoryException {
manager.refresh(createRepositoryWithId()); manager.refresh(createRepositoryWithId());
} }
/**
* Tests repository hooks.
*/
@Test @Test
public void testRepositoryHook() throws RepositoryException { public void testRepositoryHook() throws RepositoryException {
CountingReceiveHook hook = new CountingReceiveHook(); CountingReceiveHook hook = new CountingReceiveHook();
@@ -436,25 +374,96 @@ public class DefaultRepositoryManagerTest extends ManagerTestBase<Repository, Re
assertEquals(2, hook.eventsReceived); assertEquals(2, hook.eventsReceived);
} }
/**
* Tests {@link RepositoryManager#getFromTypeAndUri(String, String)}.
*/
@Test @Test
public void getRepositoryFromRequestUriTest() throws RepositoryException { public void testNamespaceSet() throws Exception {
RepositoryManager repoManager = createRepositoryManager(false);
Repository repository = spy(createTestRepository());
repository.setName("Testrepo");
((DefaultRepositoryManager) repoManager).create(repository);
assertEquals("default_namespace", repository.getNamespace());
}
@Test
public void getRepositoryFromRequestUri_withoutLeadingSlash() throws RepositoryException {
RepositoryManager m = createManager(); RepositoryManager m = createManager();
m.init(contextProvider); m.init(contextProvider);
createRepository(m, new Repository("1", "hg", "scm")); createUriTestRepositories(m);
createRepository(m, new Repository("2", "hg", "scm-test"));
createRepository(m, new Repository("3", "git", "project1/test-1"));
createRepository(m, new Repository("4", "git", "project1/test-2"));
assertEquals("scm", m.getFromUri("hg/scm").getName()); assertEquals("scm-test", m.getFromUri("hg/namespace/scm-test").getName());
assertEquals("scm-test", m.getFromUri("hg/scm-test").getName()); assertEquals("namespace", m.getFromUri("hg/namespace/scm-test").getNamespace());
assertEquals("scm-test", m.getFromUri("/hg/scm-test").getName()); }
assertEquals("project1/test-1", m.getFromUri("/git/project1/test-1").getName());
assertEquals("project1/test-1", m.getFromUri("/git/project1/test-1/ka/some/path").getName()); @Test
assertNull(m.getFromUri("/git/project1/test-3/ka/some/path")); public void getRepositoryFromRequestUri_withLeadingSlash() throws RepositoryException {
RepositoryManager m = createManager();
m.init(contextProvider);
createUriTestRepositories(m);
assertEquals("scm-test", m.getFromUri("/hg/namespace/scm-test").getName());
assertEquals("namespace", m.getFromUri("/hg/namespace/scm-test").getNamespace());
}
@Test
public void getRepositoryFromRequestUri_withPartialName() throws RepositoryException {
RepositoryManager m = createManager();
m.init(contextProvider);
createUriTestRepositories(m);
assertEquals("scm", m.getFromUri("hg/namespace/scm").getName());
assertEquals("namespace", m.getFromUri("hg/namespace/scm").getNamespace());
}
@Test
public void getRepositoryFromRequestUri_withTrailingFilePath() throws RepositoryException {
RepositoryManager m = createManager();
m.init(contextProvider);
createUriTestRepositories(m);
assertEquals("test-1", m.getFromUri("/git/namespace/test-1/ka/some/path").getName());
}
@Test
public void getRepositoryFromRequestUri_forNotExistingRepositoryName() throws RepositoryException {
RepositoryManager m = createManager();
m.init(contextProvider);
createUriTestRepositories(m);
assertNull(m.getFromUri("/git/namespace/test-3/ka/some/path"));
}
@Test
public void getRepositoryFromRequestUri_forWrongNamespace() throws RepositoryException {
RepositoryManager m = createManager();
m.init(contextProvider);
createUriTestRepositories(m);
assertNull(m.getFromUri("/git/other/other/test-2"));
}
@Test
public void shouldSetNamespace() throws RepositoryException {
Repository repository = new Repository(null, "hg", null, "scm");
manager.create(repository);
assertNotNull(repository.getId());
assertNotNull(repository.getNamespace());
}
private void createUriTestRepositories(RepositoryManager m) throws RepositoryException {
mockedNamespace = "namespace";
createRepository(m, new Repository("1", "hg", "namespace", "scm"));
createRepository(m, new Repository("2", "hg", "namespace", "scm-test"));
createRepository(m, new Repository("3", "git", "namespace", "test-1"));
createRepository(m, new Repository("4", "git", "namespace", "test-2"));
mockedNamespace = "other";
createRepository(m, new Repository("1", "hg", "other", "scm"));
createRepository(m, new Repository("2", "hg", "other", "scm-test"));
} }
//~--- methods -------------------------------------------------------------- //~--- methods --------------------------------------------------------------
@@ -489,10 +498,11 @@ public class DefaultRepositoryManagerTest extends ManagerTestBase<Repository, Re
this.configuration = new ScmConfiguration(); this.configuration = new ScmConfiguration();
NamespaceStrategy namespaceStrategy = new DefaultNamespaceStrategy();
configuration.setEnableRepositoryArchive(archiveEnabled); configuration.setEnableRepositoryArchive(archiveEnabled);
NamespaceStrategy namespaceStrategy = mock(NamespaceStrategy.class);
when(namespaceStrategy.getNamespace()).thenAnswer(invocation -> mockedNamespace);
return new DefaultRepositoryManager(configuration, contextProvider, return new DefaultRepositoryManager(configuration, contextProvider,
keyGenerator, repositoryDAO, handlerSet, createRepositoryMatcher(), namespaceStrategy); keyGenerator, repositoryDAO, handlerSet, createRepositoryMatcher(), namespaceStrategy);
} }

View File

@@ -31,10 +31,13 @@
package sonia.scm.repository; package sonia.scm.repository;
import com.google.common.collect.Sets; import com.google.common.collect.Sets;
import java.util.Set;
import org.junit.Test;
import static org.junit.Assert.*;
import org.junit.Before; import org.junit.Before;
import org.junit.Test;
import java.util.Set;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
/** /**
* Unit tests for {@link RepositoryMatcher}. * Unit tests for {@link RepositoryMatcher}.
@@ -54,11 +57,11 @@ public class RepositoryMatcherTest {
@Test @Test
public void testMatches() { public void testMatches() {
assertFalse(matcher.matches(repository("hg", "scm"), "hg", "scm-test/ka")); assertFalse(matcher.matches(repository("hg", "scm"), "hg", "namespace/scm-test/ka"));
assertFalse(matcher.matches(repository("git", "scm-test"), "hg", "scm-test")); assertFalse(matcher.matches(repository("git", "scm-test"), "hg", "namespace/scm-test"));
assertTrue(matcher.matches(repository("hg", "scm-test"), "hg", "scm-test/ka")); assertTrue(matcher.matches(repository("hg", "scm-test"), "hg", "namespace/scm-test/ka"));
assertTrue(matcher.matches(repository("hg", "scm-test"), "hg", "scm-test")); assertTrue(matcher.matches(repository("hg", "scm-test"), "hg", "namespace/scm-test"));
} }
@Test @Test
@@ -68,7 +71,7 @@ public class RepositoryMatcherTest {
} }
private Repository repository(String type, String name) { private Repository repository(String type, String name) {
return new Repository(type + "-" + name, type, name); return new Repository(type + "-" + name, type, "namespace", name);
} }
private static class AbcRepositoryPathMatcher implements RepositoryPathMatcher { private static class AbcRepositoryPathMatcher implements RepositoryPathMatcher {