move core plugins back to main repository, because of a broken release management

This commit is contained in:
Sebastian Sdorra
2011-07-01 18:43:26 +02:00
parent 9aaf71f5ca
commit fa1d433a36
58 changed files with 9240 additions and 0 deletions

View File

@@ -0,0 +1,351 @@
/**
* 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.cache.CacheManager;
import sonia.scm.installer.HgInstallerFactory;
import sonia.scm.installer.HgPackage;
import sonia.scm.installer.HgPackageReader;
import sonia.scm.installer.HgPackages;
import sonia.scm.net.HttpClient;
import sonia.scm.repository.HgConfig;
import sonia.scm.repository.HgRepositoryHandler;
import sonia.scm.web.HgWebConfigWriter;
//~--- 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 cacheManager
*/
@Inject
public HgConfigResource(HttpClient client, HgRepositoryHandler handler,
CacheManager cacheManager)
{
this.client = client;
this.handler = handler;
this.pkgReader = new HgPackageReader(cacheManager);
}
//~--- methods --------------------------------------------------------------
/**
* Method description
*
*
* @param uriInfo
*
* @return
*/
@POST
@Path("auto-configuration")
@Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
public HgConfig autoConfiguration(@Context UriInfo uriInfo)
{
return autoConfiguration(uriInfo, null);
}
/**
* Method description
*
*
* @param uriInfo
* @param config
*
* @return
*/
@POST
@Path("auto-configuration")
@Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
@Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
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_XML, MediaType.APPLICATION_JSON })
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_XML, MediaType.APPLICATION_JSON })
public InstallationsResponse getHgInstallations()
{
List<String> installations =
HgInstallerFactory.createInstaller().getHgInstallations();
return new InstallationsResponse(installations);
}
/**
* Method description
*
*
* @return
*/
@GET
@Path("packages")
@Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
public HgPackages getPackages()
{
return pkgReader.getPackages();
}
/**
* Method description
*
*
* @return
*/
@GET
@Path("installations/python")
@Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
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_XML, MediaType.APPLICATION_JSON })
public Response setConfig(@Context UriInfo uriInfo, HgConfig config)
throws IOException
{
handler.setConfig(config);
handler.storeConfig();
new HgWebConfigWriter(config).write();
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 HttpClient client;
/** Field description */
private HgRepositoryHandler handler;
/** Field description */
private HgPackageReader pkgReader;
}

View File

@@ -0,0 +1,102 @@
/**
* 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.installer;
//~--- non-JDK imports --------------------------------------------------------
import sonia.scm.net.HttpClient;
import sonia.scm.repository.HgConfig;
import sonia.scm.repository.HgRepositoryHandler;
import sonia.scm.util.IOUtil;
//~--- JDK imports ------------------------------------------------------------
import java.io.File;
import java.io.IOException;
/**
*
* @author Sebastian Sdorra
*/
public abstract class AbstractHgInstaller implements HgInstaller
{
/** Field description */
public static final String DIRECTORY_REPOSITORY = "repositories";
//~--- methods --------------------------------------------------------------
/**
* Method description
*
*
*
* @param baseDirectory
* @param config
*
* @throws IOException
*/
@Override
public void install(File baseDirectory, HgConfig config) throws IOException
{
File repoDirectory = new File(
baseDirectory,
DIRECTORY_REPOSITORY.concat(File.separator).concat(
HgRepositoryHandler.TYPE_NAME));
IOUtil.mkdirs(repoDirectory);
config.setRepositoryDirectory(repoDirectory);
}
/**
* Method description
*
*
*
*
* @param client
* @param handler
* @param baseDirectory
* @param pkg
*
* @return
*/
@Override
public boolean installPackage(HttpClient client, HgRepositoryHandler handler,
File baseDirectory, HgPackage pkg)
{
return new HgPackageInstaller(client, handler, baseDirectory,
pkg).install();
}
}

View File

@@ -0,0 +1,113 @@
/**
* 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.installer;
//~--- non-JDK imports --------------------------------------------------------
import sonia.scm.net.HttpClient;
import sonia.scm.repository.HgConfig;
import sonia.scm.repository.HgRepositoryHandler;
//~--- JDK imports ------------------------------------------------------------
import java.io.File;
import java.io.IOException;
import java.util.List;
/**
*
* @author Sebastian Sdorra
*/
public interface HgInstaller
{
/**
* Method description
*
*
*
* @param baseDirectory
* @param config
*
* @throws IOException
*/
public void install(File baseDirectory, HgConfig config) throws IOException;
/**
* Method description
*
*
*
*
* @param client
* @param handler
* @param baseDirectory
* @param pkg
*
* @return
*/
public boolean installPackage(HttpClient client, HgRepositoryHandler handler,
File baseDirectory, HgPackage pkg);
/**
* Method description
*
*
*
* @param baseDirectory
* @param config
*
* @throws IOException
*/
public void update(File baseDirectory, HgConfig config) throws IOException;
//~--- get methods ----------------------------------------------------------
/**
* Method description
*
*
* @return
*/
public List<String> getHgInstallations();
/**
* Method description
*
*
* @return
*/
public List<String> getPythonInstallations();
}

View File

@@ -0,0 +1,68 @@
/**
* 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.installer;
//~--- non-JDK imports --------------------------------------------------------
import sonia.scm.util.SystemUtil;
/**
*
* @author Sebastian Sdorra
*/
public class HgInstallerFactory
{
/**
* Method description
*
*
* @return
*/
public static HgInstaller createInstaller()
{
HgInstaller installer = null;
if (SystemUtil.isWindows())
{
installer = new WindowsHgInstaller();
}
else
{
installer = new UnixHgInstaller();
}
return installer;
}
}

View File

@@ -0,0 +1,262 @@
/**
* 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.installer;
//~--- non-JDK imports --------------------------------------------------------
import sonia.scm.repository.HgConfig;
//~--- JDK imports ------------------------------------------------------------
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
/**
*
* @author Sebastian Sdorra
*/
@XmlRootElement(name = "package")
@XmlAccessorType(XmlAccessType.FIELD)
public class HgPackage
{
/**
* Method description
*
*
* @return
*/
public String getArch()
{
return arch;
}
/**
* Method description
*
*
* @return
*/
public HgConfig getHgConfigTemplate()
{
return hgConfigTemplate;
}
/**
* Method description
*
*
* @return
*/
public String getHgVersion()
{
return hgVersion;
}
/**
* Method description
*
*
* @return
*/
public String getId()
{
return id;
}
/**
* Method description
*
*
* @return
*/
public String getPlatform()
{
return platform;
}
/**
* Method description
*
*
* @return
*/
public String getPythonVersion()
{
return pythonVersion;
}
/**
* Method description
*
*
* @return
*/
public long getSize()
{
return size;
}
/**
* Method description
*
*
* @return
*/
public String getUrl()
{
return url;
}
//~--- set methods ----------------------------------------------------------
/**
* Method description
*
*
* @param arch
*/
public void setArch(String arch)
{
this.arch = arch;
}
/**
* Method description
*
*
* @param hgConfigTemplate
*/
public void setHgConfigTemplate(HgConfig hgConfigTemplate)
{
this.hgConfigTemplate = hgConfigTemplate;
}
/**
* Method description
*
*
* @param hgVersion
*/
public void setHgVersion(String hgVersion)
{
this.hgVersion = hgVersion;
}
/**
* Method description
*
*
* @param id
*/
public void setId(String id)
{
this.id = id;
}
/**
* Method description
*
*
* @param platform
*/
public void setPlatform(String platform)
{
this.platform = platform;
}
/**
* Method description
*
*
* @param pythonVersion
*/
public void setPythonVersion(String pythonVersion)
{
this.pythonVersion = pythonVersion;
}
/**
* Method description
*
*
* @param size
*/
public void setSize(long size)
{
this.size = size;
}
/**
* Method description
*
*
* @param url
*/
public void setUrl(String url)
{
this.url = url;
}
//~--- fields ---------------------------------------------------------------
/** Field description */
private String arch;
/** Field description */
@XmlElement(name = "hg-config-template")
private HgConfig hgConfigTemplate;
/** Field description */
@XmlElement(name = "hg-version")
private String hgVersion;
/** Field description */
private String id;
/** Field description */
private String platform;
/** Field description */
@XmlElement(name = "python-version")
private String pythonVersion;
/** Field description */
private long size;
/** Field description */
private String url;
}

View File

@@ -0,0 +1,269 @@
/**
* 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.installer;
//~--- non-JDK imports --------------------------------------------------------
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import sonia.scm.io.ZipUnArchiver;
import sonia.scm.net.HttpClient;
import sonia.scm.repository.HgConfig;
import sonia.scm.repository.HgRepositoryHandler;
import sonia.scm.util.IOUtil;
//~--- JDK imports ------------------------------------------------------------
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.text.MessageFormat;
/**
*
* @author Sebastian Sdorra
*/
public class HgPackageInstaller implements Runnable
{
/** the logger for HgPackageInstaller */
private static final Logger logger =
LoggerFactory.getLogger(HgPackageInstaller.class);
//~--- constructors ---------------------------------------------------------
/**
* Constructs ...
*
*
*
*
* @param client
* @param handler
* @param baseDirectory
* @param pkg
*/
public HgPackageInstaller(HttpClient client, HgRepositoryHandler handler,
File baseDirectory, HgPackage pkg)
{
this.client = client;
this.handler = handler;
this.baseDirectory = baseDirectory;
this.pkg = pkg;
}
//~--- methods --------------------------------------------------------------
/**
* Method description
*
*
* @return
*/
public boolean install()
{
boolean success = false;
File downloadedFile = downloadFile();
if ((downloadedFile != null) && downloadedFile.exists())
{
File directory = extractPackage(downloadedFile);
if ((directory != null) && directory.exists())
{
updateConfig(directory);
success = true;
}
}
return success;
}
/**
* Method description
*
*/
@Override
public void run()
{
if (!install())
{
logger.error("installation of pkg {} failed", pkg.getId());
}
else if (logger.isInfoEnabled())
{
logger.info("successfully installed pkg {}", pkg.getId());
}
}
/**
* Method description
*
*
* @return
*/
private File downloadFile()
{
File file = null;
InputStream input = null;
OutputStream output = null;
try
{
file = File.createTempFile("scm-hg-", ".pkg");
if (logger.isDebugEnabled())
{
logger.debug("download package to {}", file.getAbsolutePath());
}
// TODO error handling
input = client.get(pkg.getUrl()).getContent();
output = new FileOutputStream(file);
IOUtil.copy(input, output);
}
catch (IOException ex)
{
logger.error("could not downlaod file ".concat(pkg.getUrl()), ex);
}
finally
{
IOUtil.close(input);
IOUtil.close(output);
}
return file;
}
/**
* Method description
*
*
* @param file
*
* @return
*/
private File extractPackage(File file)
{
File directory = new File(baseDirectory,
"pkg".concat(File.separator).concat(pkg.getId()));
IOUtil.mkdirs(directory);
try
{
IOUtil.extract(file, directory, ZipUnArchiver.EXTENSION);
}
catch (IOException ex)
{
directory = null;
logger.error("could not extract pacakge ".concat(pkg.getId()), ex);
}
finally
{
// delete temp file
try
{
IOUtil.delete(file, true);
}
catch (IOException ex)
{
logger.error(ex.getMessage(), ex);
}
}
return directory;
}
/**
* Method description
*
*
* @param directory
*/
private void updateConfig(File directory)
{
String path = directory.getAbsolutePath();
HgConfig template = pkg.getHgConfigTemplate();
HgConfig config = handler.getConfig();
config.setHgBinary(getTemplateValue(template.getHgBinary(), path));
config.setPythonBinary(getTemplateValue(template.getPythonBinary(), path));
config.setPythonPath(getTemplateValue(template.getPythonPath(), path));
config.setUseOptimizedBytecode(template.isUseOptimizedBytecode());
handler.storeConfig();
}
//~--- get methods ----------------------------------------------------------
/**
* Method description
*
*
* @param template
* @param path
*
* @return
*/
private String getTemplateValue(String template, String path)
{
String result = null;
if (template != null)
{
result = MessageFormat.format(template, path);
}
return result;
}
//~--- fields ---------------------------------------------------------------
/** Field description */
private File baseDirectory;
/** Field description */
private HttpClient client;
/** Field description */
private HgRepositoryHandler handler;
/** Field description */
private HgPackage pkg;
}

View File

@@ -0,0 +1,254 @@
/**
* 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.installer;
//~--- non-JDK imports --------------------------------------------------------
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import sonia.scm.PlatformType;
import sonia.scm.cache.Cache;
import sonia.scm.cache.CacheManager;
import sonia.scm.util.IOUtil;
import sonia.scm.util.SystemUtil;
import sonia.scm.util.Util;
//~--- JDK imports ------------------------------------------------------------
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.zip.GZIPInputStream;
import javax.xml.bind.JAXB;
/**
*
* @author Sebastian Sdorra
*/
public class HgPackageReader
{
/** Field description */
public static final String CACHENAME = "sonia.scm.hg.packages";
/** Field description */
public static final String PACKAGEURL =
"http://download.scm-manager.org/pkg/mercurial/packages.xml.gz";
/** the logger for HgPackageReader */
private static final Logger logger =
LoggerFactory.getLogger(HgPackageReader.class);
//~--- constructors ---------------------------------------------------------
/**
* Constructs ...
*
*
* @param cacheManager
*/
public HgPackageReader(CacheManager cacheManager)
{
cache = cacheManager.getCache(String.class, HgPackages.class, CACHENAME);
}
//~--- get methods ----------------------------------------------------------
/**
* Method description
*
*
* @param id
*
* @return
*/
public HgPackage getPackage(String id)
{
HgPackage pkg = null;
for (HgPackage p : getPackages())
{
if (id.equals(p.getId()))
{
pkg = p;
break;
}
}
return pkg;
}
/**
* Method description
*
*
* @return
*/
public HgPackages getPackages()
{
HgPackages packages = cache.get(HgPackages.class.getName());
if (packages == null)
{
packages = getRemptePackages();
filterPackage(packages);
cache.put(HgPackages.class.getName(), packages);
}
return packages;
}
//~--- methods --------------------------------------------------------------
/**
* Method description
*
*
* @param packages
*/
private void filterPackage(HgPackages packages)
{
List<HgPackage> pkgList = new ArrayList<HgPackage>();
for (HgPackage pkg : packages)
{
boolean add = true;
if (Util.isNotEmpty(pkg.getPlatform()))
{
PlatformType pt = PlatformType.createPlatformType(pkg.getPlatform());
if (SystemUtil.getPlatform().getType() != pt)
{
if (logger.isDebugEnabled())
{
logger.debug("reject package {}, because of wrong platform {}",
pkg.getId(), pkg.getPlatform());
}
add = false;
}
}
if (add && Util.isNotEmpty(pkg.getArch()))
{
if (!SystemUtil.getArch().equals(pkg.getArch()))
{
if (logger.isDebugEnabled())
{
logger.debug("reject package {}, because of wrong arch {}",
pkg.getId(), pkg.getArch());
}
add = false;
}
}
if (add)
{
if (logger.isDebugEnabled())
{
logger.debug("added HgPackage {}", pkg.getId());
}
pkgList.add(pkg);
}
}
packages.setPackages(pkgList);
}
//~--- get methods ----------------------------------------------------------
/**
* Method description
*
*
* @return
*/
private HgPackages getRemptePackages()
{
if (logger.isInfoEnabled())
{
logger.info("fetch HgPackages from {}", PACKAGEURL);
}
HgPackages packages = null;
InputStream input = null;
try
{
URL url = new URL(PACKAGEURL);
if (PACKAGEURL.endsWith(".gz"))
{
input = new GZIPInputStream(url.openStream());
}
else
{
input = url.openStream();
}
packages = JAXB.unmarshal(input, HgPackages.class);
}
catch (IOException ex)
{
logger.error("could not read HgPackages from {}", PACKAGEURL);
}
finally
{
IOUtil.close(input);
}
if (packages == null)
{
packages = new HgPackages();
packages.setPackages(new ArrayList<HgPackage>());
}
return packages;
}
//~--- fields ---------------------------------------------------------------
/** Field description */
private Cache<String, HgPackages> cache;
}

View File

@@ -0,0 +1,98 @@
/**
* 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.installer;
//~--- JDK imports ------------------------------------------------------------
import java.util.Iterator;
import java.util.List;
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
*/
@XmlRootElement(name = "packages")
@XmlAccessorType(XmlAccessType.FIELD)
public class HgPackages implements Iterable<HgPackage>
{
/**
* Method description
*
*
* @return
*/
@Override
public Iterator<HgPackage> iterator()
{
return packages.iterator();
}
//~--- get methods ----------------------------------------------------------
/**
* Method description
*
*
* @return
*/
public List<HgPackage> getPackages()
{
return packages;
}
//~--- set methods ----------------------------------------------------------
/**
* Method description
*
*
* @param packages
*/
public void setPackages(List<HgPackage> packages)
{
this.packages = packages;
}
//~--- fields ---------------------------------------------------------------
/** Field description */
@XmlElement(name = "package")
private List<HgPackage> packages;
}

View File

@@ -0,0 +1,152 @@
/**
* 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.installer;
//~--- non-JDK imports --------------------------------------------------------
import sonia.scm.repository.HgConfig;
import sonia.scm.util.IOUtil;
import sonia.scm.util.Util;
//~--- JDK imports ------------------------------------------------------------
import java.io.File;
import java.io.IOException;
import java.util.List;
/**
*
* @author Sebastian Sdorra
*/
public class UnixHgInstaller extends AbstractHgInstaller
{
/** Field description */
public static final String COMMAND_HG = "hg";
/** Field description */
public static final String COMMAND_PYTHON = "python";
//~--- methods --------------------------------------------------------------
/**
* Method description
*
*
*
* @param baseDirectory
* @param config
*
* @throws IOException
*/
@Override
public void install(File baseDirectory, HgConfig config) throws IOException
{
super.install(baseDirectory, config);
// search mercurial (hg)
if (Util.isEmpty(config.getHgBinary()))
{
String hg = IOUtil.search(COMMAND_HG);
if (Util.isNotEmpty(hg))
{
config.setHgBinary(hg);
// search python in the same folder
File hgFile = new File(hg);
if (hgFile.exists())
{
File pythonFile = new File(hgFile.getParentFile(), COMMAND_PYTHON);
if (pythonFile.exists())
{
config.setPythonBinary(pythonFile.getAbsolutePath());
}
}
}
}
// search python
if (Util.isEmpty(config.getPythonBinary()))
{
config.setPythonBinary(IOUtil.search(COMMAND_PYTHON));
}
}
/**
* Method description
*
*
*
* @param baseDirectory
* @param config
*/
@Override
public void update(File baseDirectory, HgConfig config)
{
// do nothing
}
//~--- get methods ----------------------------------------------------------
/**
* Method description
*
*
* @return
*/
@Override
public List<String> getHgInstallations()
{
return IOUtil.searchAll(COMMAND_HG);
}
/**
* Method description
*
*
* @return
*/
@Override
public List<String> getPythonInstallations()
{
return IOUtil.searchAll(COMMAND_PYTHON);
}
}

View File

@@ -0,0 +1,428 @@
/**
* 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.installer;
//~--- non-JDK imports --------------------------------------------------------
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import sonia.scm.repository.HgConfig;
import sonia.scm.util.IOUtil;
import sonia.scm.util.RegistryUtil;
import sonia.scm.util.Util;
//~--- JDK imports ------------------------------------------------------------
import java.io.File;
import java.io.FilenameFilter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
/**
*
* @author Sebastian Sdorra
*/
public class WindowsHgInstaller extends AbstractHgInstaller
{
/** Field description */
private static final String FILE_LIBRARY_ZIP = "library.zip";
/** Field description */
private static final String FILE_LIB_MERCURIAL =
"Lib\\site-packages\\mercurial";
/** Field description */
private static final String FILE_MERCURIAL_EXE = "hg.exe";
/** Field description */
private static final String FILE_MERCURIAL_SCRIPT = "hg.bat";
/** Field description */
private static final String FILE_SCRIPTS = "Scripts";
/** Field description */
private static final String FILE_TEMPLATES = "templates";
/** Field description */
private static final String[] REGISTRY_HG = new String[]
{
// TortoiseHg
"HKEY_CURRENT_USER\\Software\\TortoiseHg",
// Mercurial
"HKEY_CURRENT_USER\\Software\\Mercurial\\InstallDir"
};
/** Field description */
private static final String[] REGISTRY_PYTHON = new String[]
{
// .py files
"HKEY_CLASSES_ROOT\\Python.File\\shell\\open\\command"
};
/** the logger for WindowsHgInstaller */
private static final Logger logger =
LoggerFactory.getLogger(WindowsHgInstaller.class);
//~--- methods --------------------------------------------------------------
/**
* Method description
*
*
*
* @param baseDirectory
* @param config
*
* @throws IOException
*/
@Override
public void install(File baseDirectory, HgConfig config) throws IOException
{
super.install(baseDirectory, config);
if (Util.isEmpty(config.getPythonBinary()))
{
String pythonBinary = getPythonBinary();
config.setPythonBinary(pythonBinary);
}
if (Util.isEmpty(config.getHgBinary()))
{
File hgScript = getMercurialScript(config.getPythonBinary());
if (hgScript != null)
{
config.setHgBinary(hgScript.getAbsolutePath());
}
}
File hgDirectory = getMercurialDirectory(config.getHgBinary());
if (hgDirectory != null)
{
installHg(baseDirectory, config, hgDirectory);
}
checkForOptimizedByteCode(config);
}
/**
* Method description
*
*
*
* @param baseDirectory
* @param config
*/
@Override
public void update(File baseDirectory, HgConfig config) {}
//~--- get methods ----------------------------------------------------------
/**
* Method description
*
*
* @return
*/
@Override
public List<String> getHgInstallations()
{
return getInstallations(REGISTRY_HG);
}
/**
* Method description
*
*
* @return
*/
@Override
public List<String> getPythonInstallations()
{
return getInstallations(REGISTRY_PYTHON);
}
//~--- methods --------------------------------------------------------------
/**
* Method description
*
*
* @param config
*/
private void checkForOptimizedByteCode(HgConfig config)
{
boolean optimized = false;
String path = config.getPythonPath();
if (Util.isNotEmpty(path))
{
for (String part : path.split(";"))
{
if (checkForOptimizedByteCode(part))
{
optimized = true;
break;
}
}
}
config.setUseOptimizedBytecode(optimized);
}
/**
* Method description
*
*
* @param part
*
* @return
*/
private boolean checkForOptimizedByteCode(String part)
{
File libDir = new File(part);
String[] pyoFiles = libDir.list(new FilenameFilter()
{
@Override
public boolean accept(File file, String name)
{
return name.toLowerCase().endsWith(".pyo");
}
});
return Util.isNotEmpty(pyoFiles);
}
/**
* Method description
*
*
*
* @param baseDirectory
* @param config
* @param hgDirectory
*
* @throws IOException
*/
private void installHg(File baseDirectory, HgConfig config, File hgDirectory)
throws IOException
{
if (logger.isInfoEnabled())
{
logger.info("installing mercurial {}", hgDirectory.getAbsolutePath());
}
File libDir = new File(baseDirectory, "lib\\hg");
IOUtil.mkdirs(libDir);
File libraryZip = new File(hgDirectory, FILE_LIBRARY_ZIP);
if (libraryZip.exists())
{
IOUtil.extract(libraryZip, libDir);
config.setPythonPath(libDir.getAbsolutePath());
}
File templateDirectory = new File(hgDirectory, FILE_TEMPLATES);
if (templateDirectory.exists())
{
IOUtil.copy(templateDirectory, new File(libDir, FILE_TEMPLATES));
}
File hg = new File( hgDirectory, FILE_MERCURIAL_EXE );
if ( hg.exists() )
{
config.setHgBinary(hg.getAbsolutePath());
}
}
//~--- get methods ----------------------------------------------------------
/**
* Method description
*
*
* @param registryKeys
*
* @return
*/
private List<String> getInstallations(String[] registryKeys)
{
List<String> installations = new ArrayList<String>();
for (String registryKey : registryKeys)
{
String path = RegistryUtil.getRegistryValue(registryKey);
if (path != null)
{
File file = new File(path, FILE_MERCURIAL_EXE);
if (file.exists())
{
installations.add(file.getAbsolutePath());
}
}
}
return installations;
}
/**
* Method description
*
*
*
* @param hgBinary
* @return
*/
private File getMercurialDirectory(String hgBinary)
{
File directory = null;
if ( Util.isNotEmpty(hgBinary) )
{
File hg = new File(hgBinary);
if (hg.exists() && hg.isFile())
{
directory = hg.getParentFile();
}
}
if ( directory == null )
{
directory = getMercurialDirectoryFromRegistry();
}
return directory;
}
/**
* Method description
*
*
* @return
*/
private File getMercurialDirectoryFromRegistry()
{
File directory = null;
for (String registryKey : REGISTRY_HG)
{
String path = RegistryUtil.getRegistryValue(registryKey);
if (path != null)
{
directory = new File(path);
if (!directory.exists())
{
directory = null;
}
else
{
break;
}
}
}
return directory;
}
/**
* Returns the location of the script to run Mercurial, if Mercurial is
* installed as a Python package from source. Only packages that include a
* templates directory will be recognized.
*
* @param pythonBinary
*
* @return
*/
private File getMercurialScript(String pythonBinary)
{
File hgScript = null;
if (pythonBinary != null)
{
File pythonBinaryFile = new File(pythonBinary);
if (pythonBinaryFile.exists())
{
File pythonDir = pythonBinaryFile.getParentFile();
File scriptsDir = new File(pythonDir, FILE_SCRIPTS);
File potentialHgScript = new File(scriptsDir, FILE_MERCURIAL_SCRIPT);
File mercurialPackageDir = new File(pythonDir, FILE_LIB_MERCURIAL);
File templatesDir = new File(mercurialPackageDir, FILE_TEMPLATES);
if (potentialHgScript.exists() && templatesDir.exists())
{
hgScript = potentialHgScript;
}
}
}
return hgScript;
}
/**
* Method description
*
*
* @return
*/
private String getPythonBinary()
{
String python = RegistryUtil.getRegistryValue(REGISTRY_PYTHON[0]);
if (python == null)
{
python = IOUtil.search(new String[0], "python");
}
return python;
}
}

View File

@@ -0,0 +1,238 @@
/**
* 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.repository;
//~--- non-JDK imports --------------------------------------------------------
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import sonia.scm.util.Util;
//~--- JDK imports ------------------------------------------------------------
import java.io.IOException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
/**
*
* @author Sebastian Sdorra
*/
public class HgChangesetParser
{
/** the logger for HgChangesetParser */
private static final Logger logger =
LoggerFactory.getLogger(HgChangesetParser.class);
//~--- methods --------------------------------------------------------------
/**
* Method description
*
*
* @param in
*
* @return
*
* @throws IOException
* @throws ParserConfigurationException
* @throws SAXException
*/
public List<Changeset> parse(InputSource in)
throws SAXException, IOException, ParserConfigurationException
{
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
return parse(builder.parse(in));
}
/**
* Method description
*
*
* @param document
*
* @return
*/
private List<Changeset> parse(Document document)
{
List<Changeset> changesetList = new ArrayList<Changeset>();
NodeList changesetNodeList = document.getElementsByTagName("changeset");
if (changesetNodeList != null)
{
for (int i = 0; i < changesetNodeList.getLength(); i++)
{
Node changesetNode = changesetNodeList.item(i);
Changeset changeset = parseChangesetNode(changesetNode);
if ((changeset != null) && changeset.isValid())
{
changesetList.add(changeset);
}
}
}
return changesetList;
}
/**
* Method description
*
*
* @param changeset
* @param node
*/
private void parseChangesetChildNode(Changeset changeset, Node node)
{
String name = node.getNodeName();
String value = node.getTextContent();
if (Util.isNotEmpty(value))
{
if ("id".equals(name))
{
changeset.setId(value);
}
else if ("author".equals(name))
{
changeset.setAuthor(Person.toPerson(value));
}
else if ("description".equals(name))
{
changeset.setDescription(value);
}
else if ("date".equals(name))
{
try
{
Date date = dateFormat.parse(value);
changeset.setDate(date.getTime());
}
catch (ParseException ex)
{
logger.warn("could not parse date", ex);
}
}
else if ("tags".equals(name))
{
changeset.setTags(getList(value));
}
else if ("branches".equals(name))
{
changeset.setBranches(getList(value));
}
else if ("files-added".equals(name))
{
changeset.getModifications().setAdded(getList(value));
}
else if ("files-mods".equals(name))
{
changeset.getModifications().setModified(getList(value));
}
else if ("files-dels".equals(name))
{
changeset.getModifications().setRemoved(getList(value));
}
}
}
/**
* Method description
*
*
* @param changesetNode
*
* @return
*/
private Changeset parseChangesetNode(Node changesetNode)
{
Changeset changeset = new Changeset();
NodeList childrenNodeList = changesetNode.getChildNodes();
if (childrenNodeList != null)
{
for (int i = 0; i < childrenNodeList.getLength(); i++)
{
Node child = childrenNodeList.item(i);
parseChangesetChildNode(changeset, child);
}
}
return changeset;
}
//~--- get methods ----------------------------------------------------------
/**
* Method description
*
*
* @param value
*
* @return
*/
private List<String> getList(String value)
{
return Arrays.asList(value.split(" "));
}
//~--- fields ---------------------------------------------------------------
/** Field description */
private SimpleDateFormat dateFormat =
new SimpleDateFormat("yyyy-MM-dd HH:mm:ss z");
}

View File

@@ -0,0 +1,237 @@
/**
* 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.repository;
//~--- non-JDK imports --------------------------------------------------------
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import sonia.scm.io.Command;
import sonia.scm.io.CommandResult;
import sonia.scm.io.SimpleCommand;
import sonia.scm.util.IOUtil;
//~--- JDK imports ------------------------------------------------------------
import java.io.IOException;
import java.io.InputStream;
import java.io.StringReader;
import java.util.List;
import javax.xml.parsers.ParserConfigurationException;
/**
*
* @author Sebastian Sdorra
*/
public class HgChangesetViewer implements ChangesetViewer
{
/** Field description */
public static final String ID_TIP = "tip";
/** Field description */
//J-
public static final String TEMPLATE_CHANGESETS =
"\"<changeset>"
+ "<id>{rev}:{node|short}</id>"
+ "<author>{author|escape}</author>"
+ "<description>{desc|escape}</description>"
+ "<date>{date|isodatesec}</date>"
+ "<tags>{tags}</tags>"
+ "<branches>{branches}</branches>"
+ "<files-added>{file_adds}</files-added>"
+ "<files-mods>{file_mods}</files-mods>"
+ "<files-dels>{file_dels}</files-dels>"
+ "</changeset>\"";
//J+
/** Field description */
public static final String TEMPLATE_TOTAL = "{rev}";
/** the logger for HgChangesetViewer */
private static final Logger logger =
LoggerFactory.getLogger(HgChangesetViewer.class);
//~--- constructors ---------------------------------------------------------
/**
* Constructs ...
*
*
*
* @param handler
* @param repository
*/
public HgChangesetViewer(HgRepositoryHandler handler, Repository repository)
{
this.handler = handler;
this.repository = repository;
}
//~--- get methods ----------------------------------------------------------
/**
*
*
* @param start
* @param max
*
* @return
*/
@Override
public ChangesetPagingResult getChangesets(int start, int max)
{
ChangesetPagingResult changesets = null;
InputStream in = null;
try
{
String repositoryPath = getRepositoryPath(repository);
int total = getTotalChangesets(repositoryPath);
int startRev = total - start;
int endRev = total - start - (max - 1);
if (endRev < 0)
{
endRev = 0;
}
Command command = new SimpleCommand(handler.getConfig().getHgBinary(),
"-R", repositoryPath, "log", "-r",
startRev + ":" + endRev, "--template",
TEMPLATE_CHANGESETS);
CommandResult result = command.execute();
if (result.isSuccessfull())
{
StringBuilder sb = new StringBuilder("<changesets>");
sb.append(result.getOutput()).append("</changesets>");
List<Changeset> changesetList = new HgChangesetParser().parse(
new InputSource(
new StringReader(sb.toString())));
changesets = new ChangesetPagingResult(total, changesetList);
}
else if ( logger.isErrorEnabled() )
{
logger.error(
"command for fetching changesets failed with exit code {} and output {}",
result.getReturnCode(),
result.getOutput()
);
}
}
catch (ParserConfigurationException ex)
{
logger.error("could not parse changesets", ex);
}
catch (IOException ex)
{
logger.error("could not load changesets", ex);
}
catch (SAXException ex)
{
logger.error("could not unmarshall changesets", ex);
}
finally
{
IOUtil.close(in);
}
return changesets;
}
/**
* Method description
*
*
* @param repository
*
* @return
*/
private String getRepositoryPath(Repository repository)
{
return handler.getDirectory(repository).getAbsolutePath();
}
/**
* Method description
*
*
* @param repositoryPath
*
* @return
*
* @throws IOException
*/
private int getTotalChangesets(String repositoryPath) throws IOException
{
int total = -1;
Command command = new SimpleCommand(handler.getConfig().getHgBinary(),
"-R", repositoryPath, "tip", "--template",
TEMPLATE_TOTAL);
CommandResult result = command.execute();
if (result.isSuccessfull())
{
total = Integer.parseInt(result.getOutput().trim());
}
else if ( logger.isErrorEnabled() )
{
logger.error(
"could not read tip revision, command returned with exit code {} and content {}",
result.getReturnCode(),
result.getOutput()
);
}
return total;
}
//~--- fields ---------------------------------------------------------------
/** Field description */
private HgRepositoryHandler handler;
/** Field description */
private Repository repository;
}

View File

@@ -0,0 +1,176 @@
/**
* 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.repository;
//~--- non-JDK imports --------------------------------------------------------
import sonia.scm.util.Util;
//~--- JDK imports ------------------------------------------------------------
import javax.xml.bind.annotation.XmlRootElement;
/**
*
* @author Sebastian Sdorra
*/
@XmlRootElement(name = "config")
public class HgConfig extends SimpleRepositoryConfig
{
/**
* Constructs ...
*
*/
public HgConfig() {}
//~--- get methods ----------------------------------------------------------
/**
* Method description
*
*
* @return
*/
public String getHgBinary()
{
return hgBinary;
}
/**
* Method description
*
*
* @return
*/
public String getPythonBinary()
{
return pythonBinary;
}
/**
* Method description
*
*
* @return
*/
public String getPythonPath()
{
return pythonPath;
}
/**
* Method description
*
*
* @return
*/
public boolean isUseOptimizedBytecode()
{
return useOptimizedBytecode;
}
/**
* Method description
*
*
* @return
*/
@Override
public boolean isValid()
{
return super.isValid() && Util.isNotEmpty(hgBinary)
&& Util.isNotEmpty(pythonBinary);
}
//~--- set methods ----------------------------------------------------------
/**
* Method description
*
*
* @param hgBinary
*/
public void setHgBinary(String hgBinary)
{
this.hgBinary = hgBinary;
}
/**
* Method description
*
*
* @param pythonBinary
*/
public void setPythonBinary(String pythonBinary)
{
this.pythonBinary = pythonBinary;
}
/**
* Method description
*
*
* @param pythonPath
*/
public void setPythonPath(String pythonPath)
{
this.pythonPath = pythonPath;
}
/**
* Method description
*
*
* @param useOptimizedBytecode
*/
public void setUseOptimizedBytecode(boolean useOptimizedBytecode)
{
this.useOptimizedBytecode = useOptimizedBytecode;
}
//~--- fields ---------------------------------------------------------------
/** Field description */
private String hgBinary;
/** Field description */
private String pythonBinary;
/** Field description */
private String pythonPath = "";
/** Field description */
private boolean useOptimizedBytecode = false;
}

View File

@@ -0,0 +1,238 @@
/**
* 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.repository;
//~--- non-JDK imports --------------------------------------------------------
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import sonia.scm.util.IOUtil;
import sonia.scm.util.Util;
//~--- JDK imports ------------------------------------------------------------
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Map;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
/**
*
* @author Sebastian Sdorra
*/
public class HgRepositoryBrowser implements RepositoryBrowser
{
/** Field description */
public static final String DEFAULT_REVISION = "tip";
/** Field description */
public static final String ENV_PATH = "SCM_PATH";
/** Field description */
public static final String ENV_PYTHON_PATH = "SCM_PYTHON_PATH";
/** Field description */
public static final String ENV_REPOSITORY_PATH = "SCM_REPOSITORY_PATH";
/** Field description */
public static final String ENV_REVISION = "SCM_REVISION";
/** Field description */
public static final String RESOURCE_BROWSE = "/sonia/scm/hgbrowse.py";
/** the logger for HgRepositoryBrowser */
private static final Logger logger =
LoggerFactory.getLogger(HgRepositoryBrowser.class);
//~--- constructors ---------------------------------------------------------
/**
* Constructs ...
*
*
* @param handler
* @param repository
* @param browserResultContext
*/
public HgRepositoryBrowser(HgRepositoryHandler handler,
Repository repository,
JAXBContext browserResultContext)
{
this.handler = handler;
this.repository = repository;
this.browserResultContext = browserResultContext;
}
//~--- get methods ----------------------------------------------------------
/**
* Method description
*
*
* @param revision
* @param path
* @param output
*
*
* @throws IOException
* @throws RepositoryException
*/
@Override
public void getContent(String revision, String path, OutputStream output)
throws IOException, RepositoryException
{
if (Util.isEmpty(revision))
{
revision = DEFAULT_REVISION;
}
File directory = handler.getDirectory(repository);
ProcessBuilder builder =
new ProcessBuilder(handler.getConfig().getHgBinary(), "cat", "-r",
revision, Util.nonNull(path));
if (logger.isDebugEnabled())
{
StringBuilder msg = new StringBuilder();
for (String param : builder.command())
{
msg.append(param).append(" ");
}
logger.debug(msg.toString());
}
Process p = builder.directory(directory).start();
InputStream input = null;
try
{
input = p.getInputStream();
IOUtil.copy(input, output);
}
finally
{
IOUtil.close(input);
}
}
/**
* Method description
*
*
* @param revision
* @param path
*
* @return
*
* @throws IOException
* @throws RepositoryException
*/
@Override
public BrowserResult getResult(String revision, String path)
throws IOException, RepositoryException
{
HgConfig config = handler.getConfig();
ProcessBuilder pb = new ProcessBuilder(config.getPythonBinary());
Map<String, String> env = pb.environment();
env.put(ENV_PYTHON_PATH, Util.nonNull(config.getPythonPath()));
String directory = handler.getDirectory(repository).getAbsolutePath();
env.put(ENV_REPOSITORY_PATH, directory);
if (Util.isEmpty(revision))
{
revision = DEFAULT_REVISION;
}
env.put(ENV_REVISION, revision);
env.put(ENV_PATH, Util.nonNull(path));
Process p = pb.start();
BrowserResult result = null;
InputStream resource = null;
InputStream input = null;
OutputStream output = null;
try
{
resource = HgRepositoryBrowser.class.getResourceAsStream(RESOURCE_BROWSE);
output = p.getOutputStream();
IOUtil.copy(resource, output);
output.close();
// IOUtil.copy(p.getErrorStream(), System.err);
input = p.getInputStream();
result =
(BrowserResult) browserResultContext.createUnmarshaller().unmarshal(
input);
// IOUtil.copy(input, System.out);
input.close();
}
catch (JAXBException ex)
{
logger.error("could not parse result", ex);
}
finally
{
IOUtil.close(resource);
IOUtil.close(input);
IOUtil.close(output);
}
return result;
}
//~--- fields ---------------------------------------------------------------
/** Field description */
private JAXBContext browserResultContext;
/** Field description */
private HgRepositoryHandler handler;
/** Field description */
private Repository repository;
}

View File

@@ -0,0 +1,290 @@
/**
* 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.repository;
//~--- non-JDK imports --------------------------------------------------------
import com.google.inject.Inject;
import com.google.inject.Singleton;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import sonia.scm.ConfigurationException;
import sonia.scm.Type;
import sonia.scm.installer.HgInstaller;
import sonia.scm.installer.HgInstallerFactory;
import sonia.scm.io.ExtendedCommand;
import sonia.scm.io.FileSystem;
import sonia.scm.io.INIConfiguration;
import sonia.scm.io.INIConfigurationWriter;
import sonia.scm.io.INISection;
import sonia.scm.plugin.ext.Extension;
import sonia.scm.store.StoreFactory;
import sonia.scm.util.AssertUtil;
import sonia.scm.web.HgWebConfigWriter;
//~--- JDK imports ------------------------------------------------------------
import java.io.File;
import java.io.IOException;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
/**
*
* @author Sebastian Sdorra
*/
@Singleton
@Extension
public class HgRepositoryHandler
extends AbstractSimpleRepositoryHandler<HgConfig>
{
/** Field description */
public static final String TYPE_DISPLAYNAME = "Mercurial";
/** Field description */
public static final String TYPE_NAME = "hg";
/** Field description */
public static final Type TYPE = new Type(TYPE_NAME, TYPE_DISPLAYNAME);
/** the logger for HgRepositoryHandler */
private static final Logger logger =
LoggerFactory.getLogger(HgRepositoryHandler.class);
//~--- constructors ---------------------------------------------------------
/**
* Constructs ...
*
*
* @param storeFactory
* @param fileSystem
*/
@Inject
public HgRepositoryHandler(StoreFactory storeFactory, FileSystem fileSystem)
{
super(storeFactory, fileSystem);
try
{
this.browserResultContext = JAXBContext.newInstance(BrowserResult.class);
}
catch (JAXBException ex)
{
throw new ConfigurationException("could not create jaxbcontext", ex);
}
}
//~--- methods --------------------------------------------------------------
/**
* Method description
*
*
* @param autoConfig
*/
public void doAutoConfiguration(HgConfig autoConfig)
{
HgInstaller installer = HgInstallerFactory.createInstaller();
try
{
if (logger.isDebugEnabled())
{
logger.debug("installing mercurial with {}",
installer.getClass().getName());
}
installer.install(baseDirectory, autoConfig);
config = autoConfig;
storeConfig();
new HgWebConfigWriter(config).write();
}
catch (IOException ioe)
{
if (logger.isErrorEnabled())
{
logger.error(
"Could not write Hg CGI for inital config. "
+ "HgWeb may not function until a new Hg config is set", ioe);
}
}
}
/**
* Method description
*
*/
@Override
public void loadConfig()
{
super.loadConfig();
if (config == null)
{
doAutoConfiguration(new HgConfig());
}
}
//~--- get methods ----------------------------------------------------------
/**
* Method description
*
*
* @param repository
*
* @return
*/
@Override
public ChangesetViewer getChangesetViewer(Repository repository)
{
HgChangesetViewer changesetViewer = null;
AssertUtil.assertIsNotNull(repository);
String type = repository.getType();
AssertUtil.assertIsNotEmpty(type);
if (TYPE_NAME.equals(type))
{
changesetViewer = new HgChangesetViewer(this, repository);
}
else
{
throw new IllegalArgumentException("mercurial repository is required");
}
return changesetViewer;
}
/**
* Method description
*
*
* @param repository
*
* @return
*/
@Override
public RepositoryBrowser getRepositoryBrowser(Repository repository)
{
return new HgRepositoryBrowser(this, repository, browserResultContext);
}
/**
* Method description
*
*
* @return
*/
@Override
public Type getType()
{
return TYPE;
}
//~--- methods --------------------------------------------------------------
/**
* Method description
*
*
* @param repository
* @param directory
*
* @return
*/
@Override
protected ExtendedCommand buildCreateCommand(Repository repository,
File directory)
{
return new ExtendedCommand(config.getHgBinary(), "init",
directory.getPath());
}
/**
* Writes .hg/hgrc and disables hg access control
* see HgPermissionFilter
*
* @param repository
* @param directory
*
* @throws IOException
* @throws RepositoryException
*/
@Override
protected void postCreate(Repository repository, File directory)
throws IOException, RepositoryException
{
File hgrcFile = new File(directory,
".hg".concat(File.separator).concat("hgrc"));
INIConfiguration hgrc = new INIConfiguration();
INISection webSection = new INISection("web");
webSection.setParameter("push_ssl", "false");
webSection.setParameter("allow_read", "*");
webSection.setParameter("allow_push", "*");
hgrc.addSection(webSection);
INIConfigurationWriter writer = new INIConfigurationWriter();
writer.write(hgrc, hgrcFile);
}
//~--- get methods ----------------------------------------------------------
/**
* Method description
*
*
* @return
*/
@Override
protected Class<HgConfig> getConfigClass()
{
return HgConfig.class;
}
//~--- fields ---------------------------------------------------------------
/** Field description */
private JAXBContext browserResultContext;
}

View File

@@ -0,0 +1,263 @@
/**
* Copyright (c) 2010, Sebastian Sdorra
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. Neither the name of SCM-Manager; nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* http://bitbucket.org/sdorra/scm-manager
*
*/
package sonia.scm.web;
//~--- non-JDK imports --------------------------------------------------------
import com.google.inject.Inject;
import com.google.inject.Singleton;
import sonia.scm.config.ScmConfiguration;
import sonia.scm.repository.HgConfig;
import sonia.scm.repository.HgRepositoryHandler;
import sonia.scm.repository.Repository;
import sonia.scm.repository.RepositoryManager;
import sonia.scm.util.AssertUtil;
import sonia.scm.web.cgi.CGIExecutor;
import sonia.scm.web.cgi.CGIExecutorFactory;
//~--- JDK imports ------------------------------------------------------------
import java.io.File;
import java.io.IOException;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
*
* @author Sebastian Sdorra
*/
@Singleton
public class HgCGIServlet extends HttpServlet
{
/** Field description */
public static final String ENV_PYTHON_PATH = "SCM_PYTHON_PATH";
/** Field description */
public static final String ENV_REPOSITORY_NAME = "REPO_NAME";
/** Field description */
public static final String ENV_REPOSITORY_PATH = "SCM_REPOSITORY_PATH";
/** Field description */
private static final long serialVersionUID = -3492811300905099810L;
/** Field description */
public static final Pattern PATTERN_REPOSITORYNAME =
Pattern.compile("/[^/]+/([^/]+)(?:/.*)?");
//~--- constructors ---------------------------------------------------------
/**
* Constructs ...
*
*
*
*
*
* @param cgiExecutorFactory
* @param configuration
* @param repositoryManager
* @param handler
*/
@Inject
public HgCGIServlet(CGIExecutorFactory cgiExecutorFactory,
ScmConfiguration configuration,
RepositoryManager repositoryManager,
HgRepositoryHandler handler)
{
this.cgiExecutorFactory = cgiExecutorFactory;
this.configuration = configuration;
this.repositoryManager = repositoryManager;
this.handler = handler;
}
//~--- methods --------------------------------------------------------------
/**
* Method description
*
*
* @throws ServletException
*/
@Override
public void init() throws ServletException
{
command = HgUtil.getCGI();
super.init();
}
/**
* Method description
*
*
* @param request
* @param response
*
* @throws IOException
* @throws ServletException
*/
@Override
protected void service(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException
{
Repository repository = getRepository(request);
if (repository == null)
{
throw new ServletException("repository not found");
}
String name = repository.getName();
File directory = handler.getDirectory(repository);
String pythonPath = "";
HgConfig config = handler.getConfig();
if (config != null)
{
pythonPath = config.getPythonPath();
if (pythonPath == null)
{
pythonPath = "";
}
}
CGIExecutor executor = cgiExecutorFactory.createExecutor(configuration,
getServletContext(), request, response);
executor.getEnvironment().set(ENV_REPOSITORY_NAME, name);
executor.getEnvironment().set(ENV_REPOSITORY_PATH,
directory.getAbsolutePath());
executor.getEnvironment().set(ENV_PYTHON_PATH, pythonPath);
String interpreter = getInterpreter();
if (interpreter != null)
{
executor.setInterpreter(interpreter);
}
executor.execute(command.getAbsolutePath());
}
//~--- get methods ----------------------------------------------------------
/**
* Method description
*
*
* @return
*/
private String getInterpreter()
{
HgConfig config = handler.getConfig();
AssertUtil.assertIsNotNull(config);
String python = config.getPythonBinary();
if ((python != null) && config.isUseOptimizedBytecode())
{
python = python.concat(" -O");
}
return python;
}
/**
* Method description
*
*
* @param request
*
* @return
*/
private 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 repositoryname
*
* @return
*/
private Repository getRepository(String repositoryname)
{
return repositoryManager.get(HgRepositoryHandler.TYPE_NAME, repositoryname);
}
//~--- fields ---------------------------------------------------------------
/** Field description */
private CGIExecutorFactory cgiExecutorFactory;
/** Field description */
private File command;
/** Field description */
private ScmConfiguration configuration;
/** Field description */
private HgRepositoryHandler handler;
/** Field description */
private RepositoryManager repositoryManager;
}

View File

@@ -0,0 +1,101 @@
/**
* Copyright (c) 2010, Sebastian Sdorra
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. Neither the name of SCM-Manager; nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* http://bitbucket.org/sdorra/scm-manager
*
*/
package sonia.scm.web;
//~--- non-JDK imports --------------------------------------------------------
import com.google.inject.Inject;
import com.google.inject.Provider;
import com.google.inject.Singleton;
import sonia.scm.repository.HgRepositoryHandler;
import sonia.scm.repository.RepositoryManager;
import sonia.scm.web.filter.RegexPermissionFilter;
import sonia.scm.web.security.WebSecurityContext;
//~--- JDK imports ------------------------------------------------------------
import javax.servlet.http.HttpServletRequest;
/**
*
* @author Sebastian Sdorra
*/
@Singleton
public class HgPermissionFilter extends RegexPermissionFilter
{
/**
* Constructs ...
*
*
* @param securityContextProvider
* @param repositoryManager
*/
@Inject
public HgPermissionFilter(
Provider<WebSecurityContext> securityContextProvider,
RepositoryManager repositoryManager)
{
super(securityContextProvider, repositoryManager);
}
//~--- get methods ----------------------------------------------------------
/**
* Method description
*
*
* @return
*/
@Override
protected String getType()
{
return HgRepositoryHandler.TYPE_NAME;
}
/**
* Method description
*
*
* @param request
*
* @return
*/
@Override
protected boolean isWriteRequest(HttpServletRequest request)
{
return !request.getMethod().equalsIgnoreCase("GET");
}
}

View File

@@ -0,0 +1,67 @@
/**
* Copyright (c) 2010, Sebastian Sdorra
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. Neither the name of SCM-Manager; nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* http://bitbucket.org/sdorra/scm-manager
*
*/
package sonia.scm.web;
//~--- non-JDK imports --------------------------------------------------------
import com.google.inject.servlet.ServletModule;
import sonia.scm.plugin.ext.Extension;
import sonia.scm.web.filter.BasicAuthenticationFilter;
/**
*
* @author Sebastian Sdorra
*/
@Extension
public class HgServletModule extends ServletModule
{
/** Field description */
public static final String MAPPING_HG = "/hg/*";
//~--- methods --------------------------------------------------------------
/**
* Method description
*
*/
@Override
protected void configureServlets()
{
filter(MAPPING_HG).through(BasicAuthenticationFilter.class);
filter(MAPPING_HG).through(HgPermissionFilter.class);
serve(MAPPING_HG).with(HgCGIServlet.class);
}
}

View File

@@ -0,0 +1,78 @@
/**
* Copyright (c) 2010, Sebastian Sdorra
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. Neither the name of SCM-Manager; nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* http://bitbucket.org/sdorra/scm-manager
*
*/
package sonia.scm.web;
//~--- non-JDK imports --------------------------------------------------------
import sonia.scm.SCMContext;
//~--- JDK imports ------------------------------------------------------------
import java.io.File;
/**
*
* @author Sebastian Sdorra
*/
public class HgUtil
{
/** Field description */
public static final String CGI_DIRECTORY = "cgi-bin";
/** Field description */
public static final String CGI_NAME = "hgweb.py";
//~--- get methods ----------------------------------------------------------
/**
* Method description
*
*
* @return
*/
public static File getCGI()
{
File cgiDirectory = new File(SCMContext.getContext().getBaseDirectory(),
CGI_DIRECTORY);
if (!cgiDirectory.exists() &&!cgiDirectory.mkdirs())
{
throw new RuntimeException(
"could not create directory".concat(cgiDirectory.getPath()));
}
return new File(cgiDirectory, CGI_NAME);
}
}

View File

@@ -0,0 +1,125 @@
/**
* Copyright (c) 2010, Sebastian Sdorra
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. Neither the name of SCM-Manager; nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* http://bitbucket.org/sdorra/scm-manager
*
*/
package sonia.scm.web;
//~--- non-JDK imports --------------------------------------------------------
import sonia.scm.io.RegexResourceProcessor;
import sonia.scm.io.ResourceProcessor;
import sonia.scm.repository.HgConfig;
import sonia.scm.util.IOUtil;
//~--- JDK imports ------------------------------------------------------------
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
/**
*
* @author Sebastian Sdorra
*/
public class HgWebConfigWriter
{
/** Field description */
public static final String CGI_TEMPLATE = "/sonia/scm/hgweb.py";
//~--- constructors ---------------------------------------------------------
/**
* Constructs ...
*
*
* @param config
*/
public HgWebConfigWriter(HgConfig config)
{
this.config = config;
}
//~--- methods --------------------------------------------------------------
/**
* Method description
*
*
*
* @throws IOException
*/
public void write() throws IOException
{
File cgiFile = HgUtil.getCGI();
writeCGIFile(cgiFile);
}
/**
* Method description
*
*
* @param cgiFile
*
* @throws IOException
*/
private void writeCGIFile(File cgiFile) throws IOException
{
InputStream input = null;
OutputStream output = null;
try
{
input = HgWebConfigWriter.class.getResourceAsStream(CGI_TEMPLATE);
output = new FileOutputStream(cgiFile);
ResourceProcessor rp = new RegexResourceProcessor();
rp.addVariable("python", config.getPythonBinary());
rp.process(input, output);
cgiFile.setExecutable(true);
}
finally
{
IOUtil.close(input);
IOUtil.close(output);
}
}
//~--- fields ---------------------------------------------------------------
/** Field description */
private HgConfig config;
}