From 5e815cecc05409598feca0df882be838e8bf798e Mon Sep 17 00:00:00 2001 From: Sebastian Sdorra Date: Sat, 11 Aug 2012 15:40:38 +0200 Subject: [PATCH] fix defect hg.bat from package installation --- .../scm/installer/HgPackageInstaller.java | 10 +- .../java/sonia/scm/repository/HgBatFix.java | 258 ++++++++++++++++++ .../scm/repository/HgRepositoryHandler.java | 7 + .../src/main/java/sonia/scm/web/HgUtil.java | 17 +- .../sonia/scm/repository/HgBatFixTest.java | 154 +++++++++++ .../resources/sonia/scm/repository/hg.bat.01 | 35 +++ .../resources/sonia/scm/repository/hg.bat.02 | 38 +++ .../resources/sonia/scm/repository/hg.bat.03 | 38 +++ 8 files changed, 548 insertions(+), 9 deletions(-) create mode 100644 scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/HgBatFix.java create mode 100644 scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/repository/HgBatFixTest.java create mode 100644 scm-plugins/scm-hg-plugin/src/test/resources/sonia/scm/repository/hg.bat.01 create mode 100644 scm-plugins/scm-hg-plugin/src/test/resources/sonia/scm/repository/hg.bat.02 create mode 100644 scm-plugins/scm-hg-plugin/src/test/resources/sonia/scm/repository/hg.bat.03 diff --git a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/installer/HgPackageInstaller.java b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/installer/HgPackageInstaller.java index 558970b67c..f004ad170f 100644 --- a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/installer/HgPackageInstaller.java +++ b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/installer/HgPackageInstaller.java @@ -38,8 +38,10 @@ package sonia.scm.installer; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import sonia.scm.SCMContext; import sonia.scm.io.ZipUnArchiver; import sonia.scm.net.HttpClient; +import sonia.scm.repository.HgBatFix; import sonia.scm.repository.HgConfig; import sonia.scm.repository.HgRepositoryHandler; import sonia.scm.util.IOUtil; @@ -79,7 +81,7 @@ public class HgPackageInstaller implements Runnable * @param pkg */ public HgPackageInstaller(HttpClient client, HgRepositoryHandler handler, - File baseDirectory, HgPackage pkg) + File baseDirectory, HgPackage pkg) { this.client = client; this.handler = handler; @@ -181,7 +183,7 @@ public class HgPackageInstaller implements Runnable private File extractPackage(File file) { File directory = new File(baseDirectory, - "pkg".concat(File.separator).concat(pkg.getId())); + "pkg".concat(File.separator).concat(pkg.getId())); IOUtil.mkdirs(directory); @@ -227,6 +229,10 @@ public class HgPackageInstaller implements Runnable config.setPythonBinary(getTemplateValue(template.getPythonBinary(), path)); config.setPythonPath(getTemplateValue(template.getPythonPath(), path)); config.setUseOptimizedBytecode(template.isUseOptimizedBytecode()); + + // fix wrong hg.bat + HgBatFix.fixHgBat(SCMContext.getContext(), config); + handler.storeConfig(); } diff --git a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/HgBatFix.java b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/HgBatFix.java new file mode 100644 index 0000000000..46f1bc8b22 --- /dev/null +++ b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/HgBatFix.java @@ -0,0 +1,258 @@ +/** + * 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.common.base.Charsets; +import com.google.common.io.Closeables; +import com.google.common.io.Files; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import sonia.scm.SCMContextProvider; +import sonia.scm.web.HgUtil; + +//~--- JDK imports ------------------------------------------------------------ + +import java.io.BufferedReader; +import java.io.BufferedWriter; +import java.io.File; +import java.io.IOException; + +/** + * + * @author Sebastian Sdorra + */ +public class HgBatFix +{ + + /** Field description */ + static final String MODIFY_MARK = ".setbinary"; + + /** Field description */ + private static final String HG_BAT = "hg.bat"; + + /** + * the logger for HgUtil + */ + private static final Logger logger = LoggerFactory.getLogger(HgUtil.class); + + //~--- methods -------------------------------------------------------------- + + /** + * Method description + * + * + * @param context + * @param config + */ + public static void fixHgBat(SCMContextProvider context, HgConfig config) + { + String basePath = context.getBaseDirectory().getAbsolutePath(); + + String hg = config.getHgBinary(); + + if (hg.startsWith(basePath) && hg.endsWith(HG_BAT)) + { + + fixHgBat(hg); + } + } + + /** + * Visible for testing + * + * + * @param hg + */ + static void fixHgBat(String hg) + { + File hgBat = new File(hg); + + if (hgBat.exists()) + { + + File binDirectory = hgBat.getParentFile(); + File modifyMark = new File(binDirectory, MODIFY_MARK); + + if (!modifyMark.exists()) + { + if (logger.isDebugEnabled()) + { + logger.debug("check hg.bat for setbinary at {}", hg); + } + + if (!isSetBinaryAvailable(hgBat)) + { + injectSetBinary(hgBat); + } + else + { + createModifyMark(modifyMark); + } + } + else if (logger.isDebugEnabled()) + { + logger.debug("hg.bat allready fixed"); + } + + } + else if (logger.isWarnEnabled()) + { + logger.warn("could not find hg.bat at {}", hg); + } + } + + //~--- get methods ---------------------------------------------------------- + + /** + * Visible for testing + * + * + * @param hg + * + * @return + */ + static boolean isSetBinaryAvailable(File hg) + { + boolean setBinaryAvailable = false; + + BufferedReader reader = null; + + try + { + reader = Files.newReader(hg, Charsets.UTF_8); + + String line = reader.readLine(); + + while (line != null) + { + line = line.trim(); + + if (line.contains("mercurial.util.setbinary") &&!line.startsWith("#")) + { + setBinaryAvailable = true; + + break; + } + + line = reader.readLine(); + } + } + catch (IOException ex) + { + logger.error("could not check hg.bat", ex); + } + finally + { + Closeables.closeQuietly(reader); + } + + return setBinaryAvailable; + } + + //~--- methods -------------------------------------------------------------- + + /** + * Method description + * + * + * @param modifyMark + */ + private static void createModifyMark(File modifyMark) + { + try + { + if (!modifyMark.createNewFile()) + { + throw new RuntimeException("could not create modify mark"); + } + } + catch (IOException ex) + { + throw new RuntimeException("could not create modify mark", ex); + } + } + + /** + * Method description + * + * + * @param hg + */ + private static void injectSetBinary(File hg) + { + String lineSeparator = System.getProperty("line.separator"); + File mod = new File(hg.getParentFile(), MODIFY_MARK); + + hg.renameTo(mod); + + BufferedWriter writer = null; + BufferedReader reader = null; + + try + { + writer = Files.newWriter(hg, Charsets.UTF_8); + reader = Files.newReader(mod, Charsets.UTF_8); + + String line = reader.readLine(); + + while (line != null) + { + + if (line.trim().equals("mercurial.dispatch.run()")) + { + writer.write("for fp in (sys.stdin, sys.stdout, sys.stderr):"); + writer.write(lineSeparator); + writer.write(" mercurial.util.setbinary(fp)"); + writer.write(lineSeparator); + writer.write(lineSeparator); + } + + writer.write(line); + writer.write(lineSeparator); + line = reader.readLine(); + } + } + catch (IOException ex) + { + logger.error("could not check hg.bat", ex); + } + finally + { + Closeables.closeQuietly(reader); + Closeables.closeQuietly(writer); + } + } +} diff --git a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/HgRepositoryHandler.java b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/HgRepositoryHandler.java index 59d78efb06..76e6f8aa09 100644 --- a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/HgRepositoryHandler.java +++ b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/HgRepositoryHandler.java @@ -59,6 +59,7 @@ import sonia.scm.repository.spi.HgRepositoryServiceProvider; import sonia.scm.store.StoreFactory; import sonia.scm.util.AssertUtil; import sonia.scm.util.IOUtil; +import sonia.scm.util.SystemUtil; import sonia.scm.util.Util; //~--- JDK imports ------------------------------------------------------------ @@ -185,6 +186,12 @@ public class HgRepositoryHandler super.init(context); registerMissingHooks(); writePythonScripts(context); + + // fix wrong hg.bat from package installation + if (SystemUtil.isWindows()) + { + HgBatFix.fixHgBat(context, getConfig()); + } } /** diff --git a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgUtil.java b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgUtil.java index eebda80e53..aa86779b7c 100644 --- a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgUtil.java +++ b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/web/HgUtil.java @@ -35,12 +35,15 @@ package sonia.scm.web; //~--- non-JDK imports -------------------------------------------------------- -import java.io.File; import sonia.scm.SCMContext; import sonia.scm.repository.HgConfig; import sonia.scm.repository.HgPythonScript; import sonia.scm.util.Util; +//~--- JDK imports ------------------------------------------------------------ + +import java.io.File; + /** * * @author Sebastian Sdorra @@ -64,8 +67,8 @@ public class HgUtil public static String getPythonPath(HgConfig config) { String pythonPath = Util.EMPTY_STRING; - - if ( config != null ) + + if (config != null) { pythonPath = Util.nonNull(config.getPythonPath()); } @@ -82,10 +85,10 @@ public class HgUtil ).getAbsolutePath() ); //J+ - + return pythonPath; } - + /** * Method description * @@ -97,7 +100,7 @@ public class HgUtil public static String getRevision(String revision) { return Util.isEmpty(revision) - ? REVISION_TIP - : revision; + ? REVISION_TIP + : revision; } } diff --git a/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/repository/HgBatFixTest.java b/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/repository/HgBatFixTest.java new file mode 100644 index 0000000000..4b54265dd7 --- /dev/null +++ b/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/repository/HgBatFixTest.java @@ -0,0 +1,154 @@ +/** + * 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.common.io.Closeables; +import com.google.common.io.Resources; + +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.TemporaryFolder; + +import static org.junit.Assert.*; + +//~--- JDK imports ------------------------------------------------------------ + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; + +import java.net.URL; + +/** + * + * @author Sebastian Sdorra + */ +public class HgBatFixTest +{ + + /** + * Method description + * + * + * @throws IOException + */ + @Test + public void testHgBatModify() throws IOException + { + testModify(createHgBat("01")); + + } + + /** + * Method description + * + * + * @throws IOException + */ + @Test + public void testHgBatModifyWithComment() throws IOException + { + testModify(createHgBat("02")); + } + + /** + * Method description + * + * + * @throws IOException + */ + @Test + public void testHgBatWithoutModify() throws IOException + { + long length = testModify(createHgBat("03")).length(); + + assertEquals(0, length); + } + + /** + * Method description + * + * + * @param number + * + * @return + * + * @throws IOException + */ + private File createHgBat(String number) throws IOException + { + URL url = + Resources.getResource("sonia/scm/repository/hg.bat.".concat(number)); + File file = tempFolder.newFile(number); + FileOutputStream fos = null; + + try + { + fos = new FileOutputStream(file); + Resources.copy(url, fos); + } + finally + { + Closeables.closeQuietly(fos); + } + + return file; + } + + /** + * Method description + * + * + * @param file + * + * @return + */ + private File testModify(File file) + { + HgBatFix.fixHgBat(file.getAbsolutePath()); + assertTrue(HgBatFix.isSetBinaryAvailable(file)); + + File mod = new File(file.getParentFile(), HgBatFix.MODIFY_MARK); + + assertTrue(mod.exists()); + + return mod; + } + + //~--- fields --------------------------------------------------------------- + + /** Field description */ + @Rule + public TemporaryFolder tempFolder = new TemporaryFolder(); +} diff --git a/scm-plugins/scm-hg-plugin/src/test/resources/sonia/scm/repository/hg.bat.01 b/scm-plugins/scm-hg-plugin/src/test/resources/sonia/scm/repository/hg.bat.01 new file mode 100644 index 0000000000..0ef012be1d --- /dev/null +++ b/scm-plugins/scm-hg-plugin/src/test/resources/sonia/scm/repository/hg.bat.01 @@ -0,0 +1,35 @@ +#!/usr/bin/env python +# +# mercurial - scalable distributed SCM +# +# Copyright 2005-2007 Matt Mackall +# +# This software may be used and distributed according to the terms of the +# GNU General Public License version 2 or any later version. + +import os +import sys + +libdir = '@LIBDIR@' + +if libdir != '@' 'LIBDIR' '@': + if not os.path.isabs(libdir): + libdir = os.path.join(os.path.dirname(os.path.realpath(__file__)), + libdir) + libdir = os.path.abspath(libdir) + sys.path.insert(0, libdir) + +# enable importing on demand to reduce startup time +try: + from mercurial import demandimport; demandimport.enable() +except ImportError: + import sys + sys.stderr.write("abort: couldn't find mercurial libraries in [%s]\n" % + ' '.join(sys.path)) + sys.stderr.write("(check your install and PYTHONPATH)\n") + sys.exit(-1) + +import mercurial.util +import mercurial.dispatch + +mercurial.dispatch.run() \ No newline at end of file diff --git a/scm-plugins/scm-hg-plugin/src/test/resources/sonia/scm/repository/hg.bat.02 b/scm-plugins/scm-hg-plugin/src/test/resources/sonia/scm/repository/hg.bat.02 new file mode 100644 index 0000000000..2d0a4c59e1 --- /dev/null +++ b/scm-plugins/scm-hg-plugin/src/test/resources/sonia/scm/repository/hg.bat.02 @@ -0,0 +1,38 @@ +#!/usr/bin/env python +# +# mercurial - scalable distributed SCM +# +# Copyright 2005-2007 Matt Mackall +# +# This software may be used and distributed according to the terms of the +# GNU General Public License version 2 or any later version. + +import os +import sys + +libdir = '@LIBDIR@' + +if libdir != '@' 'LIBDIR' '@': + if not os.path.isabs(libdir): + libdir = os.path.join(os.path.dirname(os.path.realpath(__file__)), + libdir) + libdir = os.path.abspath(libdir) + sys.path.insert(0, libdir) + +# enable importing on demand to reduce startup time +try: + from mercurial import demandimport; demandimport.enable() +except ImportError: + import sys + sys.stderr.write("abort: couldn't find mercurial libraries in [%s]\n" % + ' '.join(sys.path)) + sys.stderr.write("(check your install and PYTHONPATH)\n") + sys.exit(-1) + +import mercurial.util +import mercurial.dispatch + +#for fp in (sys.stdin, sys.stdout, sys.stderr): +# mercurial.util.setbinary(fp) + +mercurial.dispatch.run() \ No newline at end of file diff --git a/scm-plugins/scm-hg-plugin/src/test/resources/sonia/scm/repository/hg.bat.03 b/scm-plugins/scm-hg-plugin/src/test/resources/sonia/scm/repository/hg.bat.03 new file mode 100644 index 0000000000..7083d40566 --- /dev/null +++ b/scm-plugins/scm-hg-plugin/src/test/resources/sonia/scm/repository/hg.bat.03 @@ -0,0 +1,38 @@ +#!/usr/bin/env python +# +# mercurial - scalable distributed SCM +# +# Copyright 2005-2007 Matt Mackall +# +# This software may be used and distributed according to the terms of the +# GNU General Public License version 2 or any later version. + +import os +import sys + +libdir = '@LIBDIR@' + +if libdir != '@' 'LIBDIR' '@': + if not os.path.isabs(libdir): + libdir = os.path.join(os.path.dirname(os.path.realpath(__file__)), + libdir) + libdir = os.path.abspath(libdir) + sys.path.insert(0, libdir) + +# enable importing on demand to reduce startup time +try: + from mercurial import demandimport; demandimport.enable() +except ImportError: + import sys + sys.stderr.write("abort: couldn't find mercurial libraries in [%s]\n" % + ' '.join(sys.path)) + sys.stderr.write("(check your install and PYTHONPATH)\n") + sys.exit(-1) + +import mercurial.util +import mercurial.dispatch + +for fp in (sys.stdin, sys.stdout, sys.stderr): + mercurial.util.setbinary(fp) + +mercurial.dispatch.run() \ No newline at end of file