This commit is contained in:
Mohamed Karray
2018-11-15 11:28:33 +01:00
381 changed files with 12331 additions and 11177 deletions

View File

@@ -1,348 +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.api.rest.resources;
//~--- non-JDK imports --------------------------------------------------------
import com.google.inject.Inject;
import com.google.inject.Singleton;
import sonia.scm.SCMContext;
import sonia.scm.installer.HgInstallerFactory;
import sonia.scm.installer.HgPackage;
import sonia.scm.installer.HgPackageReader;
import sonia.scm.installer.HgPackages;
import sonia.scm.net.ahc.AdvancedHttpClient;
import sonia.scm.repository.HgConfig;
import sonia.scm.repository.HgRepositoryHandler;
//~--- JDK imports ------------------------------------------------------------
import java.io.IOException;
import java.util.List;
import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.UriInfo;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
/**
*
* @author Sebastian Sdorra
*/
@Singleton
@Path("config/repositories/hg")
public class HgConfigResource
{
/**
* Constructs ...
*
*
*
*
* @param client
* @param handler
* @param pkgReader
*/
@Inject
public HgConfigResource(AdvancedHttpClient client,
HgRepositoryHandler handler, HgPackageReader pkgReader)
{
this.client = client;
this.handler = handler;
this.pkgReader = pkgReader;
}
//~--- methods --------------------------------------------------------------
/**
* Method description
*
*
* @param uriInfo
*
* @return
*/
@POST
@Path("auto-configuration")
@Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
public HgConfig autoConfiguration(@Context UriInfo uriInfo)
{
return autoConfiguration(uriInfo, null);
}
/**
* Method description
*
*
* @param uriInfo
* @param config
*
* @return
*/
@POST
@Path("auto-configuration")
@Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
@Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
public HgConfig autoConfiguration(@Context UriInfo uriInfo, HgConfig config)
{
if (config == null)
{
config = new HgConfig();
}
handler.doAutoConfiguration(config);
return handler.getConfig();
}
/**
* Method description
*
*
*
* @param id
* @return
*/
@POST
@Path("packages/{pkgId}")
public Response installPackage(@PathParam("pkgId") String id)
{
Response response = null;
HgPackage pkg = pkgReader.getPackage(id);
if (pkg != null)
{
if (HgInstallerFactory.createInstaller().installPackage(client, handler,
SCMContext.getContext().getBaseDirectory(), pkg))
{
response = Response.noContent().build();
}
else
{
response =
Response.status(Response.Status.INTERNAL_SERVER_ERROR).build();
}
}
else
{
response = Response.status(Response.Status.NOT_FOUND).build();
}
return response;
}
//~--- get methods ----------------------------------------------------------
/**
* Method description
*
*
* @return
*/
@GET
@Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
public HgConfig getConfig()
{
HgConfig config = handler.getConfig();
if (config == null)
{
config = new HgConfig();
}
return config;
}
/**
* Method description
*
*
* @return
*/
@GET
@Path("installations/hg")
@Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
public InstallationsResponse getHgInstallations()
{
List<String> installations =
HgInstallerFactory.createInstaller().getHgInstallations();
return new InstallationsResponse(installations);
}
/**
* Method description
*
*
* @return
*/
@GET
@Path("packages")
@Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
public HgPackages getPackages()
{
return pkgReader.getPackages();
}
/**
* Method description
*
*
* @return
*/
@GET
@Path("installations/python")
@Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
public InstallationsResponse getPythonInstallations()
{
List<String> installations =
HgInstallerFactory.createInstaller().getPythonInstallations();
return new InstallationsResponse(installations);
}
//~--- set methods ----------------------------------------------------------
/**
* Method description
*
*
* @param uriInfo
* @param config
*
* @return
*
* @throws IOException
*/
@POST
@Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
public Response setConfig(@Context UriInfo uriInfo, HgConfig config)
throws IOException
{
handler.setConfig(config);
handler.storeConfig();
return Response.created(uriInfo.getRequestUri()).build();
}
//~--- inner classes --------------------------------------------------------
/**
* Class description
*
*
* @version Enter version here..., 11/04/25
* @author Enter your name here...
*/
@XmlAccessorType(XmlAccessType.FIELD)
@XmlRootElement(name = "installations")
public static class InstallationsResponse
{
/**
* Constructs ...
*
*/
public InstallationsResponse() {}
/**
* Constructs ...
*
*
* @param paths
*/
public InstallationsResponse(List<String> paths)
{
this.paths = paths;
}
//~--- get methods --------------------------------------------------------
/**
* Method description
*
*
* @return
*/
public List<String> getPaths()
{
return paths;
}
//~--- set methods --------------------------------------------------------
/**
* Method description
*
*
* @param paths
*/
public void setPaths(List<String> paths)
{
this.paths = paths;
}
//~--- fields -------------------------------------------------------------
/** Field description */
@XmlElement(name = "path")
private List<String> paths;
}
//~--- fields ---------------------------------------------------------------
/** Field description */
private AdvancedHttpClient client;
/** Field description */
private HgRepositoryHandler handler;
/** Field description */
private HgPackageReader pkgReader;
}

View File

@@ -272,7 +272,7 @@ public class AbstractHgHandler
} catch (JAXBException ex) {
logger.error("could not parse result", ex);
throw new InternalRepositoryException("could not parse result", ex);
throw new InternalRepositoryException(repository, "could not parse result", ex);
}
}

View File

@@ -36,6 +36,9 @@ package sonia.scm.repository.spi;
import com.aragost.javahg.commands.ExecutionException;
import com.google.common.io.ByteStreams;
import com.google.common.io.Closeables;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import sonia.scm.ContextEntry;
import sonia.scm.repository.InternalRepositoryException;
import sonia.scm.repository.Repository;
import sonia.scm.web.HgUtil;
@@ -46,6 +49,8 @@ import java.io.OutputStream;
public class HgCatCommand extends AbstractCommand implements CatCommand {
private static final Logger log = LoggerFactory.getLogger(HgCatCommand.class);
HgCatCommand(HgCommandContext context, Repository repository) {
super(context, repository);
}
@@ -70,7 +75,8 @@ public class HgCatCommand extends AbstractCommand implements CatCommand {
try {
return cmd.execute(request.getPath());
} catch (ExecutionException e) {
throw new InternalRepositoryException(e);
log.error("could not execute cat command", e);
throw new InternalRepositoryException(ContextEntry.ContextBuilder.entity(getRepository()), "could not execute cat command", e);
}
}
}

View File

@@ -103,7 +103,7 @@ public class HgIncomingCommand extends AbstractCommand
}
else
{
throw new InternalRepositoryException("could not execute incoming command", ex);
throw new InternalRepositoryException(getRepository(), "could not execute incoming command", ex);
}
}

View File

@@ -103,7 +103,7 @@ public class HgOutgoingCommand extends AbstractCommand
}
else
{
throw new InternalRepositoryException("could not execute outgoing command", ex);
throw new InternalRepositoryException(getRepository(), "could not execute outgoing command", ex);
}
}

View File

@@ -97,7 +97,7 @@ public class HgPullCommand extends AbstractHgPushOrPullCommand
}
catch (ExecutionException ex)
{
throw new InternalRepositoryException("could not execute push command", ex);
throw new InternalRepositoryException(getRepository(), "could not execute push command", ex);
}
return new PullResponse(result.size());

View File

@@ -97,7 +97,7 @@ public class HgPushCommand extends AbstractHgPushOrPullCommand
}
catch (ExecutionException ex)
{
throw new InternalRepositoryException("could not execute push command", ex);
throw new InternalRepositoryException(getRepository(), "could not execute push command", ex);
}
return new PushResponse(result.size());

View File

@@ -44,11 +44,11 @@ import org.apache.shiro.SecurityUtils;
import org.apache.shiro.subject.Subject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import sonia.scm.NotFoundException;
import sonia.scm.repository.HgContext;
import sonia.scm.repository.HgHookManager;
import sonia.scm.repository.HgRepositoryHandler;
import sonia.scm.repository.RepositoryHookType;
import sonia.scm.repository.RepositoryNotFoundException;
import sonia.scm.repository.RepositoryUtil;
import sonia.scm.repository.api.HgHookMessage;
import sonia.scm.repository.api.HgHookMessage.Severity;
@@ -275,17 +275,11 @@ public class HgHookCallbackServlet extends HttpServlet
printMessages(response, context);
}
catch (RepositoryNotFoundException ex)
catch (NotFoundException ex)
{
if (logger.isErrorEnabled())
{
logger.error("could not find repository with id {}", id);
logger.error(ex.getMessage());
if (logger.isTraceEnabled())
{
logger.trace("repository not found", ex);
}
}
logger.trace("repository not found", ex);
response.sendError(HttpServletResponse.SC_NOT_FOUND);
}

View File

@@ -0,0 +1,113 @@
//@flow
import React from "react";
import type { Links } from "@scm-manager/ui-types";
import { translate } from "react-i18next";
import { InputField, Checkbox } from "@scm-manager/ui-components";
type Configuration = {
"hgBinary": string,
"pythonBinary": string,
"pythonPath"?: string,
"repositoryDirectory": string,
"encoding": string,
"useOptimizedBytecode": boolean,
"showRevisionInId": boolean,
"disabled": boolean,
"_links": Links
};
type Props = {
initialConfiguration: Configuration,
readOnly: boolean,
onConfigurationChange: (Configuration, boolean) => void,
// context props
t: (string) => string
}
type State = Configuration & {
validationErrors: string[]
};
class HgConfigurationForm extends React.Component<Props, State> {
constructor(props: Props) {
super(props);
this.state = { ...props.initialConfiguration, validationErrors: [] };
}
updateValidationStatus = () => {
const requiredFields = [
"hgBinary", "pythonBinary", "repositoryDirectory", "encoding"
];
const validationErrors = [];
for (let field of requiredFields) {
if (!this.state[field]) {
validationErrors.push( field );
}
}
this.setState({
validationErrors
});
return validationErrors.length === 0;
};
hasValidationError = (name: string) => {
return this.state.validationErrors.indexOf(name) >= 0;
};
handleChange = (value: any, name: string) => {
this.setState({
[name]: value
}, () => this.props.onConfigurationChange(this.state, this.updateValidationStatus()));
};
inputField = (name: string) => {
const { readOnly, t } = this.props;
return <InputField
name={ name }
label={t("scm-hg-plugin.config." + name)}
helpText={t("scm-hg-plugin.config." + name + "HelpText")}
value={this.state[name]}
onChange={this.handleChange}
validationError={this.hasValidationError(name)}
errorMessage={t("scm-hg-plugin.config.required")}
disabled={readOnly}
/>;
};
checkbox = (name: string) => {
const { readOnly, t } = this.props;
return <Checkbox
name={ name }
label={t("scm-hg-plugin.config." + name)}
helpText={t("scm-hg-plugin.config." + name + "HelpText")}
checked={this.state[name]}
onChange={this.handleChange}
disabled={readOnly}
/>;
};
render() {
return (
<>
{this.inputField("hgBinary")}
{this.inputField("pythonBinary")}
{this.inputField("pythonPath")}
{this.inputField("repositoryDirectory")}
{this.inputField("encoding")}
{this.checkbox("useOptimizedBytecode")}
{this.checkbox("showRevisionInId")}
{this.checkbox("disabled")}
</>
);
}
}
export default translate("plugins")(HgConfigurationForm);

View File

@@ -0,0 +1,28 @@
//@flow
import React from "react";
import { Title, GlobalConfiguration } from "@scm-manager/ui-components";
import { translate } from "react-i18next";
import HgConfigurationForm from "./HgConfigurationForm";
type Props = {
link: string,
// context props
t: (string) => string
}
class HgGlobalConfiguration extends React.Component<Props> {
render() {
const { link, t } = this.props;
return (
<div>
<Title title={t("scm-hg-plugin.config.title")}/>
<GlobalConfiguration link={link} render={props => <HgConfigurationForm {...props} />}/>
</div>
);
}
}
export default translate("plugins")(HgGlobalConfiguration);

View File

@@ -2,6 +2,8 @@
import { binder } from "@scm-manager/ui-extensions";
import ProtocolInformation from "./ProtocolInformation";
import HgAvatar from "./HgAvatar";
import { ConfigurationBinder as cfgBinder } from "@scm-manager/ui-components";
import HgGlobalConfiguration from "./HgGlobalConfiguration";
const hgPredicate = (props: Object) => {
return props.repository && props.repository.type === "hg";
@@ -9,3 +11,7 @@ const hgPredicate = (props: Object) => {
binder.bind("repos.repository-details.information", ProtocolInformation, hgPredicate);
binder.bind("repos.repository-avatar", HgAvatar, hgPredicate);
// bind global configuration
cfgBinder.bindGlobal("/hg", "scm-hg-plugin.config.link", "hgConfig", HgGlobalConfiguration);

View File

@@ -4,6 +4,27 @@
"clone" : "Clone the repository",
"create" : "Create a new repository",
"replace" : "Push an existing repository"
},
"config": {
"link": "Mercurial",
"title": "Mercurial Configuration",
"hgBinary": "HG Binary",
"hgBinaryHelpText": "Location of Mercurial binary.",
"pythonBinary": "Python Binary",
"pythonBinaryHelpText": "Location of Python binary.",
"pythonPath": "Python Module Search Path",
"pythonPathHelpText": "Python Module Search Path (PYTHONPATH).",
"repositoryDirectory": "Repository directory",
"repositoryDirectoryHelpText": "Location of Mercurial repositories.",
"encoding": "Encoding",
"encodingHelpText": "Repository Encoding.",
"useOptimizedBytecode": "Optimized Bytecode (.pyo)",
"useOptimizedBytecodeHelpText": "Use the Python '-O' switch.",
"showRevisionInId": "Show Revision",
"showRevisionInIdHelpText": "Show revision as part of the node id.",
"disabled": "Disabled",
"disabledHelpText": "Enable or disable the Mercurial plugin.",
"required": "This configuration value is required"
}
}
}

View File

@@ -39,7 +39,6 @@ import org.junit.Test;
import sonia.scm.repository.Changeset;
import sonia.scm.repository.ChangesetPagingResult;
import sonia.scm.repository.Modifications;
import sonia.scm.repository.RevisionNotFoundException;
import java.io.IOException;
@@ -151,7 +150,7 @@ public class HgLogCommandTest extends AbstractHgCommandTestBase
}
@Test
public void testGetCommit() throws IOException, RevisionNotFoundException {
public void testGetCommit() throws IOException {
HgLogCommand command = createComamnd();
String revision = "a9bacaf1b7fa0cebfca71fed4e59ed69a6319427";
Changeset c =