improve windows support

This commit is contained in:
Sebastian Sdorra
2010-12-25 17:09:08 +01:00
parent 297d7f617d
commit 8bba333ac0
11 changed files with 774 additions and 52 deletions

View File

@@ -0,0 +1,92 @@
/**
* 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 sonia.scm.repository.HgConfig;
//~--- JDK imports ------------------------------------------------------------
import com.sun.jersey.api.json.JSONConfiguration;
import com.sun.jersey.api.json.JSONJAXBContext;
import javax.ws.rs.ext.ContextResolver;
import javax.ws.rs.ext.Provider;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
/**
*
* @author Sebastian Sdorra
*/
@Provider
public class HgJsonJaxbContextResolver implements ContextResolver<JAXBContext>
{
/**
* Constructs ...
*
*
* @throws JAXBException
*/
public HgJsonJaxbContextResolver() throws JAXBException
{
this.context = new JSONJAXBContext(
JSONConfiguration.mapped().rootUnwrapping(true).nonStrings(
"useOptimizedBytecode").build(), new Class[] { HgConfig.class });
}
//~--- get methods ----------------------------------------------------------
/**
* Method description
*
*
* @param type
*
* @return
*/
@Override
public JAXBContext getContext(Class<?> type)
{
return context;
}
//~--- fields ---------------------------------------------------------------
/** Field description */
private JAXBContext context;
}

View File

@@ -31,7 +31,7 @@
package sonia.scm.repository;
package sonia.scm.installer;
//~--- non-JDK imports --------------------------------------------------------
@@ -41,8 +41,10 @@ import org.slf4j.LoggerFactory;
import sonia.scm.io.Command;
import sonia.scm.io.CommandResult;
import sonia.scm.io.SimpleCommand;
import sonia.scm.repository.HgConfig;
import sonia.scm.repository.HgRepositoryHandler;
import sonia.scm.util.IOUtil;
import sonia.scm.web.HgWebConfigWriter;
import sonia.scm.util.SystemUtil;
//~--- JDK imports ------------------------------------------------------------
@@ -53,32 +55,15 @@ import java.io.IOException;
*
* @author Sebastian Sdorra
*/
public class HgInitialConfigBuilder
public abstract class AbstractHgInstaller implements HgInstaller
{
/** Field description */
public static final String DIRECTORY_REPOSITORY = "repositories";
/** Field description */
private static final String[] PATH = new String[]
{
// default path
"/usr/bin",
// manually installed
"/usr/local/bin",
// mac ports
"/opt/local/bin",
// opencsw
"/opt/csw/bin"
};
/** the logger for HgInitialConfigBuilder */
/** the logger for AbstractHgInstaller */
private static final Logger logger =
LoggerFactory.getLogger(HgInitialConfigBuilder.class);
LoggerFactory.getLogger(AbstractHgInstaller.class);
//~--- constructors ---------------------------------------------------------
@@ -88,7 +73,7 @@ public class HgInitialConfigBuilder
*
* @param baseDirectory
*/
public HgInitialConfigBuilder(File baseDirectory)
public AbstractHgInstaller(File baseDirectory)
{
this.baseDirectory = baseDirectory;
}
@@ -99,9 +84,12 @@ public class HgInitialConfigBuilder
* Method description
*
*
* @return
* @param config
*
* @throws IOException
*/
public HgConfig createInitialConfig()
@Override
public void install(HgConfig config) throws IOException
{
File repoDirectory = new File(
baseDirectory,
@@ -110,29 +98,19 @@ public class HgInitialConfigBuilder
IOUtil.mkdirs(repoDirectory);
config.setRepositoryDirectory(repoDirectory);
config.setHgBinary(search("hg"));
config.setPythonBinary(search("python"));
try {
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);
}
}
return config;
}
/**
* TODO check for windows
*
*
*
* @param path
* @param cmd
*
* @return
*/
public static String search(String cmd)
protected String search(String[] path, String cmd)
{
String cmdPath = null;
@@ -150,9 +128,18 @@ public class HgInitialConfigBuilder
if (cmdPath == null)
{
for (String pathPart : PATH)
for (String pathPart : path)
{
File file = new File(pathPart, cmd);
File file = null;
if (SystemUtil.isWindows())
{
file = new File(pathPart, cmd.concat(".exe"));
}
else
{
file = new File(pathPart, cmd);
}
if (file.exists())
{
@@ -181,8 +168,5 @@ public class HgInitialConfigBuilder
//~--- fields ---------------------------------------------------------------
/** Field description */
private File baseDirectory;
/** Field description */
private HgConfig config = new HgConfig();
protected File baseDirectory;
}

View File

@@ -0,0 +1,63 @@
/**
* 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 java.io.IOException;
import sonia.scm.repository.HgConfig;
/**
*
* @author Sebastian Sdorra
*/
public interface HgInstaller
{
/**
* Method description
*
*
* @param config
*/
public void install(HgConfig config) throws IOException;
/**
* Method description
*
*
* @param config
*/
public void update(HgConfig config) throws IOException;
}

View File

@@ -0,0 +1,115 @@
/**
* 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;
//~--- JDK imports ------------------------------------------------------------
import java.io.File;
/**
*
* @author Sebastian Sdorra
*/
public class UnixHgInstaller extends AbstractHgInstaller
{
/** Field description */
private static final String[] PATH = new String[]
{
// default path
"/usr/bin",
// manually installed
"/usr/local/bin",
// mac ports
"/opt/local/bin",
// opencsw
"/opt/csw/bin"
};
/** the logger for UnixHgInstaller */
private static final Logger logger =
LoggerFactory.getLogger(UnixHgInstaller.class);
//~--- constructors ---------------------------------------------------------
/**
* Constructs ...
*
*
* @param baseDirectory
*/
public UnixHgInstaller(File baseDirectory)
{
super(baseDirectory);
}
//~--- methods --------------------------------------------------------------
/**
* Method description
*
*
* @param config
*/
@Override
public void install(HgConfig config)
{
config.setHgBinary(search(PATH, "hg"));
config.setPythonBinary(search(PATH, "python"));
}
/**
* Method description
*
*
* @param config
*/
@Override
public void update(HgConfig config)
{
// do nothing
}
}

View File

@@ -0,0 +1,338 @@
/**
* 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.SimpleCommand;
import sonia.scm.io.SimpleCommandResult;
import sonia.scm.repository.HgConfig;
import sonia.scm.util.IOUtil;
import sonia.scm.util.Util;
//~--- JDK imports ------------------------------------------------------------
import java.io.File;
import java.io.FilenameFilter;
import java.io.IOException;
import java.util.Scanner;
/**
*
* @author Sebastian Sdorra
*/
public class WindowsHgInstaller extends AbstractHgInstaller
{
/** Field description */
public static String[] PATH_HG = new String[]
{
// TortoiseHg
"TortoiseHg\\hg.exe"
};
/** Field description */
public static String[] PATH_LIBRARY_ZIP = new String[]
{
// TortoiseHg
"TortoiseHg\\library.zip"
};
/** Field description */
public static String[] PATH_TEMPLATE = new String[]
{
// TortoiseHg
"TortoiseHg\\template"
};
/** Field description */
private static final String DEFAULT_PROGRAMMDIRECTORY =
"C:\\Programm Files\\";
/** the logger for WindowsHgInstaller */
private static final Logger logger =
LoggerFactory.getLogger(WindowsHgInstaller.class);
//~--- constructors ---------------------------------------------------------
/**
* Constructs ...
*
*
* @param baseDirectory
*/
public WindowsHgInstaller(File baseDirectory)
{
super(baseDirectory);
}
//~--- methods --------------------------------------------------------------
/**
* Method description
*
*
* @param config
*
* @throws IOException
*/
@Override
public void install(HgConfig config) throws IOException
{
super.install(config);
String progDir = getProgrammDirectory();
String path = null;
File libraryZip = find(progDir, PATH_LIBRARY_ZIP);
if (libraryZip != null)
{
File libDir = new File(baseDirectory, "lib\\hg");
IOUtil.extract(libraryZip, libDir);
path = libDir.getAbsolutePath();
}
File templateDir = find(progDir, PATH_TEMPLATE);
if (templateDir != null)
{
if (path != null)
{
path = path.concat(";").concat(templateDir.getAbsolutePath());
}
else
{
path = templateDir.getAbsolutePath();
}
}
if (path != null)
{
config.setPythonPath(path);
}
checkForOptimizedByteCode(config);
config.setPythonBinary(getPythonBinary());
}
/**
* Method description
*
*
* @param config
*/
@Override
public void update(HgConfig config) {}
/**
* 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 prefix
* @param path
*
* @return
*/
private File find(String prefix, String[] path)
{
File result = null;
for (String pathPart : path)
{
File file = new File(prefix, pathPart);
if (file.exists())
{
result = file;
break;
}
}
return result;
}
//~--- get methods ----------------------------------------------------------
/**
* Method description
*
*
* @return
*/
private String getProgrammDirectory()
{
return getRegistryValue(
"HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion",
"ProgramFilesDir", DEFAULT_PROGRAMMDIRECTORY);
}
/**
* Method description
*
*
* @return
*/
private String getPythonBinary()
{
String python =
getRegistryValue(
"HKEY_CLASSES_ROOT\\Python.File\\shell\\open\\command", null, null);
if (python == null)
{
python = search(new String[0], "python");
}
return python;
}
/**
* Method description
*
*
* @param key
* @param subKey
* @param defaultValue
*
* @return
*/
private String getRegistryValue(String key, String subKey,
String defaultValue)
{
String programmDirectory = defaultValue;
SimpleCommand command = null;
if (subKey != null)
{
command = new SimpleCommand("reg", "query", key, "/v", subKey);
}
else
{
command = new SimpleCommand("reg", "query", key);
}
try
{
SimpleCommandResult result = command.execute();
if (result.isSuccessfull())
{
String output = result.getOutput();
Scanner scanner = new Scanner(output);
while (scanner.hasNextLine())
{
String line = scanner.nextLine();
int index = line.indexOf("REG_SZ");
if (index > 0)
{
programmDirectory = line.substring(index
+ "REG_SZ".length()).trim();
if (logger.isDebugEnabled())
{
logger.debug("use programm directory {}", programmDirectory);
}
}
}
}
}
catch (IOException ex)
{
logger.error(ex.getMessage(), ex);
}
return programmDirectory;
}
}

View File

@@ -90,6 +90,17 @@ public class HgConfig extends SimpleRepositoryConfig
return pythonPath;
}
/**
* Method description
*
*
* @return
*/
public boolean isUseOptimizedBytecode()
{
return useOptimizedBytecode;
}
/**
* Method description
*
@@ -138,6 +149,17 @@ public class HgConfig extends SimpleRepositoryConfig
this.pythonPath = pythonPath;
}
/**
* Method description
*
*
* @param useOptimizedBytecode
*/
public void setUseOptimizedBytecode(boolean useOptimizedBytecode)
{
this.useOptimizedBytecode = useOptimizedBytecode;
}
//~--- fields ---------------------------------------------------------------
/** Field description */
@@ -148,4 +170,7 @@ public class HgConfig extends SimpleRepositoryConfig
/** Field description */
private String pythonPath = "";
/** Field description */
private boolean useOptimizedBytecode = false;
}

View File

@@ -38,13 +38,20 @@ package sonia.scm.repository;
import com.google.inject.Inject;
import com.google.inject.Singleton;
import org.slf4j.LoggerFactory;
import sonia.scm.Type;
import sonia.scm.installer.HgInstaller;
import sonia.scm.installer.UnixHgInstaller;
import sonia.scm.installer.WindowsHgInstaller;
import sonia.scm.io.ExtendedCommand;
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.SystemUtil;
import sonia.scm.web.HgWebConfigWriter;
//~--- JDK imports ------------------------------------------------------------
@@ -70,6 +77,10 @@ public class HgRepositoryHandler
/** Field description */
public static final Type TYPE = new Type(TYPE_NAME, TYPE_DISPLAYNAME);
/** the logger for HgRepositoryHandler */
private static final org.slf4j.Logger logger =
LoggerFactory.getLogger(HgRepositoryHandler.class);
//~--- constructors ---------------------------------------------------------
/**
@@ -95,11 +106,61 @@ public class HgRepositoryHandler
{
super.loadConfig();
HgInstaller installer = null;
if (SystemUtil.isWindows())
{
installer = new WindowsHgInstaller(baseDirectory);
}
else
{
installer = new UnixHgInstaller(baseDirectory);
}
if (config == null)
{
config = new HgInitialConfigBuilder(baseDirectory).createInitialConfig();
storeConfig();
config = new HgConfig();
try
{
if (logger.isDebugEnabled())
{
logger.debug("installing mercurial with {}",
installer.getClass().getName());
}
installer.install(config);
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);
}
}
}
else
{
try
{
if (logger.isDebugEnabled())
{
logger.debug("update mercurial with {}",
installer.getClass().getName());
}
installer.update(config);
}
catch (IOException ex)
{
logger.error(ex.getMessage(), ex);
}
}
storeConfig();
}
//~--- get methods ----------------------------------------------------------

View File

@@ -177,7 +177,14 @@ public class HgCGIServlet extends AbstractCGIServlet
AssertUtil.assertIsNotNull(config);
return config.getPythonBinary();
String python = config.getPythonBinary();
if ((python != null) && config.isUseOptimizedBytecode())
{
python = python.concat(" -O");
}
return python;
}
/**