Java tutorial
/* * This library is part of OpenCms - * the Open Source Content Management System * * Copyright (c) Alkacon Software GmbH & Co. KG (http://www.alkacon.com) * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * For further information about Alkacon Software, please see the * company website: http://www.alkacon.com * * For further information about OpenCms, please see the * project website: http://www.opencms.org * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package org.opencms.workplace.tools.git; import org.opencms.configuration.CmsConfigurationException; import org.opencms.file.CmsObject; import org.opencms.importexport.CmsImportExportException; import org.opencms.importexport.CmsImportParameters; import org.opencms.main.CmsException; import org.opencms.main.CmsLog; import org.opencms.main.OpenCms; import org.opencms.module.CmsModule; import org.opencms.module.CmsModuleImportExportHandler; import org.opencms.module.CmsModuleManager; import org.opencms.report.CmsPrintStreamReport; import org.opencms.report.I_CmsReport; import org.opencms.security.CmsRoleViolationException; import org.opencms.util.CmsFileUtil; import org.opencms.util.CmsFileUtil.FileWalkState; import org.opencms.util.CmsStringUtil; import org.opencms.xml.CmsXmlEntityResolver; import org.opencms.xml.CmsXmlUtils; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; import java.io.PrintStream; import java.lang.ProcessBuilder.Redirect; import java.nio.file.Paths; import java.util.Collection; import java.util.Date; import java.util.HashSet; import java.util.LinkedList; import java.util.List; import java.util.Set; import java.util.zip.ZipEntry; import java.util.zip.ZipOutputStream; import org.apache.commons.collections.Closure; import org.apache.commons.logging.Log; import org.dom4j.Document; import org.dom4j.Node; import com.google.common.collect.HashMultimap; import com.google.common.collect.Lists; import com.google.common.collect.Multimap; import com.google.common.collect.Sets; /** The class provides methods to automatically export modules from OpenCms and check in the exported, * unzipped modules into some git repository. * The feature is only available under Linux at the moment. It uses a shell script. * Which modules are exported to and checked in to which git repository is configured in the file * <code>/WEB-INF/git-scripts/module-checkin.sh</code>. * */ public class CmsGitCheckin { /** The log file for the git check in. */ private static final String DEFAULT_LOGFILE_PATH = OpenCms.getSystemInfo().getWebInfRfsPath() + "logs/git.log"; /** The variable under which the export path is set. */ /** The default path to the script. */ private static final String DEFAULT_RFS_PATH = OpenCms.getSystemInfo().getWebInfRfsPath() + "git-scripts/"; /** The default folder for configuration files. */ private static final String DEFAULT_CONFIG_FOLDER = DEFAULT_RFS_PATH + "config/"; /** The default script file used for the git check in. */ private static final String DEFAULT_SCRIPT_FILE = DEFAULT_RFS_PATH + "module-checkin.sh"; /** The default configuration file used for the git check in. */ private static final String DEFAULT_CONFIG_FILE = DEFAULT_RFS_PATH + "module-checkin.conf"; /** Logger instance for this class. */ private static final Log LOG = CmsLog.getLog(CmsGitCheckin.class); /** Lock used to prevent simultaneous execution of checkIn method. */ private static final Object STATIC_LOCK = new Object(); /** Flag, indicating if an automatic pull should be performed after commit. */ private Boolean m_autoPullAfter; /** Flag, indicating if an automatic pull should be performed first. */ private Boolean m_autoPullBefore; /** Flag, indicating if an automatic push should be performed in the end. */ private Boolean m_autoPush; /** The checkout flag. */ private boolean m_checkout; /** The CMS context. */ private CmsObject m_cms; /** The commit message. */ private String m_commitMessage; /** Flag, indicating if modules should be exported and unzipped. */ private Boolean m_copyAndUnzip; /** The commit mode. */ private Boolean m_commitMode; /** Fetch and reset option. */ private boolean m_fetchAndResetBeforeImport; /** Stream for the log file. */ private PrintStream m_logStream; /** The modules that should really be exported and checked in. */ private Collection<String> m_modulesToExport; /** Flag, indicating if reset on HEAD should be performed. */ private boolean m_resetHead; /** Flag, indicating if reset on ${origin}/${branch} should be performed. */ private boolean m_resetRemoteHead; /** Flag, indicating if the lib/ folder of the modules should be deleted before the commit. */ private Boolean m_excludeLibs; /** The git user email. */ private String m_gitUserEmail; /** The git user name. */ private String m_gitUserName; /** Flag, indicating if execution of the script should go on for an unclean repository. */ private Boolean m_ignoreUnclean; /** The current configuration. */ private CmsGitConfiguration m_currentConfiguration; /** The available configurations. */ private List<CmsGitConfiguration> m_configurations = new LinkedList<CmsGitConfiguration>(); /** * Default constructor. Initializing member variables with default values. * * @param cms the CMS context to use */ public CmsGitCheckin(CmsObject cms) { m_cms = cms; m_configurations = readConfigFiles(); for (CmsGitConfiguration config : m_configurations) { if (config.isValid()) { m_currentConfiguration = config; break; } } } /** * Creates ZIP file data from the files / subfolders of the given root folder, and sends it to the given stream.<p> * * The stream passed as an argument is closed after the data is written. * * @param root the folder to zip * @param zipOutput the output stream which the zip file data should be written to * * @throws Exception if something goes wrong */ public static void zipRfsFolder(final File root, final OutputStream zipOutput) throws Exception { final ZipOutputStream zip = new ZipOutputStream(zipOutput); try { CmsFileUtil.walkFileSystem(root, new Closure() { @SuppressWarnings("resource") public void execute(Object stateObj) { try { FileWalkState state = (FileWalkState) stateObj; for (File file : state.getFiles()) { String relativePath = Paths.get(root.getAbsolutePath()) .relativize(Paths.get(file.getAbsolutePath())).toString(); ZipEntry entry = new ZipEntry(relativePath); entry.setTime(file.lastModified()); zip.putNextEntry(entry); zip.write(CmsFileUtil.readFully(new FileInputStream(file))); zip.closeEntry(); } } catch (Exception e) { throw new RuntimeException(e); } } }); } catch (RuntimeException e) { if (e.getCause() instanceof Exception) { throw (Exception) (e.getCause()); } else { throw e; } } zip.flush(); zip.close(); } /** Adds a module to the modules that should be exported. * If called at least once, the explicitly added modules will be exported * instead of the default modules. * * @param moduleName the name of the module to export. */ public void addModuleToExport(final String moduleName) { if (m_modulesToExport == null) { m_modulesToExport = new HashSet<String>(); } m_modulesToExport.add(moduleName); } /** * Start export and check in of the selected modules. * @return The exit code of the check in procedure (like a script's exit code). */ public int checkIn() { try { synchronized (STATIC_LOCK) { m_logStream = new PrintStream(new FileOutputStream(DEFAULT_LOGFILE_PATH, false)); CmsObject cms = getCmsObject(); if (cms != null) { return checkInInternal(); } else { m_logStream.println("No CmsObject given. Did you call init() first?"); return -1; } } } catch (FileNotFoundException e) { e.printStackTrace(); return -2; } } /** * Clears the selected modules.<p> */ public void clearModules() { if (m_modulesToExport != null) { m_modulesToExport.clear(); } } /** * Gets the checkout flag.<p> * * @return the checkout flag */ public boolean getCheckout() { return m_checkout; } /** * Gets the CMS context.<p> * * @return the CMS context */ public CmsObject getCmsObject() { return m_cms; } /** * Returns the commitMessage.<p> * * @return the commitMessage */ public String getCommitMessage() { return m_commitMessage; } /** Returns the available configurations. * @return the available configurations. */ public Collection<CmsGitConfiguration> getConfigurations() { return m_configurations; } /** * Returns the currently used configuration. * @return the currently used configuration. */ public CmsGitConfiguration getCurrentConfiguration() { return m_currentConfiguration; } /** * Returns the gitUserEmail.<p> * * @return the gitUserEmail */ public String getGitUserEmail() { return m_gitUserEmail; } /** * Returns the gitUserName.<p> * * @return the gitUserName */ public String getGitUserName() { return m_gitUserName; } /** Returns the collection of all installed modules. * * @return the collection of all installed modules. */ public Collection<String> getInstalledModules() { return OpenCms.getModuleManager().getModuleNames(); } /** Returns the path to the log file. * @return the path to the log file. */ public String getLogFilePath() { return DEFAULT_LOGFILE_PATH; } /** * Gets the log text.<p> * * @return the log text */ @SuppressWarnings("resource") public String getLogText() { try { String logFilePath = getLogFilePath(); byte[] logData = CmsFileUtil.readFully(new FileInputStream(logFilePath)); return new String(logData, "UTF-8"); } catch (@SuppressWarnings("unused") IOException e) { return "Error reading log file: " + getLogFilePath(); } } /** * Returns true if at least one valid configuration is present. * @return true if at least one valid configuration is present. */ public boolean hasValidConfiguration() { return !m_configurations.isEmpty(); } /** * Returns true if the 'fetch and reset' flag is set.<p> * * @return true if 'fetch and reset' flag is set */ public boolean isFetchAndResetBeforeImport() { return m_fetchAndResetBeforeImport; } /** Tests if a module is installed. * @param moduleName name of the module to check. * @return Flag, indicating if the module is installed. */ public boolean isModuleInstalled(final String moduleName) { return (OpenCms.getModuleManager().getModule(moduleName) != null); } /** * Sets the checkout flag.<p> * * @param checkout the checkout flag */ public void setCheckout(boolean checkout) { m_checkout = checkout; } /** Setter for the commit mode. * @param autoCommit the commit mode to set. */ public void setCommit(final boolean autoCommit) { m_commitMode = Boolean.valueOf(autoCommit); } /** Setter for the commit message. * @param message the commit message to set. */ public void setCommitMessage(final String message) { m_commitMessage = message; } /** Setter for the copy and unzip mode. * @param copyAndUnzip the copy and unzip mode to set. */ public void setCopyAndUnzip(final boolean copyAndUnzip) { m_copyAndUnzip = Boolean.valueOf(copyAndUnzip); } /** * Sets the current configuration if it is a valid configuration. Otherwise the configuration is not set. * @param configuration the configuration to set. * @return flag, indicating if the configuration is set. */ public boolean setCurrentConfiguration(CmsGitConfiguration configuration) { if ((null != configuration) && configuration.isValid()) { m_currentConfiguration = configuration; return true; } return false; } /** Setter for the exclude libs flag. * @param excludeLibs flag, indicating if the lib/ folder of the modules should be deleted before the commit. */ public void setExcludeLibs(final boolean excludeLibs) { m_excludeLibs = Boolean.valueOf(excludeLibs); } /** * Sets the 'fetch and reset' flag.<p> * * If this flag is set, the script will be used to fetch the remote branch and reset the current branch to the remote state before * trying to import the modules.<p> * * @param fetchAndReset the 'fetch and reset' flag */ public void setFetchAndResetBeforeImport(boolean fetchAndReset) { m_fetchAndResetBeforeImport = fetchAndReset; } /** Setter for the git user email. * @param useremail the git user email to set. */ public void setGitUserEmail(final String useremail) { m_gitUserEmail = useremail; } /** Setter for the git user name. * @param username the git user name to set. */ public void setGitUserName(final String username) { m_gitUserName = username; } /** Setter for the ignore-unclean flag. * @param ignore flag, indicating if an unclean repository should be ignored. */ public void setIgnoreUnclean(final boolean ignore) { m_ignoreUnclean = Boolean.valueOf(ignore); } /** Setter for the pull-after flag. * @param autoPull flag, indicating if a pull should be performed directly after the commit. */ public void setPullAfter(final boolean autoPull) { m_autoPullAfter = Boolean.valueOf(autoPull); } /** Setter for the pull-before flag. * @param autoPull flag, indicating if a pull should be performed first. */ public void setPullBefore(final boolean autoPull) { m_autoPullBefore = Boolean.valueOf(autoPull); } /** Setter for the auto-push flag. * @param autoPush flag, indicating if a push should be performed in the end. */ public void setPush(final boolean autoPush) { m_autoPush = Boolean.valueOf(autoPush); } /** Setter for the reset-head flag. * @param reset flag, indicating if a reset to the HEAD should be performed or not. */ public void setResetHead(final boolean reset) { m_resetHead = reset; } /** Setter for the reset-remote-head flag. * @param reset flag, indicating if a reset to the ${origin}/${branch} should be performed or not. */ public void setResetRemoteHead(final boolean reset) { m_resetRemoteHead = reset; } /** * Adds the configuration from <code>configFile</code> to the {@link Collection} of {@link CmsGitConfiguration}, * if a valid configuration is read. Otherwise it logs the failure. * @param configurations Collection of configurations where the new configuration should be added. * @param configFile file to read the new configuration from. */ private void addConfigurationIfValid(final Collection<CmsGitConfiguration> configurations, final File configFile) { CmsGitConfiguration config = null; try { if (configFile.isFile()) { config = new CmsGitConfiguration(configFile); if (config.isValid()) { configurations.add(config); } else { throw new Exception("Could not read git configuration file" + config.getConfigurationFile().getAbsolutePath()); } } } catch (NullPointerException npe) { LOG.error("Could not read git configuration.", npe); } catch (Exception e) { String file = (null != config) && (null != config.getConfigurationFile()) && (null != config.getConfigurationFile().getAbsolutePath()) ? config.getConfigurationFile().getAbsolutePath() : "<unknown>"; LOG.warn("Trying to read invalid git configuration from " + file + ".", e); } } /** * Export modules and check them in. Assumes the log stream already open. * @return exit code of the commit-script. */ private int checkInInternal() { m_logStream.println("[" + new Date() + "] STARTING Git task"); m_logStream.println("========================="); m_logStream.println(); if (m_checkout) { m_logStream.println("Running checkout script"); } else if (!(m_resetHead || m_resetRemoteHead)) { m_logStream.println("Exporting relevant modules"); m_logStream.println("--------------------------"); m_logStream.println(); exportModules(); m_logStream.println(); m_logStream.println("Calling script to check in the exports"); m_logStream.println("--------------------------------------"); m_logStream.println(); } else { m_logStream.println(); m_logStream.println("Calling script to reset the repository"); m_logStream.println("--------------------------------------"); m_logStream.println(); } int exitCode = runCommitScript(); if (exitCode != 0) { m_logStream.println(); m_logStream.println("ERROR: Something went wrong. The script got exitcode " + exitCode + "."); m_logStream.println(); } if ((exitCode == 0) && m_checkout) { boolean importOk = importModules(); if (!importOk) { return -1; } } m_logStream.println("[" + new Date() + "] FINISHED Git task"); m_logStream.println(); m_logStream.close(); return exitCode; } /** Returns the command to run by the shell to normally run the checkin script. * @return the command to run by the shell to normally run the checkin script. */ private String checkinScriptCommand() { String exportModules = ""; if ((m_modulesToExport != null) && !m_modulesToExport.isEmpty()) { StringBuffer exportModulesParam = new StringBuffer(); for (String moduleName : m_modulesToExport) { exportModulesParam.append(" ").append(moduleName); } exportModulesParam.replace(0, 1, " \""); exportModulesParam.append("\" "); exportModules = " --modules " + exportModulesParam.toString(); } String commitMessage = ""; if (m_commitMessage != null) { commitMessage = " -msg \"" + m_commitMessage.replace("\"", "\\\"") + "\""; } String gitUserName = ""; if (m_gitUserName != null) { if (m_gitUserName.trim().isEmpty()) { gitUserName = " --ignore-default-git-user-name"; } else { gitUserName = " --git-user-name \"" + m_gitUserName + "\""; } } String gitUserEmail = ""; if (m_gitUserEmail != null) { if (m_gitUserEmail.trim().isEmpty()) { gitUserEmail = " --ignore-default-git-user-email"; } else { gitUserEmail = " --git-user-email \"" + m_gitUserEmail + "\""; } } String autoPullBefore = ""; if (m_autoPullBefore != null) { autoPullBefore = m_autoPullBefore.booleanValue() ? " --pull-before " : " --no-pull-before"; } String autoPullAfter = ""; if (m_autoPullAfter != null) { autoPullAfter = m_autoPullAfter.booleanValue() ? " --pull-after " : " --no-pull-after"; } String autoPush = ""; if (m_autoPush != null) { autoPush = m_autoPush.booleanValue() ? " --push " : " --no-push"; } String exportFolder = " --export-folder \"" + m_currentConfiguration.getModuleExportPath() + "\""; String exportMode = " --export-mode " + m_currentConfiguration.getExportMode(); String excludeLibs = ""; if (m_excludeLibs != null) { excludeLibs = m_excludeLibs.booleanValue() ? " --exclude-libs" : " --no-exclude-libs"; } String commitMode = ""; if (m_commitMode != null) { commitMode = m_commitMode.booleanValue() ? " --commit" : " --no-commit"; } String ignoreUncleanMode = ""; if (m_ignoreUnclean != null) { ignoreUncleanMode = m_ignoreUnclean.booleanValue() ? " --ignore-unclean" : " --no-ignore-unclean"; } String copyAndUnzip = ""; if (m_copyAndUnzip != null) { copyAndUnzip = m_copyAndUnzip.booleanValue() ? " --copy-and-unzip" : " --no-copy-and-unzip"; } String configFilePath = m_currentConfiguration.getFilePath(); return "\"" + DEFAULT_SCRIPT_FILE + "\"" + exportModules + commitMessage + gitUserName + gitUserEmail + autoPullBefore + autoPullAfter + autoPush + exportFolder + exportMode + excludeLibs + commitMode + ignoreUncleanMode + copyAndUnzip + " \"" + configFilePath + "\""; } /** Returns the command to run by the shell to normally run the checkin script. * @return the command to run by the shell to normally run the checkin script. */ private String checkoutScriptCommand() { String configFilePath = m_currentConfiguration.getFilePath(); return "\"" + DEFAULT_SCRIPT_FILE + "\"" + " --checkout " + " \"" + configFilePath + "\""; } /** * Export the modules that should be checked in into git. */ private void exportModules() { // avoid to export modules if unnecessary if (((null != m_copyAndUnzip) && !m_copyAndUnzip.booleanValue()) || ((null == m_copyAndUnzip) && !m_currentConfiguration.getDefaultCopyAndUnzip())) { m_logStream.println(); m_logStream.println("NOT EXPORTING MODULES - you disabled copy and unzip."); m_logStream.println(); return; } CmsModuleManager moduleManager = OpenCms.getModuleManager(); Collection<String> modulesToExport = ((m_modulesToExport == null) || m_modulesToExport.isEmpty()) ? m_currentConfiguration.getConfiguredModules() : m_modulesToExport; for (String moduleName : modulesToExport) { CmsModule module = moduleManager.getModule(moduleName); if (module != null) { CmsModuleImportExportHandler handler = CmsModuleImportExportHandler.getExportHandler(getCmsObject(), module, "Git export handler"); try { handler.exportData(getCmsObject(), new CmsPrintStreamReport(m_logStream, OpenCms.getWorkplaceManager().getWorkplaceLocale(getCmsObject()), false)); } catch (CmsRoleViolationException | CmsConfigurationException | CmsImportExportException e) { e.printStackTrace(m_logStream); } } } } /** * Imports a module from the given zip file.<p> * * @param file the module file to import * @throws CmsException if soemthing goes wrong * * @return true if there were no errors during the import */ private boolean importModule(File file) throws CmsException { m_logStream.println("Trying to import module from " + file.getAbsolutePath()); CmsModuleImportExportHandler importHandler = new CmsModuleImportExportHandler(); CmsModule module = CmsModuleImportExportHandler.readModuleFromImport(file.getAbsolutePath()); String moduleName = module.getName(); I_CmsReport report = new CmsPrintStreamReport(m_logStream, OpenCms.getWorkplaceManager().getWorkplaceLocale(getCmsObject()), false); if (OpenCms.getModuleManager().hasModule(moduleName)) { OpenCms.getModuleManager().deleteModule(m_cms, moduleName, true /*replace module*/, report); } CmsImportParameters params = new CmsImportParameters(file.getAbsolutePath(), "/", false); importHandler.setImportParameters(params); importHandler.importData(m_cms, report); file.delete(); if (report.hasError() || report.hasWarning()) { m_logStream.println("Import failed, see opencms.log for details"); return false; } return true; } /** * Imports the selected modules from the git repository.<p> * * @return true if there were no errors during the import */ @SuppressWarnings("resource") private boolean importModules() { boolean result = true; try { m_logStream.println("Checking module dependencies."); Multimap<String, String> dependencies = HashMultimap.create(); Set<String> unsortedModules = Sets.newHashSet(m_modulesToExport); for (String module : m_modulesToExport) { String manifestPath = CmsStringUtil.joinPaths(m_currentConfiguration.getModulesPath(), module, m_currentConfiguration.getResourcesSubFolder(), "manifest.xml"); Document doc = CmsXmlUtils.unmarshalHelper(CmsFileUtil.readFully(new FileInputStream(manifestPath)), new CmsXmlEntityResolver(null)); List<?> depNodes = doc.getRootElement().selectNodes("//dependencies/dependency/@name"); for (Object nodeObj : depNodes) { Node node = ((Node) nodeObj); String dependency = node.getText(); if (m_modulesToExport.contains(dependency)) { // we can only handle dependencies between selected modules // and just have to assume that other dependencies are fulfilled dependencies.put(module, dependency); } } } List<String> sortedModules = Lists.newArrayList(); // if there are no cycles, this loop will find one element on each iteration for (int i = 0; i < m_modulesToExport.size(); i++) { String nextModule = null; for (String key : unsortedModules) { if (dependencies.get(key).isEmpty()) { nextModule = key; break; } } if (nextModule != null) { sortedModules.add(nextModule); unsortedModules.remove(nextModule); for (String key : Sets.newHashSet(dependencies.keySet())) { // copy key set to avoid concurrent modification exception dependencies.get(key).remove(nextModule); } } } m_logStream.println("Modules sorted by dependencies: " + sortedModules); for (String moduleName : sortedModules) { String dir = CmsStringUtil.joinPaths(m_currentConfiguration.getModulesPath(), moduleName, m_currentConfiguration.getResourcesSubFolder()); File dirEntry = new File(dir); if (!dirEntry.exists()) { continue; } try { m_logStream.println("Creating temp file for module " + moduleName); File outputFile = File.createTempFile(moduleName + "-", ".zip"); FileOutputStream fos = new FileOutputStream(outputFile); m_logStream.println("Zipping module structure to " + outputFile.getAbsolutePath()); zipRfsFolder(dirEntry, fos); result &= importModule(outputFile); outputFile.delete(); } catch (Exception e) { LOG.error(e.getLocalizedMessage(), e); e.printStackTrace(m_logStream); result = false; } } } catch (Exception e) { LOG.error(e.getLocalizedMessage(), e); m_logStream.println("Unable to check dependencies for modules, giving up."); e.printStackTrace(m_logStream); result = false; } return result; } /** * Read all configuration files. * @return the list with all available configurations */ private List<CmsGitConfiguration> readConfigFiles() { List<CmsGitConfiguration> configurations = new LinkedList<CmsGitConfiguration>(); // Default configuration file for backwards compatibility addConfigurationIfValid(configurations, new File(DEFAULT_CONFIG_FILE)); // All files in the config folder File configFolder = new File(DEFAULT_CONFIG_FOLDER); if (configFolder.isDirectory()) { for (File configFile : configFolder.listFiles()) { addConfigurationIfValid(configurations, configFile); } } return configurations; } /** Returns the command to run by the shell to reset to HEAD. * @return the command to run by the shell to reset to HEAD. */ private String resetHeadScriptCommand() { String configFilePath = m_currentConfiguration.getFilePath(); return "\"" + DEFAULT_SCRIPT_FILE + "\" --reset-head" + " \"" + configFilePath + "\""; } /** Returns the command to run by the shell to reset to ${origin}/${branch}. * @return the command to run by the shell to reset to ${origin}/${branch}. */ private String resetRemoteHeadScriptCommand() { String configFilePath = m_currentConfiguration.getFilePath(); return "\"" + DEFAULT_SCRIPT_FILE + "\" --reset-remote-head" + " \"" + configFilePath + "\""; } /** * Runs the shell script for committing and optionally pushing the changes in the module. * @return exit code of the script. */ private int runCommitScript() { if (m_checkout && !m_fetchAndResetBeforeImport) { m_logStream.println("Skipping script...."); return 0; } try { m_logStream.flush(); String commandParam; if (m_resetRemoteHead) { commandParam = resetRemoteHeadScriptCommand(); } else if (m_resetHead) { commandParam = resetHeadScriptCommand(); } else if (m_checkout) { commandParam = checkoutScriptCommand(); } else { commandParam = checkinScriptCommand(); } String[] cmd = { "bash", "-c", commandParam }; m_logStream.println("Calling the script as follows:"); m_logStream.println(); m_logStream.println(cmd[0] + " " + cmd[1] + " " + cmd[2]); ProcessBuilder builder = new ProcessBuilder(cmd); m_logStream.close(); m_logStream = null; Redirect redirect = Redirect.appendTo(new File(DEFAULT_LOGFILE_PATH)); builder.redirectOutput(redirect); builder.redirectError(redirect); Process scriptProcess = builder.start(); int exitCode = scriptProcess.waitFor(); scriptProcess.getOutputStream().close(); m_logStream = new PrintStream(new FileOutputStream(DEFAULT_LOGFILE_PATH, true)); return exitCode; } catch (InterruptedException | IOException e) { e.printStackTrace(m_logStream); return -1; } } }