Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
org.netbeans.modules.mercurial.util.HgCommand Maven / Gradle / Ivy
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.netbeans.modules.mercurial.util;
import java.awt.EventQueue;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.InterruptedIOException;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.Writer;
import java.net.PasswordAuthentication;
import java.net.URI;
import java.net.URISyntaxException;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.concurrent.Callable;
import java.util.logging.Level;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.netbeans.api.options.OptionsDisplayer;
import org.netbeans.modules.mercurial.FileInformation;
import org.netbeans.modules.mercurial.HgException;
import org.netbeans.modules.mercurial.HgModuleConfig;
import org.netbeans.modules.mercurial.Mercurial;
import org.netbeans.modules.mercurial.OutputLogger;
import org.netbeans.modules.mercurial.WorkingCopyInfo;
import org.netbeans.modules.mercurial.commands.StatusCommand;
import org.netbeans.modules.mercurial.config.HgConfigFiles;
import org.netbeans.modules.mercurial.ui.branch.HgBranch;
import org.netbeans.modules.mercurial.ui.log.HgLogMessage;
import org.netbeans.modules.mercurial.ui.log.HgLogMessage.HgRevision;
import org.netbeans.modules.mercurial.ui.queues.QPatch;
import org.netbeans.modules.mercurial.ui.queues.Queue;
import org.netbeans.modules.mercurial.ui.repository.HgURL;
import org.netbeans.modules.mercurial.ui.repository.Repository;
import org.netbeans.modules.mercurial.ui.repository.UserCredentialsSupport;
import org.netbeans.modules.mercurial.ui.tag.HgTag;
import org.netbeans.modules.versioning.util.KeyringSupport;
import org.netbeans.modules.versioning.util.Utils;
import org.openide.filesystems.FileUtil;
import org.openide.util.NbBundle;
import org.openide.util.NetworkSettings;
import org.openide.util.Utilities;
/**
*
* @author jrice
*/
public abstract class HgCommand implements Callable {
public static final String HG_COMMAND = "hg"; // NOI18N
public static final String HG_WINDOWS_EXE = ".exe"; // NOI18N
public static final String HG_WINDOWS_BAT = ".bat"; // NOI18N
public static final String HG_WINDOWS_CMD = ".cmd"; // NOI18N
public static final String[] HG_WINDOWS_EXECUTABLES = new String[] {
HG_COMMAND + HG_WINDOWS_EXE,
HG_COMMAND + HG_WINDOWS_BAT,
HG_COMMAND + HG_WINDOWS_CMD,
};
public static final String HG_COMMAND_PLACEHOLDER = HG_COMMAND;
public static final String HGK_COMMAND = "hgk"; // NOI18N
private static final String HG_DIFF_CMD = "diff"; //NOI18N
private static final String HG_OPT_STAT = "--stat"; //NOI18N
protected static final String HG_STATUS_CMD = "status"; // NOI18N // need -A to see ignored files, specified in .hgignore, see man hgignore for details
private static final String HG_OPT_REPOSITORY = "--repository"; // NOI18N
private static final String HG_OPT_BUNDLE = "--bundle"; // NOI18N
protected static final String HG_OPT_CWD_CMD = "--cwd"; // NOI18N
private static final String HG_OPT_USERNAME = "--user"; // NOI18N
private static final String HG_OPT_CLOSE_BRANCH = "--close-branch"; // NOI18N
private static final String HG_OPT_FOLLOW = "--follow"; // NOI18N
protected static final String HG_FLAG_REV_CMD = "--rev"; // NOI18N
private static final String HG_STATUS_FLAG_TIP_CMD = "tip"; // NOI18N
private static final String HG_HEAD_STR = "HEAD"; // NOI18N
private static final String HG_FLAG_DATE_CMD = "--date"; // NOI18N
private static final String HG_COMMIT_CMD = "commit"; // NOI18N
private static final String HG_COMMIT_OPT_LOGFILE_CMD = "--logfile"; // NOI18N
private static final String HG_COMMIT_TEMPNAME = "hgcommit"; // NOI18N
private static final String HG_COMMIT_TEMPNAME_SUFFIX = ".hgm"; // NOI18N
private static final String HG_COMMIT_DEFAULT_MESSAGE = "[no commit message]"; // NOI18N
private static final String HG_REVERT_CMD = "revert"; // NOI18N
private static final String HG_REVERT_NOBACKUP_CMD = "--no-backup"; // NOI18N
private static final String HG_PURGE_CMD = "purge"; // NOI18N
private static final String HG_EXT_PURGE = "extensions.purge="; //NOI18N
private static final String HG_ADD_CMD = "add"; // NOI18N
private static final String HG_TIP_CONST = "tip"; // NOI18N
private static final String HG_CREATE_CMD = "init"; // NOI18N
private static final String HG_CLONE_CMD = "clone"; // NOI18N
private static final String HG_UPDATE_ALL_CMD = "update"; // NOI18N
private static final String HG_UPDATE_FORCE_ALL_CMD = "-C"; // NOI18N
private static final String HG_REMOVE_CMD = "remove"; // NOI18N
private static final String HG_REMOVE_FLAG_FORCE_CMD = "--force"; // NOI18N
private static final String HG_LOG_CMD = "log"; // NOI18N
private static final String HG_TIP_CMD = "tip"; // NOI18N
private static final String HG_OUT_CMD = "out"; // NOI18N
private static final String HG_LOG_LIMIT_ONE_CMD = "-l 1"; // NOI18N
private static final String HG_LOG_LIMIT_CMD = "-l"; // NOI18N
private static final String HG_PARENT_CMD = "parents"; //NOI18N
private static final String HG_PARAM_BRANCH = "-b"; //NOI18N
private static final String HG_PARAM_PUSH_NEW_BRANCH = "--new-branch"; //NOI18N
private static final String HG_LOG_NO_MERGES_CMD = "-M";
private static final String HG_LOG_DEBUG_CMD = "--debug";
private static final String HG_LOG_REVISION_OUT = "rev:"; // NOI18N
private static final String HG_LOG_AUTHOR_OUT = "auth:"; // NOI18N
private static final String HG_LOG_USER_OUT = "user:"; // NOI18N
private static final String HG_LOG_DESCRIPTION_OUT = "desc:"; // NOI18N
private static final String HG_LOG_DATE_OUT = "date:"; // NOI18N
private static final String HG_LOG_ID_OUT = "id:"; // NOI18N
private static final String HG_LOG_PARENTS_OUT = "parents:"; // NOI18N
private static final String HG_LOG_FILEMODS_OUT = "file_mods:"; // NOI18N
private static final String HG_LOG_FILEADDS_OUT = "file_adds:"; // NOI18N
private static final String HG_LOG_FILEDELS_OUT = "file_dels:"; // NOI18N
private static final String HG_LOG_FILECOPIESS_OUT = "file_copies:"; // NOI18N
private static final String HG_LOG_BRANCHES_OUT = "branches:"; // NOI18N
private static final String HG_LOG_TAGS_OUT = "tags:"; // NOI18N
private static final String HG_LOG_ENDCS_OUT = "endCS:"; // NOI18N
private static final String HG_LOG_PATCH_CMD = "-p";
private static final String HG_LOG_TEMPLATE_EXPORT_FILE_CMD =
"--template=# Mercurial Export File Diff\\n# changeset: \\t{rev}:{node|short}\\n# user:\\t\\t{author}\\n# date:\\t\\t{date|isodate}\\n# summary:\\t{desc}\\n\\n";
private static final String HG_REV_TEMPLATE_CMD = "--template={rev}\\n"; // NOI18N
private static final String HG_CAT_CMD = "cat"; // NOI18N
private static final String HG_FLAG_OUTPUT_CMD = "--output"; // NOI18N
private static final String HG_COMMONANCESTOR_CMD = "debugancestor"; // NOI18N
private static final String HG_ANNOTATE_CMD = "annotate"; // NOI18N
private static final String HG_ANNOTATE_FLAGN_CMD = "--number"; // NOI18N
private static final String HG_ANNOTATE_FLAGU_CMD = "--user"; // NOI18N
private static final String HG_ANNOTATE_FLAGL_CMD = "--line-number"; // NOI18N
private static final String HG_EXPORT_CMD = "export"; // NOI18N
private static final String HG_IMPORT_CMD = "import"; // NOI18N
private static final String HG_RENAME_CMD = "rename"; // NOI18N
private static final String HG_RENAME_AFTER_CMD = "-A"; // NOI18N
private static final String HG_COPY_CMD = "copy"; // NOI18N
private static final String HG_COPY_AFTER_CMD = "-A"; // NOI18N
private static final String HG_NEWEST_FIRST = "--newest-first"; // NOI18N
private static final String HG_RESOLVE_CMD = "resolve"; //NOI18N
private static final String HG_RESOLVE_MARK_RESOLVED = "--mark"; //NOI18N
private static final String HG_MQ_EXT_CMD = "extensions.mq="; //NOI18N
private static final String HG_QPATCHES_NAME = "patches"; //NOI18N
private static final String HG_QQUEUE_CMD = "qqueue"; //NOI18N
private static final String HG_QSERIES_CMD = "qseries"; //NOI18N
private static final String HG_OPT_SUMMARY = "--summary"; //NOI18N
private static final String HG_OPT_LIST = "--list"; //NOI18N
private static final String HG_QGOTO_CMD = "qgoto"; //NOI18N
private static final String HG_QPOP_CMD = "qpop"; //NOI18N
private static final String HG_QPUSH_CMD = "qpush"; //NOI18N
private static final String HG_OPT_ALL = "--all"; //NOI18N
private static final String HG_QCREATE_CMD = "qnew"; //NOI18N
private static final String HG_QREFRESH_PATCH = "qrefresh"; //NOI18N
private static final String HG_OPT_EXCLUDE = "--exclude"; //NOI18N
private static final String HG_OPT_SHORT = "--short"; //NOI18N
private static final String HG_QFINISH_CMD = "qfinish"; //NOI18N
private static final String QUEUE_ACTIVE = "(active)"; //NOI18N
protected static final String HG_REBASE_CMD = "rebase"; //NOI18N
// TODO: replace this hack
// Causes /usr/bin/hgmerge script to return when a merge
// has conflicts with exit 0, instead of throwing up EDITOR.
// Problem is after this Hg thinks the merge succeded and no longer
// marks repository with a merge needed flag. So Plugin needs to
// track this merge required status by changing merge conflict file
// status. If the cache is removed this information would be lost.
//
// Really need Hg to give us back merge status information,
// which it currently does not
private static final String HG_MERGE_CMD = "merge"; // NOI18N
private static final String HG_MERGE_FORCE_CMD = "-f"; // NOI18N
private static final String HG_MERGE_ENV = "EDITOR=success || $TEST -s"; // NOI18N
protected static final String HG_MERGE_SIMPLE_TOOL = "ui.merge=internal:merge"; //NOI18N
public static final String HG_HGK_PATH_SOLARIS10 = "/usr/demo/mercurial"; // NOI18N
private static final String HG_HGK_PATH_SOLARIS10_ENV = "PATH=/usr/bin/:/usr/sbin:/bin:"+ HG_HGK_PATH_SOLARIS10; // NOI18N
private static final String HG_PULL_CMD = "pull"; // NOI18N
private static final String HG_UPDATE_CMD = "-u"; // NOI18N
private static final String HG_PUSH_CMD = "push"; // NOI18N
private static final String HG_BUNDLE_CMD = "bundle"; // NOI18N
private static final String HG_UNBUNDLE_CMD = "unbundle"; // NOI18N
private static final String HG_ROLLBACK_CMD = "rollback"; // NOI18N
private static final String HG_BACKOUT_CMD = "backout"; // NOI18N
private static final String HG_BACKOUT_MERGE_CMD = "--merge"; // NOI18N
private static final String HG_BACKOUT_COMMIT_MSG_CMD = "-m"; // NOI18N
private static final String HG_REV_CMD = "-r"; // NOI18N
private static final String HG_BASE_CMD = "--base"; // NOI18N
private static final String HG_OPTION_GIT = "--git"; //NOI18N
private static final String HG_STRIP_CMD = "strip"; // NOI18N
private static final String HG_STRIP_EXT_CMD = "extensions.mq="; // NOI18N
private static final String HG_STRIP_NOBACKUP_CMD = "-n"; // NOI18N
private static final String HG_STRIP_FORCE_MULTIHEAD_CMD = "-f"; // NOI18N
private static final String HG_VERIFY_CMD = "verify"; // NOI18N
private static final String HG_VERSION_CMD = "version"; // NOI18N
private static final String HG_INCOMING_CMD = "incoming"; // NOI18N
private static final String HG_OUTGOING_CMD = "outgoing"; // NOI18N
private static final String HG_VIEW_CMD = "view"; // NOI18N
private static final String HG_VERBOSE_CMD = "-v"; // NOI18N
private static final String HG_CONFIG_OPTION_CMD = "--config"; // NOI18N
private static final String HG_FETCH_EXT_CMD = "extensions.fetch="; // NOI18N
private static final String HG_FETCH_CMD = "fetch"; // NOI18N
public static final String HG_PROXY_ENV = "http_proxy="; // NOI18N
private static final String HG_NO_COMMIT = "--no-commit"; // NOI18N
private static final String HG_UPDATE_NEEDED_ERR = "(run 'hg update' to get a working copy)"; //NOI18N
public static final String HG_MERGE_CONFLICT_ERR = "conflicts detected in "; // NOI18N
public static final String HG_MERGE_FAILED1_ERR = "merging"; // NOI18N
public static final String HG_MERGE_FAILED2_ERR = "failed!"; // NOI18N
public static final String HG_MERGE_FAILED3_ERR = "incomplete!"; // NOI18N
private static final String HG_MERGE_MULTIPLE_HEADS_ERR = "abort: repo has "; // NOI18N
private static final String HG_MERGE_UNCOMMITTED_ERR = "abort: outstanding uncommitted merges"; // NOI18N
private static final String HG_MERGE_UNAVAILABLE_ERR = "is not recognized as an internal or external command";
private static final String HG_NO_CHANGES_ERR = "no changes found"; // NOI18N
private static final String HG_CREATE_NEW_BRANCH_ERR = "abort: push creates new remote "; // NOI18N
private static final String HG_HEADS_CREATED_ERR = "(+1 heads)"; // NOI18N
private static final String HG_NO_HG_CMD_FOUND_ERR = "hg: not found";
private static final String HG_ARG_LIST_TOO_LONG_ERR = "Arg list too long";
private static final String HG_ARGUMENT_LIST_TOO_LONG_ERR = "Argument list too long"; //NOI18N
private static final String HG_HEADS_CMD = "heads"; // NOI18N
private static final String HG_BRANCHES_CMD = "branches"; // NOI18N
private static final String HG_BRANCH_CMD = "branch"; // NOI18N
private static final String HG_TAG_CMD = "tag"; // NOI18N
private static final String HG_TAG_OPT_MESSAGE = "--message"; // NOI18N
private static final String HG_TAG_OPT_REMOVE = "--remove"; // NOI18N
private static final String HG_TAG_OPT_REVISION = "--rev"; // NOI18N
private static final String HG_TAG_OPT_LOCAL = "--local"; // NOI18N
private static final String HG_TAGS_CMD = "tags"; // NOI18N
private static final String HG_NO_REPOSITORY_ERR = "There is no Mercurial repository here"; // NOI18N
private static final String HG_NO_RESPONSE_ERR = "no suitable response from remote hg!"; // NOI18N
private static final String HG_NOT_REPOSITORY_ERR = "does not appear to be an hg repository"; // NOI18N
private static final String HG_REPOSITORY = "repository"; // NOI18N
private static final String HG_NOT_FOUND_ERR = "not found!"; // NOI18N
private static final String HG_UPDATE_SPAN_BRANCHES_ERR = "abort: update spans branches"; // NOI18N
private static final String HG_UPDATE_CROSS_BRANCHES_ERR = "abort: crosses branches"; // NOI18N
private static final String HG_ALREADY_TRACKED_ERR = " already tracked!"; // NOI18N
private static final String HG_NOT_TRACKED_ERR = " no tracked!"; // NOI18N
private static final String HG_CANNOT_READ_COMMIT_MESSAGE_ERR = "abort: can't read commit message"; // NOI18N
private static final String HG_CANNOT_RUN_ERR = "Cannot run program"; // NOI18N
private static final String HG_ABORT_ERR = "abort: "; // NOI18N
//#132984: range of issues with upgrade to Hg 1.0, error string changed from branches to heads, just removed ending
private static final String HG_ABORT_PUSH_ERR = "abort: push creates new remote "; // NOI18N
private static final String HG_ABORT_NO_FILES_TO_COPY_ERR = "abort: no files to copy"; // NOI18N
private static final String HG_ABORT_NO_DEFAULT_PUSH_ERR = "abort: repository default-push not found!"; // NOI18N
private static final String HG_ABORT_NO_DEFAULT_ERR = "abort: repository default not found!"; // NOI18N
private static final String HG_ABORT_POSSIBLE_PROXY_ERR = "abort: error: node name or service name not known"; // NOI18N
private static final String HG_ABORT_UNCOMMITTED_CHANGES_ERR = "abort: outstanding uncommitted changes"; // NOI18N
private static final String HG_BACKOUT_MERGE_NEEDED_ERR = "(use \"backout --merge\" if you want to auto-merge)";
private static final String HG_ABORT_BACKOUT_MERGE_CSET_ERR = "abort: cannot back out a merge changeset without --parent"; // NOI18N"
private static final String HG_COMMIT_AFTER_MERGE_ERR = "abort: cannot partially commit a merge (do not specify files or patterns)"; // NOI18N"
private static final String HG_ADDING = "adding"; //NOI18N
private static final String HG_WARNING_PERFORMANCE_FILES_OVER = ": files over"; //NOI18N
private static final String HG_WARNING_PERFORMANCE_CAUSE_PROBLEMS = "cause memory and performance problems"; //NOI18N
private static final String HG_ABORT_CANNOT_FOLLOW_NONEXISTENT_FILE = "cannot follow nonexistent file"; //NOI18N
private static final String HG_NO_CHANGE_NEEDED_ERR = "no change needed"; // NOI18N
private static final String HG_NO_ROLLBACK_ERR = "no rollback information available"; // NOI18N
private static final String HG_NO_UPDATES_ERR = "0 files updated, 0 files merged, 0 files removed, 0 files unresolved"; // NOI18N
private static final String HG_NO_VIEW_ERR = "hg: unknown command 'view'"; // NOI18N
private static final String HG_HGK_NOT_FOUND_ERR = "sh: hgk: not found"; // NOI18N
private static final String HG_NO_SUCH_FILE_ERR = "no such file"; // NOI18N
private static final String HG_NO_REV_STRIP_ERR = "abort: unknown revision"; // NOI18N
private static final String HG_LOCAL_CHANGES_STRIP_ERR = "abort: local changes found"; // NOI18N
private static final String HG_MULTIPLE_HEADS_STRIP_ERR = "no rollback information available"; // NOI18N
private static final char HG_STATUS_CODE_CONFLICT = 'U' + ' '; // NOI18N // STATUS_VERSIONED_CONFLICT - TODO when Hg status supports conflict markers
public static final String HG_STR_CONFLICT_EXT = ".conflict~"; // NOI18N
private static final String HG_EPOCH_PLUS_ONE_YEAR = "1971-01-01"; // NOI18N
private static final String HG_AUTHORIZATION_REQUIRED_ERR = "authorization required"; // NOI18N
private static final String HG_AUTHORIZATION_FAILED_ERR = "authorization failed"; // NOI18N
public static final String COMMIT_AFTER_MERGE = "commitAfterMerge"; //NOI18N
private static final String ENV_HGPLAIN = "HGPLAIN"; //NOI18N
private static final String ENV_HGENCODING = "HGENCODING"; //NOI18N
public static final String ENCODING = getEncoding();
private static final String HG_LOG_FULL_CHANGESET_NAME = "log-full-changeset.tmpl"; //NOI18N
private static final String HG_LOG_ONLY_FILE_COPIES_CHANGESET_NAME = "log-only-file-copies-changeset.tmpl"; //NOI18N
private static final String HG_LOG_BASIC_CHANGESET_NAME = "log-no-files-changeset.tmpl"; //NOI18N
private static final String HG_LOG_CHANGESET_GENERAL_NAME = "changeset.tmpl"; //NOI18N
private static final String HG_LOG_STYLE_NAME = "log.style"; //NOI18N
private static final String HG_ARGUMENT_STYLE = "--style="; //NOI18N
private static final int WINDOWS_MAX_COMMANDLINE_SIZE = 8000;
private static final int MAC_MAX_COMMANDLINE_SIZE = 64000;
private static final int UNIX_MAX_COMMANDLINE_SIZE = 128000;
private static final int MAX_COMMANDLINE_SIZE;
static {
String maxCmdSizeProp = System.getProperty("mercurial.maxCommandlineSize");
if (maxCmdSizeProp == null) {
maxCmdSizeProp = ""; //NOI18N
}
int maxCmdSize = 0;
try {
maxCmdSize = Integer.parseInt(maxCmdSizeProp);
} catch (NumberFormatException e) {
maxCmdSize = 0;
}
if (maxCmdSize < 1024) {
if (Utilities.isWindows()) {
maxCmdSize = WINDOWS_MAX_COMMANDLINE_SIZE;
} else if (Utilities.isMac()) {
maxCmdSize = MAC_MAX_COMMANDLINE_SIZE;
} else {
maxCmdSize = UNIX_MAX_COMMANDLINE_SIZE;
}
}
MAX_COMMANDLINE_SIZE = maxCmdSize;
}
private static final HashSet WORKING_COPY_PARENT_MODIFYING_COMMANDS = new HashSet(Arrays.asList(
HG_BACKOUT_CMD,
HG_CLONE_CMD,
HG_COMMIT_CMD,
HG_CREATE_CMD,
HG_FETCH_CMD,
HG_IMPORT_CMD,
HG_MERGE_CMD,
HG_PULL_CMD,
HG_ROLLBACK_CMD,
HG_QCREATE_CMD,
HG_QGOTO_CMD,
HG_QFINISH_CMD,
HG_QPOP_CMD,
HG_QPUSH_CMD,
HG_QREFRESH_PATCH,
HG_REBASE_CMD,
HG_STRIP_CMD,
HG_TAG_CMD,
HG_UNBUNDLE_CMD,
HG_UPDATE_ALL_CMD
));
private static final HashSet REPOSITORY_NOMODIFICATION_COMMANDS = new HashSet(Arrays.asList(
HG_ANNOTATE_CMD,
HG_BRANCH_CMD,
HG_BRANCHES_CMD,
HG_BUNDLE_CMD,
HG_CAT_CMD,
HG_DIFF_CMD,
HG_EXPORT_CMD,
HG_HEADS_CMD,
HG_INCOMING_CMD,
HG_LOG_CMD,
HG_OUTGOING_CMD,
HG_OUT_CMD,
HG_PARENT_CMD,
HG_PUSH_CMD,
HG_RESOLVE_CMD,
HG_QSERIES_CMD,
HG_QQUEUE_CMD,
HG_STATUS_CMD,
HG_TAG_CMD,
HG_TAGS_CMD,
HG_TIP_CMD,
HG_VERIFY_CMD,
HG_VERSION_CMD,
HG_VIEW_CMD
));
private static final String HG_FLAG_TOPO = "--topo"; //NOI18N
private static final String CMD_EXE = "cmd.exe"; //NOI18N
private static ThreadLocal doNotAddHgPlain = new ThreadLocal();
protected static final class CommandParameters {
private final ArrayList arguments;
private final String commandName;
public CommandParameters (String commandName) {
this.commandName = commandName;
this.arguments = new ArrayList();
}
public CommandParameters add (String parameter) {
arguments.add(parameter);
return this;
}
public CommandParameters addVerboseOption () {
arguments.add(HG_VERBOSE_CMD);
return this;
}
public CommandParameters addConfigOption (String configOption) {
arguments.add(HG_CONFIG_OPTION_CMD);
arguments.add(configOption);
return this;
}
public CommandParameters addRepositoryLocation (String repositoryRootLocation) {
arguments.add(HG_OPT_REPOSITORY);
arguments.add(repositoryRootLocation);
return this;
}
public List toCommand () {
List command = new ArrayList(arguments.size() + 2);
command.add(getHgCommand());
command.add(commandName);
command.addAll(arguments);
return command;
}
}
/**
* Merge working directory with the head revision
* Merge the contents of the current working directory and the
* requested revision. Files that changed between either parent are
* marked as changed for the next commit and a commit must be
* performed before any further updates are allowed.
*
* @param File repository of the mercurial repository's root directory
* @param Revision to merge with, if null will merge with default tip rev
* @return hg merge output
* @throws HgException
*/
public static List doMerge(File repository, String revStr) throws HgException {
if (repository == null ) return null;
List command = new ArrayList();
List env = new ArrayList();
command.add(getHgCommand());
command.add(HG_MERGE_CMD);
command.add(HG_MERGE_FORCE_CMD);
command.add(HG_OPT_REPOSITORY);
command.add(repository.getAbsolutePath());
if (HgModuleConfig.getDefault().isInternalMergeToolEnabled()) {
command.add(HG_CONFIG_OPTION_CMD);
command.add(HG_MERGE_SIMPLE_TOOL);
}
if(revStr != null)
command.add(revStr);
env.add(HG_MERGE_ENV);
List list = execEnv(command, env);
return list;
}
/**
* Update the working directory to the tip revision.
* By default, update will refuse to run if doing so would require
* merging or discarding local changes.
*
* @param File repository of the mercurial repository's root directory
* @param Boolean force an Update and overwrite any modified files in the working directory
* @param String revision to be updated to
* @param Boolean throw exception on error
* @return hg update output
* @throws org.netbeans.modules.mercurial.HgException
*/
@NbBundle.Messages({
"MSG_WARN_UPDATE_MERGE_TEXT=Cannot update because it would end on a different head - \"Merge\" or \"Rebase\" is needed.",
"MSG_WARN_UPDATE_COMMIT_TEXT=Merge has been done, invoke \"Commit\" menu item\n "
+ "to commit these changes before doing an \"Update\""
})
public static List doUpdateAll(File repository, boolean bForce, String revision, boolean bThrowException) throws HgException {
if (repository == null ) return null;
List command = new ArrayList();
command.add(getHgCommand());
command.add(HG_UPDATE_ALL_CMD);
command.add(HG_VERBOSE_CMD);
if (bForce) command.add(HG_UPDATE_FORCE_ALL_CMD);
if (HgModuleConfig.getDefault().isInternalMergeToolEnabled()) {
command.add(HG_CONFIG_OPTION_CMD);
command.add(HG_MERGE_SIMPLE_TOOL);
}
command.add(HG_OPT_REPOSITORY);
command.add(repository.getAbsolutePath());
if (revision != null){
command.add(revision);
}
List list = exec(command);
if (bThrowException) {
if (!list.isEmpty()) {
if (isErrorUpdateSpansBranches(list.get(0))) {
handleError(command, list, Bundle.MSG_WARN_UPDATE_MERGE_TEXT(),
OutputLogger.getLogger(repository));
} else if (isMergeAbortUncommittedMsg(list.get(0))) {
handleError(command, list, Bundle.MSG_WARN_UPDATE_COMMIT_TEXT(),
OutputLogger.getLogger(repository));
} else if (isErrorAbort(list.get(list.size() -1))) {
handleError(command, list, NbBundle.getMessage(HgCommand.class, "MSG_COMMAND_ABORTED"),
OutputLogger.getLogger(repository));
}
}
}
return list;
}
public static List doUpdateAll(File repository, boolean bForce, String revision) throws HgException {
return doUpdateAll(repository, bForce, revision, true);
}
/**
* Roll back the last transaction in this repository
* Transactions are used to encapsulate the effects of all commands
* that create new changesets or propagate existing changesets into a
* repository. For example, the following commands are transactional,
* and their effects can be rolled back:
* commit, import, pull, push (with this repository as destination)
* unbundle
* There is only one level of rollback, and there is no way to undo a rollback.
*
* @param File repository of the mercurial repository's root directory
* @return hg update output
* @throws org.netbeans.modules.mercurial.HgException
*/
public static List doRollback(File repository, OutputLogger logger) throws HgException {
if (repository == null ) return null;
List command = new ArrayList();
command.add(getHgCommand());
command.add(HG_ROLLBACK_CMD);
command.add(HG_OPT_REPOSITORY);
command.add(repository.getAbsolutePath());
List list = exec(command);
if (list.isEmpty())
handleError(command, list, NbBundle.getMessage(HgCommand.class, "MSG_ROLLBACK_FAILED"), logger);
return list;
}
public static List doBackout(File repository, String revision,
boolean doMerge, String commitMsg, OutputLogger logger) throws HgException {
if (repository == null ) return null;
List env = new ArrayList();
List command = new ArrayList();
command.add(getHgCommand());
command.add(HG_BACKOUT_CMD);
if(doMerge){
command.add(HG_BACKOUT_MERGE_CMD);
env.add(HG_MERGE_ENV);
}
if (commitMsg != null && !commitMsg.equals("")) { // NOI18N
command.add(HG_BACKOUT_COMMIT_MSG_CMD);
command.add(commitMsg);
} else {
command.add(HG_BACKOUT_COMMIT_MSG_CMD);
command.add(NbBundle.getMessage(HgCommand.class, "MSG_BACKOUT_MERGE_COMMIT_MSG", revision)); // NOI18N
}
command.add(HG_OPT_REPOSITORY);
command.add(repository.getAbsolutePath());
if (revision != null){
command.add(HG_REV_CMD);
command.add(revision);
}
List list;
if(doMerge){
list = execEnv(command, env);
}else{
list = exec(command);
}
if (list.isEmpty())
handleError(command, list, NbBundle.getMessage(HgCommand.class, "MSG_BACKOUT_FAILED"), logger);
return list;
}
public static List doStrip(File repository, String revision,
boolean doForceMultiHead, boolean doBackup, OutputLogger logger) throws HgException {
if (repository == null ) return null;
List command = new ArrayList();
command.add(getHgCommand());
command.add(HG_STRIP_CMD);
command.add(HG_CONFIG_OPTION_CMD);
command.add(HG_STRIP_EXT_CMD);
if(doForceMultiHead){
command.add(HG_STRIP_FORCE_MULTIHEAD_CMD);
}
if(!doBackup){
command.add(HG_STRIP_NOBACKUP_CMD);
}
command.add(HG_VERBOSE_CMD);
command.add(HG_OPT_REPOSITORY);
command.add(repository.getAbsolutePath());
if (revision != null){
command.add(revision);
}
List list = exec(command);
if (list.isEmpty() && doBackup)
handleError(command, list, NbBundle.getMessage(HgCommand.class, "MSG_STRIP_FAILED"), logger);
return list;
}
public static List doVerify(File repository, OutputLogger logger) throws HgException {
if (repository == null ) return null;
List command = new ArrayList();
command.add(getHgCommand());
command.add(HG_VERIFY_CMD);
command.add(HG_OPT_REPOSITORY);
command.add(repository.getAbsolutePath());
List list = exec(command);
if (list.isEmpty())
handleError(command, list, NbBundle.getMessage(HgCommand.class, "MSG_VERIFY_FAILED"), logger);
return list;
}
/**
* Return the version of hg, e.g. "0.9.3". // NOI18N
*
* @return String
*/
public static String getHgVersion() {
List list;
try {
list = execForVersionCheck();
} catch (HgException ex) {
// Ignore Exception
return null;
}
if (!list.isEmpty()) {
int start = list.get(0).indexOf('(');
int end = list.get(0).indexOf(')');
if (start != -1 && end != -1) {
return list.get(0).substring(start + 9, end);
}
}
return null;
}
/**
* Pull changes from the default pull locarion and update working directory.
* By default, update will refuse to run if doing so would require
* merging or discarding local changes.
*
* @param File repository of the mercurial repository's root directory
* @return hg pull output
* @throws org.netbeans.modules.mercurial.HgException
*/
public static List doPull (File repository, String revision, String branch, OutputLogger logger) throws HgException {
if (repository == null ) return null;
List command = new ArrayList();
command.add(getHgCommand());
command.add(HG_PULL_CMD);
command.add(HG_VERBOSE_CMD);
command.add(HG_OPT_REPOSITORY);
command.add(repository.getAbsolutePath());
if (HgModuleConfig.getDefault().isInternalMergeToolEnabled()) {
command.add(HG_CONFIG_OPTION_CMD);
command.add(HG_MERGE_SIMPLE_TOOL);
}
if (revision != null) {
command.add(HG_FLAG_REV_CMD);
command.add(revision);
}
if (branch != null) {
command.add(HG_PARAM_BRANCH);
command.add(branch);
}
List list;
String defaultPull = new HgConfigFiles(repository).getDefaultPull(false);
String proxy = getGlobalProxyIfNeeded(defaultPull, true, logger);
if(proxy != null){
List env = new ArrayList();
env.add(HG_PROXY_ENV + proxy);
list = execEnv(command, env);
}else{
list = exec(command);
}
if (!list.isEmpty() &&
isErrorAbort(list.get(list.size() -1))) {
handleError(command, list, NbBundle.getMessage(HgCommand.class, "MSG_COMMAND_ABORTED"), logger);
}
return list;
}
/**
* Unbundle changes from the specified local source repository and
* update working directory.
* By default, update will refuse to run if doing so would require
* merging or discarding local changes.
*
* @param File repository of the mercurial repository's root directory
* @param File bundle identfies the compressed changegroup file to be applied
* @return hg unbundle output
* @throws org.netbeans.modules.mercurial.HgException
*/
public static List doUnbundle(File repository, File bundle, boolean update, OutputLogger logger) throws HgException {
if (repository == null ) return null;
List command = new ArrayList();
command.add(getHgCommand());
command.add(HG_UNBUNDLE_CMD);
command.add(HG_VERBOSE_CMD);
if (update) {
command.add(HG_UPDATE_CMD);
}
command.add(HG_OPT_REPOSITORY);
command.add(repository.getAbsolutePath());
if (HgModuleConfig.getDefault().isInternalMergeToolEnabled()) {
command.add(HG_CONFIG_OPTION_CMD);
command.add(HG_MERGE_SIMPLE_TOOL);
}
if (bundle != null) {
command.add(bundle.getAbsolutePath());
}
List list = exec(command);
if (!list.isEmpty() &&
isErrorAbort(list.get(list.size() -1))) {
handleError(command, list, NbBundle.getMessage(HgCommand.class, "MSG_COMMAND_ABORTED"), logger);
}
return list;
}
/**
* Show the changesets that would be pulled if a pull
* was requested from the default pull location
*
* @param File repository of the mercurial repository's root directory
* @return hg incoming output
* @throws org.netbeans.modules.mercurial.HgException
*/
public static List doIncoming(File repository, String revision, String branch, OutputLogger logger) throws HgException {
if (repository == null ) return null;
List command = new ArrayList();
command.add(getHgCommand());
command.add(HG_INCOMING_CMD);
command.add(HG_VERBOSE_CMD);
command.add(HG_OPT_REPOSITORY);
command.add(repository.getAbsolutePath());
if (revision != null) {
command.add(HG_FLAG_REV_CMD);
command.add(revision);
}
if (branch != null) {
command.add(HG_PARAM_BRANCH);
command.add(branch);
}
List cmdOutput;
String defaultPull = new HgConfigFiles(repository).getDefaultPull(false);
String proxy = getGlobalProxyIfNeeded(defaultPull, false, null);
if(proxy != null){
List env = new ArrayList();
env.add(HG_PROXY_ENV + proxy);
cmdOutput = execEnv(command, env);
}else{
cmdOutput = exec(command);
}
if (!cmdOutput.isEmpty() &&
isErrorAbort(cmdOutput.get(cmdOutput.size() -1))) {
handleError(command, cmdOutput, NbBundle.getMessage(HgCommand.class, "MSG_COMMAND_ABORTED"), logger);
}
return cmdOutput;
}
/**
* Show the changesets that would be pulled if a pull
* was requested from the specified repository
*
* @param File repository of the mercurial repository's root directory
* @param String source repository to query
* @param File bundle to store downloaded changesets.
* @return hg incoming output
* @throws org.netbeans.modules.mercurial.HgException
*/
public static List doIncoming(File repository, HgURL from, String revision, String branch, File bundle, OutputLogger logger, boolean showSaveCredentialsOption) throws HgException {
if (repository == null || from == null) return null;
InterRepositoryCommand command = new InterRepositoryCommand();
command.defaultUrl = new HgConfigFiles(repository).getDefaultPull(false);
command.hgCommandType = HG_INCOMING_CMD;
command.logger = logger;
command.outputDetails = false;
command.remoteUrl = from;
command.repository = repository;
if (revision != null) {
command.additionalOptions.add(HG_FLAG_REV_CMD);
command.additionalOptions.add(revision);
}
if (branch != null) {
command.additionalOptions.add(HG_PARAM_BRANCH);
command.additionalOptions.add(branch);
}
command.additionalOptions.add(HG_VERBOSE_CMD);
command.showSaveOption = showSaveCredentialsOption;
if (bundle != null) {
command.additionalOptions.add(HG_OPT_BUNDLE);
command.additionalOptions.add(bundle.getAbsolutePath());
}
command.urlPathProperties = new String[] {HgConfigFiles.HG_DEFAULT_PULL_VALUE, HgConfigFiles.HG_DEFAULT_PULL};
List retval = command.invoke();
return retval;
}
/**
* Show the changesets that would be pushed if a push
* was requested to the specified local source repository
*
* @param File repository of the mercurial repository's root directory
* @param String source repository to query
* @return hg outgoing output
* @throws org.netbeans.modules.mercurial.HgException
*/
public static List doOutgoing(File repository, HgURL toUrl, String revision, String branch, OutputLogger logger, boolean showSaveCredentialsOption) throws HgException {
if (repository == null || toUrl == null) return null;
InterRepositoryCommand command = new InterRepositoryCommand();
command.defaultUrl = new HgConfigFiles(repository).getDefaultPush(false);
command.hgCommandType = HG_OUTGOING_CMD;
command.logger = logger;
command.outputDetails = false;
command.remoteUrl = toUrl;
command.repository = repository;
if (revision != null) {
command.additionalOptions.add(HG_FLAG_REV_CMD);
command.additionalOptions.add(revision);
}
if (branch != null) {
command.additionalOptions.add(HG_PARAM_BRANCH);
command.additionalOptions.add(branch);
}
command.additionalOptions.add(HG_VERBOSE_CMD);
File tempFolder = Utils.getTempFolder(false);
try {
command.additionalOptions.add(prepareLogTemplate(tempFolder, HG_LOG_BASIC_CHANGESET_NAME));
command.showSaveOption = showSaveCredentialsOption;
command.urlPathProperties = new String[] {HgConfigFiles.HG_DEFAULT_PUSH};
return command.invoke();
} catch (IOException ex) {
Mercurial.LOG.log(Level.INFO, null, ex);
throw new HgException(ex.getMessage());
} finally {
Utils.deleteRecursively(tempFolder);
}
}
/**
* Push changes to the specified repository
* By default, push will refuse to run if doing so would create multiple heads
*
* @param File repository of the mercurial repository's root directory
* @param String source repository to push to
* @return hg push output
* @throws org.netbeans.modules.mercurial.HgException
*/
public static List doPush (File repository, final HgURL toUrl,
String revision, String branch, boolean allowNewBranch,
OutputLogger logger, boolean showSaveCredentialsOption) throws HgException {
if (repository == null || toUrl == null) return null;
InterRepositoryCommand command = new InterRepositoryCommand();
command.defaultUrl = new HgConfigFiles(repository).getDefaultPush(false);
command.hgCommandType = HG_PUSH_CMD;
command.logger = logger;
command.remoteUrl = toUrl;
command.repository = repository;
if (revision != null) {
command.additionalOptions.add(HG_FLAG_REV_CMD);
command.additionalOptions.add(revision);
}
if (branch != null) {
command.additionalOptions.add(HG_PARAM_BRANCH);
command.additionalOptions.add(branch);
command.additionalOptions.add(HG_PARAM_PUSH_NEW_BRANCH);
} else if (allowNewBranch) {
command.additionalOptions.add(HG_PARAM_PUSH_NEW_BRANCH);
}
command.urlPathProperties = new String[] {HgConfigFiles.HG_DEFAULT_PUSH};
List retval = command.invoke();
return retval;
}
/**
* Run the command hg view for the specified repository
*
* @param File repository of the mercurial repository's root directory
* @throws org.netbeans.modules.mercurial.HgException
*/
public static List doView(File repository, OutputLogger logger) throws HgException {
if (repository == null) return null;
List command = new ArrayList();
List env = new ArrayList();
command.add(getHgCommand());
command.add(HG_VIEW_CMD);
command.add(HG_OPT_REPOSITORY);
command.add(repository.getAbsolutePath());
List list;
if(HgUtils.isSolaris()){
env.add(HG_HGK_PATH_SOLARIS10_ENV);
list = execEnv(command, env);
}else{
list = exec(command);
}
if (!list.isEmpty()) {
if (isErrorNoView(list.get(list.size() -1))) {
throw new HgException(NbBundle.getMessage(HgCommand.class, "MSG_WARN_NO_VIEW_TEXT"));
}
else if (isErrorHgkNotFound(list.get(0)) || isErrorNoSuchFile(list.get(0))) {
OutputLogger.getLogger(repository).outputInRed(list.toString());
throw new HgException(NbBundle.getMessage(HgCommand.class, "MSG_WARN_HGK_NOT_FOUND_TEXT"));
} else if (isErrorAbort(list.get(list.size() -1))) {
handleError(command, list, NbBundle.getMessage(HgCommand.class, "MSG_COMMAND_ABORTED"), logger);
}
}
return list;
}
@Override
public abstract T call () throws HgException;
private static final ThreadLocal disabledUI = new ThreadLocal();
public static T runWithoutUI (Callable callable) throws HgException {
try {
disabledUI.set(true);
return callable.call();
} catch (HgException ex) {
throw ex;
} catch (Exception ex) {
Mercurial.LOG.log(Level.INFO, null, ex);
throw new HgException(ex.getMessage());
} finally {
disabledUI.remove();
}
}
private static String getGlobalProxyIfNeeded(String defaultPath, boolean bOutputDetails, OutputLogger logger){
String proxy = null;
if( defaultPath != null &&
(defaultPath.startsWith("http:") || // NOI18N
defaultPath.startsWith("https:"))) // NOI18N
{
URI uri = null;
try {
uri = new URI(defaultPath);
} catch (URISyntaxException ex) {
Mercurial.LOG.log(Level.INFO, null, ex);
}
String proxyHost = NetworkSettings.getProxyHost(uri);
// check DIRECT connection
if(proxyHost != null && proxyHost.length() > 0) {
proxy = proxyHost;
String proxyPort = NetworkSettings.getProxyPort(uri);
assert proxyPort != null;
proxy += !proxyPort.equals("") ? ":" + proxyPort : ""; // NOI18N
}
}
if(proxy != null && bOutputDetails){
logger.output(NbBundle.getMessage(HgCommand.class, "MSG_USING_PROXY_INFO", proxy)); // NOI18N
}
return proxy;
}
public static List doFetch(File repository, HgURL from, String revision, boolean enableFetchExtension, OutputLogger logger) throws HgException {
if (repository == null || from == null) return null;
InterRepositoryCommand command = new InterRepositoryCommand();
command.defaultUrl = new HgConfigFiles(repository).getDefaultPull(false);
command.hgCommandType = HG_FETCH_CMD;
command.logger = logger;
command.outputDetails = false;
command.remoteUrl = from;
command.repository = repository;
if (revision != null) {
command.additionalOptions.add(HG_FLAG_REV_CMD);
command.additionalOptions.add(revision);
}
command.additionalOptions.add(HG_VERBOSE_CMD);
if (enableFetchExtension && !"false".equals(System.getProperty("versioning.mercurial.enableFetchExtension"))) { //NOI18N
command.additionalOptions.add(HG_CONFIG_OPTION_CMD);
command.additionalOptions.add(HG_FETCH_EXT_CMD);
}
if (HgModuleConfig.getDefault().isInternalMergeToolEnabled()) {
command.additionalOptions.add(HG_CONFIG_OPTION_CMD);
command.additionalOptions.add(HG_MERGE_SIMPLE_TOOL);
}
command.showSaveOption = true;
command.urlPathProperties = new String[] {HgConfigFiles.HG_DEFAULT_PULL_VALUE, HgConfigFiles.HG_DEFAULT_PULL};
try {
// remove when rebase is implemented
if ("false".equals(System.getProperty("versioning.mercurial.enableFetchExtension"))) { //NOI18N
doNotAddHgPlain.set(true);
}
return command.invoke();
} finally {
doNotAddHgPlain.remove();
}
}
public static List processLogMessages (File root, List files, List list) {
return processLogMessages(root, files, list, false);
}
public static List processLogMessages (File root, List files, List list, boolean revertOrder) {
List messages = new ArrayList();
String rev, author, username, desc, date, id, parents, fm, fa, fd, fc, branches, tags;
List filesShortPaths = new ArrayList();
String rootPath = root.getAbsolutePath();
if (!rootPath.endsWith(File.separator)) {
rootPath = rootPath + File.separator;
}
if (list != null && !list.isEmpty()) {
if (files != null) {
for (File f : files) {
if (!f.isFile()) {
continue;
}
String shortPath = f.getAbsolutePath();
if (shortPath.startsWith(rootPath) && shortPath.length() > rootPath.length()) {
if (Utilities.isWindows()) {
filesShortPaths.add(shortPath.substring(rootPath.length()).replace(File.separatorChar, '/')); // NOI18N
} else {
filesShortPaths.add(shortPath.substring(rootPath.length())); // NOI18N
}
}
}
}
rev = author = username = desc = date = id = parents = fm = fa = fd = fc = null;
branches = tags = "";
boolean bEnd = false;
boolean stillInMessage = false; // commit message can have multiple lines !!!
for (String s : list) {
if (s.indexOf(HG_LOG_REVISION_OUT) == 0) {
rev = s.substring(HG_LOG_REVISION_OUT.length()).trim();
stillInMessage = false;
} else if (s.indexOf(HG_LOG_AUTHOR_OUT) == 0) {
author = s.substring(HG_LOG_AUTHOR_OUT.length()).trim();
stillInMessage = false;
} else if (s.indexOf(HG_LOG_USER_OUT) == 0) {
username = s.substring(HG_LOG_USER_OUT.length()).trim();
stillInMessage = false;
} else if (s.indexOf(HG_LOG_DESCRIPTION_OUT) == 0) {
desc = s.substring(HG_LOG_DESCRIPTION_OUT.length()).trim();
stillInMessage = true;
} else if (s.indexOf(HG_LOG_DATE_OUT) == 0) {
date = s.substring(HG_LOG_DATE_OUT.length()).trim();
stillInMessage = false;
} else if (s.indexOf(HG_LOG_ID_OUT) == 0) {
id = s.substring(HG_LOG_ID_OUT.length()).trim();
stillInMessage = false;
} else if (s.indexOf(HG_LOG_PARENTS_OUT) == 0) {
parents = s.substring(HG_LOG_PARENTS_OUT.length()).trim();
stillInMessage = false;
} else if (s.indexOf(HG_LOG_FILEMODS_OUT) == 0) {
fm = s.substring(HG_LOG_FILEMODS_OUT.length()).trim();
stillInMessage = false;
} else if (s.indexOf(HG_LOG_FILEADDS_OUT) == 0) {
fa = s.substring(HG_LOG_FILEADDS_OUT.length()).trim();
stillInMessage = false;
} else if (s.indexOf(HG_LOG_FILEDELS_OUT) == 0) {
fd = s.substring(HG_LOG_FILEDELS_OUT.length()).trim();
stillInMessage = false;
} else if (s.indexOf(HG_LOG_FILECOPIESS_OUT) == 0) {
fc = s.substring(HG_LOG_FILECOPIESS_OUT.length()).trim();
stillInMessage = false;
} else if (s.indexOf(HG_LOG_BRANCHES_OUT) == 0) {
branches = s.substring(HG_LOG_BRANCHES_OUT.length()).trim();
stillInMessage = false;
} else if (s.indexOf(HG_LOG_TAGS_OUT) == 0) {
tags = s.substring(HG_LOG_TAGS_OUT.length()).trim();
stillInMessage = false;
} else if (s.indexOf(HG_LOG_ENDCS_OUT) == 0) {
stillInMessage = false;
bEnd = true;
} else {
if (stillInMessage) {
// add next lines of commit message
desc += "\n" + s;
}
}
if (rev != null & bEnd) {
HgLogMessage hgMsg = new HgLogMessage(rootPath, filesShortPaths, rev, author, username, desc, date, id, parents, fm, fa, fd, fc, branches, tags);
messages.add(hgMsg);
rev = author = desc = date = id = parents = fm = fa = fd = fc = null;
bEnd = false;
}
}
}
if (revertOrder) {
Collections.reverse(messages);
}
return messages;
}
private static HgBranch[] processBranches (List lines, List heads) {
List branches = new ArrayList();
Pattern p = Pattern.compile("^(.+)(\\b\\d+):(\\S+)(.*)$"); //NOI18N
for (String line : lines) {
Matcher m = p.matcher(line);
if (!m.matches()){
Mercurial.LOG.log(Level.WARNING, "HgCommand.processBranches(): Failed when matching: {0}", new Object[] { line }); //NOI18N
} else {
String branchName = m.group(1).trim();
String revNumber = m.group(2).trim();
String changeSetId = m.group(3).trim();
String status = m.group(4).trim().toLowerCase();
HgLogMessage info = null;
for (HgLogMessage head : heads) {
if (head.getRevisionNumber().equals(revNumber) || head.getCSetShortID().equals(changeSetId)) {
info = head;
}
}
if (info == null) {
Mercurial.LOG.log(Level.WARNING, "HgCommand.processBranches(): Failed when pairing branch with head info : {0}:{1}:{2}\n{3}", //NOI18N
new Object[] { branchName, revNumber, changeSetId, heads });
} else {
boolean closed = false;
boolean active = true;
if (status.contains("inactive")) { //NOI18N
active = false;
} else if (status.contains("closed")) { //NOI18N
closed = true;
}
branches.add(new HgBranch(branchName, info, closed, active));
}
}
}
return branches.toArray(new HgBranch[0]);
}
private static HgTag[] processTags (List lines, File repository, OutputLogger logger) throws HgException {
class TagInfo {
String name;
String revNumber;
String changeSetId;
boolean local;
private TagInfo (String tagName, String revNumber, String changeSetId, boolean local) {
this.name = tagName;
this.revNumber = revNumber;
this.changeSetId = changeSetId;
this.local = local;
}
}
List tags = new ArrayList();
Pattern p = Pattern.compile("^(.+)(\\b\\d+):(\\S+)(.*)$"); //NOI18N
List tagInfos = new ArrayList(lines.size());
List revisions = new ArrayList(lines.size());
for (String line : lines) {
Matcher m = p.matcher(line);
if (!m.matches()) {
Mercurial.LOG.log(Level.WARNING, "HgCommand.processTags(): Failed when matching: {0}", new Object[] { line }); //NOI18N
} else {
String tagName = m.group(1).trim();
String revNumber = m.group(2).trim();
String changeSetId = m.group(3).trim();
String status = m.group(4).trim().toLowerCase();
boolean local = false;
if (status.contains("local")) { //NOI18N
local = true;
}
tagInfos.add(new TagInfo(tagName, revNumber, changeSetId, local));
revisions.add(revNumber);
}
}
List list = doLog(repository, revisions, -1, logger);
if (!list.isEmpty()) {
if (isErrorNoRepository(list.get(0))) {
handleError(null, list, NbBundle.getMessage(HgCommand.class, "MSG_NO_REPOSITORY_ERR"), logger); //NOI18N
} else if (isErrorAbort(list.get(0))) {
handleError(null, list, NbBundle.getMessage(HgCommand.class, "MSG_COMMAND_ABORTED"), logger); //NOI18N
}
}
List messages = processLogMessages(repository, null, list, false);
for (TagInfo t : tagInfos) {
HgLogMessage info = null;
for (HgLogMessage head : messages) {
if (head.getRevisionNumber().equals(t.revNumber) || head.getCSetShortID().equals(t.changeSetId)) {
info = head;
}
}
if (info == null) {
Mercurial.LOG.log(Level.WARNING, "HgCommand.processTags(): Failed when pairing tag with commit info : {0}:{1}:{2}\n{3}", //NOI18N
new Object[] { t.name, t.revNumber, t.changeSetId, messages });
} else {
tags.add(new HgTag(t.name, info, t.local, !HG_TIP_CONST.equals(t.name)));
}
}
return tags.toArray(new HgTag[0]);
}
public static HgLogMessage[] getIncomingMessages(final File root, String toRevision, String branchName,
boolean bShowMerges, boolean bGetFileInfo, boolean getParents,
int limitRevisions, OutputLogger logger) throws HgException {
List messages = Collections.emptyList();
try {
List list = HgCommand.doIncomingForSearch(root, toRevision, branchName, bShowMerges, bGetFileInfo, getParents, limitRevisions, logger);
messages = processLogMessages(root, null, list, true);
} finally {
logger.closeLog();
}
return messages.toArray(new HgLogMessage[0]);
}
public static HgLogMessage[] getOutMessages(final File root, String toRevision, String branchName,
boolean bShowMerges, boolean getParents, int limitRevisions, OutputLogger logger) throws HgException {
List messages = Collections.emptyList();
try {
List list = HgCommand.doOutForSearch(root, toRevision, branchName, bShowMerges, getParents, limitRevisions, logger);
messages = processLogMessages(root, null, list, true);
} finally {
logger.closeLog();
}
return messages.toArray(new HgLogMessage[0]);
}
public static HgLogMessage[] getLogMessagesNoFileInfo(final File root, final Set files, String fromRevision, String toRevision, boolean bShowMerges, int limitRevisions, List branchNames, OutputLogger logger) {
return getLogMessages(root, files, fromRevision, toRevision, bShowMerges, false, true, limitRevisions, branchNames, logger, true);
}
public static HgLogMessage[] getLogMessagesNoFileInfo(final File root, final Set files, int limit, OutputLogger logger) {
return getLogMessages(root, files, "0", HG_STATUS_FLAG_TIP_CMD, true, false, true, limit, Collections.emptyList(), logger, false);
}
public static HgLogMessage[] getLogMessages(final File root,
final Set files, String fromRevision, String toRevision,
boolean bShowMerges, boolean bGetFileInfo, boolean getParents, int limit, List branchNames, OutputLogger logger, boolean ascOrder) {
List messages = Collections.emptyList();
try {
String headRev = HgCommand.getLastRevision(root, null);
if (headRev == null) {
return messages.toArray(new HgLogMessage[0]);
}
List filesList = files != null ? new ArrayList(files) : null;
List list = HgCommand.doLog(root,
filesList,
fromRevision, toRevision, headRev, bShowMerges, bGetFileInfo, getParents, limit, branchNames, logger);
messages = processLogMessages(root, filesList, list, ascOrder);
} catch (HgException.HgCommandCanceledException ex) {
// do not take any action
} catch (HgException ex) {
HgUtils.notifyException(ex);
} finally {
if(logger != null) {
logger.closeLog();
}
}
return messages.toArray(new HgLogMessage[0]);
}
public static HgLogMessage[] getRevisionInfo (File root, List revisions, OutputLogger logger) {
List messages = Collections.emptyList();
try {
List list = HgCommand.doLog(root, revisions, -1, logger);
messages = processLogMessages(root, null, list, false);
} catch (HgException.HgCommandCanceledException ex) {
// do not take any action
} catch (HgException ex) {
HgUtils.notifyException(ex);
} finally {
if(logger != null) {
logger.closeLog();
}
}
return messages.toArray(new HgLogMessage[0]);
}
/**
* Determines whether anything has been committed to the repository
*
* @param File repository of the mercurial repository's root directory
* @return Boolean which is true if the repository has revision history.
*/
public static Boolean hasHistory(File repository) {
if (repository == null ) return false;
List command = new ArrayList();
command.add(getHgCommand());
command.add(HG_LOG_CMD);
command.add(HG_LOG_LIMIT_ONE_CMD);
command.add(HG_OPT_REPOSITORY);
command.add(repository.getAbsolutePath());
try {
List list = exec(command);
if (!list.isEmpty() && isErrorAbort(list.get(0)))
return false;
else
return !list.isEmpty();
} catch (HgException e) {
return false;
}
}
/**
* Determines the previous name of the specified file
* We make the assumption that the previous file name is in the
* cmdOutput of files returned by hg log command immediately befor
* the file we started with.
*
* @param File repository of the mercurial repository's root directory
* @param File file of the file whose previous name is required
* @param String revision which the revision to start from.
* @return File for the previous name of the file
*/
private static File getPreviousName(File repository, File file, String revision, boolean tryHard) throws HgException {
if (repository == null ) return null;
if (revision == null ) return null;
List command = new ArrayList();
command.add(getHgCommand());
command.add(HG_LOG_CMD);
command.add(HG_OPT_FOLLOW);
command.add(HG_OPT_REPOSITORY);
command.add(repository.getAbsolutePath());
command.add(HG_FLAG_REV_CMD);
command.add(revision);
List list = null;
File tempFolder = Utils.getTempFolder(false);
try {
command.add(prepareLogTemplate(tempFolder, HG_LOG_ONLY_FILE_COPIES_CHANGESET_NAME));
command.add(file.getAbsolutePath());
list = exec(command);
if (list.isEmpty() || isErrorAbort(list.get(0))) {
return null;
}
} catch (IOException ex) {
Mercurial.LOG.log(Level.INFO, null, ex);
throw new HgException(ex.getMessage());
} catch (HgException e) {
Mercurial.LOG.log(Level.WARNING, "command: {0}", HgUtils.replaceHttpPassword(command)); // NOI18N
Mercurial.LOG.log(e instanceof HgException.HgCommandCanceledException ? Level.FINE : Level.INFO, null, e); // NOI18N
throw e;
} finally {
Utils.deleteRecursively(tempFolder);
}
if(!tryHard) {
String[] fileNames = list.get(0).split("\t");
for (int j = 0; j < fileNames.length / 2; ++j) {
File name = new File(repository, fileNames[2 * j]);
if (name.equals(file)) {
return new File(repository, fileNames[2 * j + 1]);
}
}
}
return null;
}
/**
* Retrives the log information for the specified files.
*
* @param File repository of the mercurial repository's root directory
* @param List of files which revision history is to be retrieved.
* @param String Template specifying how output should be returned
* @param boolean flag indicating if debug param should be used - required to get all file mod, add, del info
* @param branchNames list of branches you want to browse - equiv to --branch
* @return List cmdOutput of the log entries for the specified file.
* @throws org.netbeans.modules.mercurial.HgException
*/
private static List doLog(File repository, List files,
String from, String to, String headRev, boolean bShowMerges, boolean bGetFileInfo, boolean getAllParents, int limit, List branchNames, OutputLogger logger) throws HgException {
List dateConstraints = new ArrayList();
String dateStr = handleRevDates(from, to);
if (dateStr != null) {
dateConstraints.add(HG_FLAG_DATE_CMD);
dateConstraints.add(dateStr);
}
List list = null;
// try first without and then with limiting the rev numbers
for (String lastRev : new String[] { null, headRev }) {
String revStr = handleRevNumbers(from, to, lastRev);
if (revStr == null) {
// from is probably higher than head revision, it's useless to run the command
return Collections.emptyList();
}
List constraints = new ArrayList(dateConstraints);
if (dateStr == null) {
constraints.add(HG_FLAG_REV_CMD);
constraints.add(revStr);
}
list = doLog(repository, files, constraints, bShowMerges, bGetFileInfo, getAllParents, limit, branchNames, logger);
if (list.size() > 0 && lastRev == null && isNoRevStrip(list.get(0))) {
// try again
} else {
break;
}
}
return list;
}
private static List doLog(File repository, List revisions, int limit, OutputLogger logger) throws HgException {
List constraints = new ArrayList(revisions.size() * 2);
for (String rev : revisions) {
constraints.add(HG_FLAG_REV_CMD);
constraints.add(rev);
}
return doLog(repository, null, constraints, true, false, false, limit, Collections.emptyList(), logger);
}
private static List doLog(File repository, List files,
List revisionConstraints, boolean bShowMerges, boolean bGetFileInfo, boolean getParents, int limit, List branchNames, OutputLogger logger) throws HgException {
if (repository == null ) return null;
if (files != null && files.isEmpty()) return null;
List command = new ArrayList();
command.add(getHgCommand());
command.add(HG_LOG_CMD);
command.add(HG_VERBOSE_CMD);
if (limit > 0) {
command.add(HG_LOG_LIMIT_CMD);
command.add(Integer.toString(limit));
}
boolean doFollow = false;
if( files != null){
doFollow = true;
for (File f : files) {
if (f.isDirectory()) {
doFollow = false;
break;
}
}
}
if (doFollow) {
command.add(HG_OPT_FOLLOW);
}
if(!bShowMerges){
command.add(HG_LOG_NO_MERGES_CMD);
}
command.add(HG_OPT_REPOSITORY);
command.add(repository.getAbsolutePath());
if (getParents) {
command.add(HG_LOG_DEBUG_CMD);
}
for (String rc : revisionConstraints) {
command.add(rc);
}
for (String branch : branchNames) {
command.add(HG_PARAM_BRANCH);
command.add(branch);
}
File tempFolder = Utils.getTempFolder(false);
try {
command.add(prepareLogTemplate(tempFolder, bGetFileInfo ? HG_LOG_FULL_CHANGESET_NAME : HG_LOG_BASIC_CHANGESET_NAME));
if (files != null) {
for (File f : files) {
command.add(f.getAbsolutePath());
}
}
List list = exec(command);
if (!list.isEmpty()) {
if (isErrorNoRepository(list.get(0))) {
handleError(command, list, NbBundle.getMessage(HgCommand.class, "MSG_NO_REPOSITORY_ERR"), logger);
} else if (isFollowNotAllowed(list.get(0))) {
// nothing
} else if (isErrorAbort(list.get(0))) {
if (isNoRevStrip(list.get(0))) {
// nothing, return error in the list
} else {
handleError(command, list, NbBundle.getMessage(HgCommand.class, "MSG_COMMAND_ABORTED"), logger);
}
}
}
return list;
} catch (IOException ex) {
Mercurial.LOG.log(Level.INFO, null, ex);
throw new HgException(ex.getMessage());
} finally {
Utils.deleteRecursively(tempFolder);
}
}
/**
* Retrives the tip information for the specified repository, as defined by the LOG_TEMPLATE.
*
* @param File repository of the mercurial repository's root directory
* @return List cmdOutput of the log entries for the tip
* @throws org.netbeans.modules.mercurial.HgException
*/
public static HgLogMessage doTip(File repository, OutputLogger logger) throws HgException {
if (repository == null ) return null;
List command = new ArrayList();
command.add(getHgCommand());
command.add(HG_TIP_CMD);
command.add(HG_OPT_REPOSITORY);
command.add(repository.getAbsolutePath());
File tempFolder = Utils.getTempFolder(false);
try {
command.add(prepareLogTemplate(tempFolder, HG_LOG_BASIC_CHANGESET_NAME));
List list = exec(command);
if (!list.isEmpty()) {
if (isErrorNoRepository(list.get(0))) {
handleError(command, list, NbBundle.getMessage(HgCommand.class, "MSG_NO_REPOSITORY_ERR"), logger);
} else if (isErrorAbort(list.get(0))) {
handleError(command, list, NbBundle.getMessage(HgCommand.class, "MSG_COMMAND_ABORTED"), logger);
}
}
List messages = processLogMessages(repository, null, list, false);
return messages.get(0);
} catch (IOException ex) {
Mercurial.LOG.log(Level.INFO, null, ex);
throw new HgException(ex.getMessage());
} finally {
Utils.deleteRecursively(tempFolder);
}
}
/**
* Retrives the Out information for the specified repository
*
* @param File repository of the mercurial repository's root directory
* @return List cmdOutput of the out entries for the specified repo.
* @throws org.netbeans.modules.mercurial.HgException
*/
public static List doOutForSearch(File repository, String to, String branchName, boolean bShowMerges, boolean getParents, int limit, OutputLogger logger) throws HgException {
if (repository == null ) return null;
String defaultPush = new HgConfigFiles(repository).getDefaultPush(false);
if (HgUtils.isNullOrEmpty(defaultPush)) {
Mercurial.LOG.log(Level.FINE, "No push url, falling back to command without target");
} else {
try {
HgURL pushUrl = new HgURL(defaultPush);
return doOutForSearch(repository, pushUrl, to, branchName, bShowMerges, getParents, limit, logger);
} catch (URISyntaxException ex) {
Mercurial.LOG.log(Level.INFO, "Invalid push url: {0}, falling back to command without target", defaultPush);
}
}
List command = new ArrayList();
command.add(getHgCommand());
command.add(HG_OUT_CMD);
command.add(HG_OPT_REPOSITORY);
command.add(repository.getAbsolutePath());
command.add(HG_NEWEST_FIRST);
if(!bShowMerges){
command.add(HG_LOG_NO_MERGES_CMD);
}
if (getParents) {
command.add(HG_LOG_DEBUG_CMD);
}
String revStr = handleIncomingRev(to);
if(revStr != null){
command.add(HG_FLAG_REV_CMD);
command.add(revStr);
}
if (branchName != null) {
command.add(HG_PARAM_BRANCH);
command.add(branchName);
}
if (limit > 0) {
command.add(HG_LOG_LIMIT_CMD);
command.add(Integer.toString(limit));
}
File tempFolder = Utils.getTempFolder(false);
try {
command.add(prepareLogTemplate(tempFolder, HG_LOG_BASIC_CHANGESET_NAME));
List list;
String proxy = getGlobalProxyIfNeeded(defaultPush, false, null);
if(proxy != null){
List env = new ArrayList();
env.add(HG_PROXY_ENV + proxy);
list = execEnv(command, env);
}else{
list = exec(command);
}
if (!list.isEmpty()) {
if(isErrorNoDefaultPush(list.get(0))){
// Ignore
}else if (isErrorNoRepository(list.get(0))) {
handleError(command, list, NbBundle.getMessage(HgCommand.class, "MSG_NO_REPOSITORY_ERR"), logger);
} else if (isErrorAbort(list.get(0))) {
handleError(command, list, NbBundle.getMessage(HgCommand.class, "MSG_COMMAND_ABORTED"), logger);
}
}
return list;
} catch (IOException ex) {
Mercurial.LOG.log(Level.INFO, null, ex);
throw new HgException(ex.getMessage());
} finally {
Utils.deleteRecursively(tempFolder);
}
}
private static List doOutForSearch (File repository, HgURL repositoryUrl, String to, String branchName,
boolean bShowMerges, boolean getParents, int limit, OutputLogger logger) throws HgException {
InterRepositoryCommand command = new InterRepositoryCommand();
command.defaultUrl = new HgConfigFiles(repository).getDefaultPush(false);
command.hgCommandType = HG_OUTGOING_CMD;
command.logger = logger;
command.outputDetails = false;
command.remoteUrl = repositoryUrl;
command.repository = repository;
command.additionalOptions.add(HG_OPT_REPOSITORY);
command.additionalOptions.add(repository.getAbsolutePath());
command.additionalOptions.add(HG_NEWEST_FIRST);
if(!bShowMerges){
command.additionalOptions.add(HG_LOG_NO_MERGES_CMD);
}
if (getParents) {
command.additionalOptions.add(HG_LOG_DEBUG_CMD);
}
String revStr = handleIncomingRev(to);
if(revStr != null){
command.additionalOptions.add(HG_FLAG_REV_CMD);
command.additionalOptions.add(revStr);
}
if (branchName != null) {
command.additionalOptions.add(HG_PARAM_BRANCH);
command.additionalOptions.add(branchName);
}
if (limit > 0) {
command.additionalOptions.add(HG_LOG_LIMIT_CMD);
command.additionalOptions.add(Integer.toString(limit));
}
File tempFolder = Utils.getTempFolder(false);
try {
command.additionalOptions.add(prepareLogTemplate(tempFolder, HG_LOG_BASIC_CHANGESET_NAME));
command.showSaveOption = true;
command.urlPathProperties = new String[] {HgConfigFiles.HG_DEFAULT_PUSH};
return command.invoke();
} catch (IOException ex) {
Mercurial.LOG.log(Level.INFO, null, ex);
throw new HgException(ex.getMessage());
} finally {
Utils.deleteRecursively(tempFolder);
}
}
/**
* Retrives the Incoming changeset information for the specified repository
*
* @param File repository of the mercurial repository's root directory
* @return List cmdOutput of the out entries for the specified repo.
* @throws org.netbeans.modules.mercurial.HgException
*/
public static List doIncomingForSearch(File repository, String to, String branchName,
boolean bShowMerges, boolean bGetFileInfo, boolean getParents,
int limit, OutputLogger logger) throws HgException {
if (repository == null ) return null;
String defaultPull = new HgConfigFiles(repository).getDefaultPull(false);
if (HgUtils.isNullOrEmpty(defaultPull)) {
Mercurial.LOG.log(Level.FINE, "No pull url, falling back to command without target");
} else {
try {
HgURL pullUrl = new HgURL(defaultPull);
return doIncomingForSearch(repository, pullUrl, to, branchName, bShowMerges, bGetFileInfo, getParents, limit, logger);
} catch (URISyntaxException ex) {
Mercurial.LOG.log(Level.INFO, "Invalid pull url: {0}, falling back to command without target", defaultPull);
}
}
List command = new ArrayList();
command.add(getHgCommand());
command.add(HG_INCOMING_CMD);
command.add(HG_OPT_REPOSITORY);
command.add(repository.getAbsolutePath());
command.add(HG_NEWEST_FIRST);
if(!bShowMerges){
command.add(HG_LOG_NO_MERGES_CMD);
}
if (getParents) {
command.add(HG_LOG_DEBUG_CMD);
}
String revStr = handleIncomingRev(to);
if(revStr != null){
command.add(HG_FLAG_REV_CMD);
command.add(revStr);
}
if (branchName != null) {
command.add(HG_PARAM_BRANCH);
command.add(branchName);
}
if (limit > 0) {
command.add(HG_LOG_LIMIT_CMD);
command.add(Integer.toString(limit));
}
File tempFolder = Utils.getTempFolder(false);
try {
command.add(prepareLogTemplate(tempFolder, bGetFileInfo ? HG_LOG_FULL_CHANGESET_NAME : HG_LOG_BASIC_CHANGESET_NAME));
List list;
String proxy = getGlobalProxyIfNeeded(defaultPull, false, null);
if (proxy != null) {
List env = new ArrayList();
env.add(HG_PROXY_ENV + proxy);
list = execEnv(command, env);
} else {
list = exec(command);
}
if (!list.isEmpty()) {
if (isErrorNoDefaultPath(list.get(0))) {
// Ignore
} else if (isErrorNoRepository(list.get(0))) {
handleError(command, list, NbBundle.getMessage(HgCommand.class, "MSG_NO_REPOSITORY_ERR"), logger);
} else if (isErrorAbort(list.get(0)) || isErrorAbort(list.get(list.size() - 1))) {
handleError(command, list, NbBundle.getMessage(HgCommand.class, "MSG_COMMAND_ABORTED"), logger);
}
}
return list;
} catch (IOException ex) {
Mercurial.LOG.log(Level.INFO, null, ex);
throw new HgException(ex.getMessage());
} finally {
Utils.deleteRecursively(tempFolder);
}
}
public static List getBundleChangesets (File repository, File bundleFile, OutputLogger logger) throws HgException {
if (repository == null ) return null;
List command = new ArrayList();
command.add(getHgCommand());
command.add(HG_INCOMING_CMD);
command.add(bundleFile.getAbsolutePath());
command.add(HG_OPT_REPOSITORY);
command.add(repository.getAbsolutePath());
File tempFolder = Utils.getTempFolder(false);
try {
command.add(prepareLogTemplate(tempFolder, HG_LOG_BASIC_CHANGESET_NAME));
List list;
list = exec(command);
if (!list.isEmpty()) {
if (isErrorNoRepository(list.get(0))) {
handleError(command, list, NbBundle.getMessage(HgCommand.class, "MSG_NO_REPOSITORY_ERR"), logger);
} else if (isErrorAbort(list.get(0)) || isErrorAbort(list.get(list.size() - 1))) {
handleError(command, list, NbBundle.getMessage(HgCommand.class, "MSG_COMMAND_ABORTED"), logger);
}
}
return processLogMessages(repository, null, list);
} catch (IOException ex) {
Mercurial.LOG.log(Level.INFO, null, ex);
throw new HgException(ex.getMessage());
} finally {
Utils.deleteRecursively(tempFolder);
}
}
private static List doIncomingForSearch (File repository, HgURL repositoryUrl, String to, String branchName,
boolean bShowMerges, boolean bGetFileInfo, boolean getParents, int limit, OutputLogger logger) throws HgException {
InterRepositoryCommand command = new InterRepositoryCommand();
command.defaultUrl = new HgConfigFiles(repository).getDefaultPull(false);
command.hgCommandType = HG_INCOMING_CMD;
command.logger = logger;
command.outputDetails = false;
command.remoteUrl = repositoryUrl;
command.repository = repository;
command.additionalOptions.add(HG_VERBOSE_CMD);
command.additionalOptions.add(HG_OPT_REPOSITORY);
command.additionalOptions.add(repository.getAbsolutePath());
command.additionalOptions.add(HG_NEWEST_FIRST);
if(!bShowMerges){
command.additionalOptions.add(HG_LOG_NO_MERGES_CMD);
}
if (getParents) {
command.additionalOptions.add(HG_LOG_DEBUG_CMD);
}
String revStr = handleIncomingRev(to);
if(revStr != null){
command.additionalOptions.add(HG_FLAG_REV_CMD);
command.additionalOptions.add(revStr);
}
if (branchName != null) {
command.additionalOptions.add(HG_PARAM_BRANCH);
command.additionalOptions.add(branchName);
}
if (limit > 0) {
command.additionalOptions.add(HG_LOG_LIMIT_CMD);
command.additionalOptions.add(Integer.toString(limit));
}
command.showSaveOption = true;
command.urlPathProperties = new String[] {HgConfigFiles.HG_DEFAULT_PULL_VALUE, HgConfigFiles.HG_DEFAULT_PULL};
File tempFolder = Utils.getTempFolder(false);
try {
command.additionalOptions.add(prepareLogTemplate(tempFolder, bGetFileInfo ? HG_LOG_FULL_CHANGESET_NAME : HG_LOG_BASIC_CHANGESET_NAME));
return command.invoke();
} catch (IOException ex) {
Mercurial.LOG.log(Level.INFO, null, ex);
throw new HgException(ex.getMessage());
} finally {
Utils.deleteRecursively(tempFolder);
}
}
private static String handleRevDates(String from, String to){
// Check for Date range:
Date fromDate = null;
Date toDate = null;
Date currentDate = new Date(); // Current Date
Date epochPlusOneDate = null;
try {
epochPlusOneDate = new SimpleDateFormat("yyyy-MM-dd").parse(HG_EPOCH_PLUS_ONE_YEAR); // NOI18N
} catch (ParseException ex) {
// Ignore invalid dates
}
// Set From date
try {
if(from != null)
fromDate = new SimpleDateFormat("yyyy-MM-dd").parse(from); // NOI18N
} catch (ParseException ex) {
// Ignore invalid dates
}
// Set To date
try {
if(to != null)
toDate = new SimpleDateFormat("yyyy-MM-dd").parse(to); // NOI18N
} catch (ParseException ex) {
// Ignore invalid dates
}
// If From date is set, but To date is not - default To date to current date
if( fromDate != null && toDate == null && to == null){
toDate = currentDate;
to = new SimpleDateFormat("yyyy-MM-dd").format(toDate);
}
// If To date is set, but From date is not - default From date to 1971-01-01
if (fromDate == null && from == null && toDate != null) {
fromDate = epochPlusOneDate;
from = HG_EPOCH_PLUS_ONE_YEAR; // NOI18N
}
// If using dates make sure both From and To are set to dates
if( (fromDate != null && toDate == null && to != null) ||
(fromDate == null && from != null && toDate != null)){
HgUtils.warningDialog(HgCommand.class,"MSG_SEARCH_HISTORY_TITLE",// NOI18N
"MSG_SEARCH_HISTORY_WARN_BOTHDATES_NEEDED_TEXT"); // NOI18N
return null;
}
if(fromDate != null && toDate != null){
// Check From date - default to 1971-01-01 if From date is earlier than this
if(epochPlusOneDate != null && fromDate.before(epochPlusOneDate)){
fromDate = epochPlusOneDate;
from = HG_EPOCH_PLUS_ONE_YEAR; // NOI18N
}
// Set To date - default to current date if To date is later than this
if(currentDate != null && toDate.after(currentDate)){
toDate = currentDate;
to = new SimpleDateFormat("yyyy-MM-dd").format(toDate);
}
// Make sure the From date is before the To date
if( fromDate.after(toDate)){
HgUtils.warningDialog(HgCommand.class,"MSG_SEARCH_HISTORY_TITLE",// NOI18N
"MSG_SEARCH_HISTORY_WARN_FROM_BEFORE_TODATE_NEEDED_TEXT"); // NOI18N
return null;
}
return from + " to " + to; // NOI18N
}
return null;
}
private static String handleIncomingRev(String to) {
// Handle users entering head or tip for revision, instead of a number
if (to != null && (to.equalsIgnoreCase(HG_STATUS_FLAG_TIP_CMD) || to.equalsIgnoreCase(HG_HEAD_STR))) {
to = HG_STATUS_FLAG_TIP_CMD;
}
return to;
}
/**
*
* @param from
* @param to
* @param headRev if not null
then from and to are compared to headRev and a relevant value is returned
* @return revision string or null if headRev is not null and from is outside of valid limits - e.g. from is higher than headRev
*/
private static String handleRevNumbers(String from, String to, String headRev){
int fromInt = -1;
int toInt = -1;
int headRevInt = -1;
// Handle users entering head or tip for revision, instead of a number
if(headRev != null && from != null && (from.equalsIgnoreCase(HG_STATUS_FLAG_TIP_CMD) || from.equalsIgnoreCase(HG_HEAD_STR)))
from = headRev;
if(headRev != null && to != null && (to.equalsIgnoreCase(HG_STATUS_FLAG_TIP_CMD) || to.equalsIgnoreCase(HG_HEAD_STR)))
to = headRev;
try{
fromInt = Integer.parseInt(from);
}catch (NumberFormatException e){
// ignore invalid numbers
}
try{
toInt = Integer.parseInt(to);
}catch (NumberFormatException e){
// ignore invalid numbers
}
try{
if (headRev != null) {
headRevInt = Integer.parseInt(headRev);
}
}catch (NumberFormatException e){
// ignore invalid numbers
}
// Handle out of range revisions
if (headRevInt > -1 && toInt > headRevInt) {
to = headRev;
toInt = headRevInt;
}
if (headRevInt > -1 && fromInt > headRevInt) {
return null;
}
// Handle revision ranges
String revStr = null;
if (fromInt > -1 && toInt > -1){
revStr = to + ":" + from;
}else if (fromInt > -1){
revStr = (headRevInt != -1 ? headRevInt + ":" : "tip:") + from;
}else if (toInt > -1){
revStr = to + ":0";
}
if(revStr == null) {
if(to == null) {
to = HG_STATUS_FLAG_TIP_CMD;
}
if(from == null) {
from = "0";
}
revStr = to + ":" + from;
}
return revStr;
}
/**
* Retrieves the base revision of the specified file to the
* specified output file.
*
* @param File repository of the mercurial repository's root directory
* @param File file in the mercurial repository
* @param File outFile to contain the contents of the file
* @throws org.netbeans.modules.mercurial.HgException
*/
public static void doCat(File repository, File file, File outFile, OutputLogger logger) throws HgException {
doCat(repository, file, outFile, null, true, logger); //NOI18N
}
public static void doCat(File repository, File file, File outFile, String revision, OutputLogger logger) throws HgException {
doCat(repository, file, outFile, revision, logger, true);
}
/**
* Retrieves the specified revision of the specified file to the
* specified output file.
*
* @param File repository of the mercurial repository's root directory
* @param File file in the mercurial repository
* @param File outFile to contain the contents of the file
* @param String of revision for the revision of the file to be
* printed to the output file.
* @return List cmdOutput of all the log entries
* @throws org.netbeans.modules.mercurial.HgException
*/
public static void doCat(File repository, File file, File outFile, String revision, OutputLogger logger, boolean tryHard) throws HgException {
doCat(repository, file, outFile, revision, true, logger); //NOI18N
}
public static void doCat(File repository, File file, File outFile, String revision, boolean retry, OutputLogger logger) throws HgException {
doCat(repository, file, outFile, revision, retry, logger, true);
}
public static void doCat(File repository, File file, File outFile, String revision, boolean retry, OutputLogger logger, boolean tryHard) throws HgException {
if (repository == null) return;
if (file == null) return;
List command = new ArrayList();
command.add(getHgCommand());
command.add(HG_CAT_CMD);
command.add(HG_OPT_REPOSITORY);
command.add(repository.getAbsolutePath());
command.add(HG_FLAG_OUTPUT_CMD);
command.add(outFile.getAbsolutePath());
if (revision != null) {
command.add(HG_FLAG_REV_CMD);
command.add(revision);
}
try {
// cmd returns error if there are simlinks in absolute path and file is deleted
// abort: /path/file not under root
command.add(file.getCanonicalPath());
} catch (IOException e) {
Mercurial.LOG.log(Level.WARNING, "command: {0}", HgUtils.replaceHttpPassword(command)); // NOI18N
Mercurial.LOG.log(Level.INFO, null, e); // NOI18N
throw new HgException(e.getMessage());
}
List list = exec(command);
if (!list.isEmpty()) {
if (isErrorNoRepository(list.get(0))) {
handleError(command, list, NbBundle.getMessage(HgCommand.class, "MSG_NO_REPOSITORY_ERR"), logger);
} else if (isErrorAbort(list.get(0))) {
handleError(command, list, NbBundle.getMessage(HgCommand.class, "MSG_COMMAND_ABORTED"), logger);
}
}
if (outFile.length() == 0 && retry) {
if (revision == null) {
// maybe the file is copied?
FileInformation fi = getStatus(repository, Collections.singletonList(file), null, null, true).get(file);
if (fi != null && fi.getStatus(null) != null && fi.getStatus(null).getOriginalFile() != null) {
doCat(repository, fi.getStatus(null).getOriginalFile(), outFile, revision, false, logger);
}
} else {
// Perhaps the file has changed its name
try {
String newRevision = Integer.toString(Integer.parseInt(revision)+1);
File prevFile = getPreviousName(repository, file, newRevision, tryHard);
if (prevFile != null) {
doCat(repository, prevFile, outFile, revision, false, logger); //NOI18N
}
} catch (NumberFormatException ex) {
// revision is not a number
}
}
}
}
/**
* Get common ancestor for two provided revisions.
*
* @param root for the mercurial repository
* @param first rev to get ancestor for
* @param second rev to get ancestor for
* @param output logger
* @return void
* @throws org.netbeans.modules.mercurial.HgException
*/
public static HgRevision getCommonAncestor(String rootURL, String rev1, String rev2, OutputLogger logger) throws HgException {
HgRevision res = getCommonAncestor(rootURL, rev1, rev2, false, logger);
if( res == null){
res = getCommonAncestor(rootURL, rev1, rev2, true, logger);
}
return res;
}
private static HgRevision getCommonAncestor(String rootURL, String rev1, String rev2, boolean bUseIndex, OutputLogger logger) throws HgException {
if (rootURL == null ) return null;
List command = new ArrayList();
command.add(getHgCommand());
command.add(HG_COMMONANCESTOR_CMD);
if(bUseIndex){
command.add(".hg/store/00changelog.i"); //NOI18N
}
command.add(rev1);
command.add(rev2);
command.add(HG_OPT_REPOSITORY);
command.add(rootURL);
command.add(HG_OPT_CWD_CMD);
command.add(rootURL);
List list = exec(command);
if (!list.isEmpty()){
String splits[] = list.get(0).split(":"); // NOI18N
String tmp = splits != null && splits.length >= 1 ? splits[0]: null;
String tmpId = splits != null && splits.length >= 2 ? splits[1]: null;
int tmpRev = -1;
try{
tmpRev = Integer.parseInt(tmp);
}catch(NumberFormatException ex){
// Ignore
}
return tmpRev > -1 ? new HgRevision(tmpId, tmp): null;
} else {
return null;
}
}
/**
* Initialize a new repository in the given directory. If the given
* directory does not exist, it is created. Will throw a HgException
* if the repository already exists.
*
* @param root for the mercurial repository
* @return void
* @throws org.netbeans.modules.mercurial.HgException
*/
public static void doCreate(File root, OutputLogger logger) throws HgException {
if (root == null ) return;
List command = new ArrayList();
command.add(getHgCommand());
command.add(HG_CREATE_CMD);
command.add(root.getAbsolutePath());
List list = exec(command);
if (!list.isEmpty())
handleError(command, list, NbBundle.getMessage(HgCommand.class, "MSG_CREATE_FAILED"), logger);
}
/**
* Clone an exisiting repository to the specified target directory
*
* @param File repository of the mercurial repository's root directory
* @param target directory to clone to
* @return clone output
* @throws org.netbeans.modules.mercurial.HgException
*/
public static List doClone(File repository, File target, OutputLogger logger) throws HgException {
if (repository == null) return null;
return doClone(new HgURL(repository), target, logger);
}
/**
* Clone a repository to the specified target directory
*
* @param String repository of the mercurial repository
* @param target directory to clone to
* @return clone output
* @throws org.netbeans.modules.mercurial.HgException
*/
public static List doClone(HgURL repository, File target, OutputLogger logger) throws HgException {
if (repository == null || target == null) return null;
// Ensure that parent directory of target exists, creating if necessary
File parentTarget = target.getParentFile();
try {
if (!parentTarget.mkdirs()) {
if (!parentTarget.isDirectory()) {
Mercurial.LOG.log(Level.WARNING, "File.mkdir() failed for : {0}", parentTarget.getAbsolutePath()); // NOI18N
throw (new HgException (NbBundle.getMessage(HgCommand.class, "MSG_UNABLE_TO_CREATE_PARENT_DIR"))); // NOI18N
}
}
} catch (SecurityException e) {
Mercurial.LOG.log(Level.WARNING, "File.mkdir() for : {0} threw SecurityException {1}", new Object[]{parentTarget.getAbsolutePath(), e.getMessage()}); // NOI18N
throw (new HgException (NbBundle.getMessage(HgCommand.class, "MSG_UNABLE_TO_CREATE_PARENT_DIR"))); // NOI18N
}
List list = null;
boolean retry = true;
PasswordAuthentication credentials = null;
String rawUrl = repository.toUrlStringWithoutUserInfo();
HgURL url = repository;
while (retry) {
retry = false;
try {
if (credentials != null) {
url = new HgURL(repository.toHgCommandUrlString(), credentials.getUserName(), credentials.getPassword());
}
} catch (URISyntaxException ex) {
// this should NEVER happen
Mercurial.LOG.log(Level.SEVERE, null, ex);
break;
}
List command = new ArrayList();
command.add(getHgCommand());
command.add(HG_CLONE_CMD);
command.add(HG_VERBOSE_CMD);
command.add(url);
command.add(target); // target must be the last argument
String proxy = getGlobalProxyIfNeeded(url.toUrlStringWithoutUserInfo(), true, logger);
if (proxy != null) {
List env = new ArrayList();
env.add(HG_PROXY_ENV + proxy);
list = execEnv(command, env);
} else {
list = exec(command);
}
try {
if (!list.isEmpty()) {
if (isErrorNoRepository(list.get(0))) {
handleError(command, list, NbBundle.getMessage(HgCommand.class, "MSG_NO_REPOSITORY_ERR"), logger);
} else if (isErrorNoResponse(list.get(list.size() - 1))) {
handleError(command, list, NbBundle.getMessage(HgCommand.class, "MSG_NO_RESPONSE_ERR"), logger);
} else if (isErrorAbort(list.get(0)) || isErrorAbort(list.get(list.size() - 1))) {
if ((credentials = handleAuthenticationError(list, target, rawUrl, credentials == null ? "" : credentials.getUserName(), new UserCredentialsSupport(), HG_CLONE_CMD)) != null) { //NOI18N
// try again with new credentials
retry = true;
} else {
handleError(command, list, NbBundle.getMessage(HgCommand.class, "MSG_COMMAND_ABORTED"), logger);
}
} else {
// save credentials
if (url.getPassword() != null) {
try {
HgModuleConfig.getDefault().setProperty(target, HgConfigFiles.HG_DEFAULT_PULL,
new HgURL(url.toUrlStringWithoutUserInfo(), url.getUsername(), null).toCompleteUrlString());
} catch (URISyntaxException ex) {
Mercurial.LOG.log(Level.INFO, null, ex);
} catch (IOException ex) {
Mercurial.LOG.log(Level.INFO, null, ex);
}
KeyringSupport.save(HgUtils.PREFIX_VERSIONING_MERCURIAL_URL, url.toHgCommandStringWithNoPassword(), url.getPassword().clone(), null);
}
}
}
} finally {
if (url != repository) {
url.clearPassword();
}
}
}
return list;
}
/**
* Commits the cmdOutput of Locally Changed files to the mercurial Repository
*
* @param File repository of the mercurial repository's root directory
* @param List of files to be committed to hg
* @param String for commitMessage
* @return void
* @throws org.netbeans.modules.mercurial.HgException
*/
public static void doCommit(File repository, List commitFiles, String commitMessage, OutputLogger logger) throws HgException {
doCommit(repository, commitFiles, commitMessage, null, false, logger);
}
/**
* Commits the cmdOutput of Locally Changed files to the mercurial Repository
*
* @param File repository of the mercurial repository's root directory
* @param List of files to be committed to hg
* @param commitMessage for commitMessage
* @param user author of the commit or null
if to use the default committer
* @param closeBranch runs commit with --close-branch option
* @return void
* @throws org.netbeans.modules.mercurial.HgException
*/
public static void doCommit(File repository, List commitFiles, String commitMessage, String user,
boolean closeBranch, OutputLogger logger) throws HgException {
List command = new ArrayList();
command.add(getHgCommand());
command.add(HG_COMMIT_CMD);
command.add(HG_OPT_REPOSITORY);
command.add(repository.getAbsolutePath());
command.add(HG_OPT_CWD_CMD);
command.add(repository.getAbsolutePath());
if (user == null) {
String projectUserName = new HgConfigFiles(repository).getUserName(false);
String globalUsername = HgModuleConfig.getDefault().getSysUserName();
if (projectUserName != null && projectUserName.length() > 0) {
user = projectUserName;
} else if (globalUsername != null && globalUsername.length() > 0) {
user = globalUsername;
}
}
if(user != null ){
command.add(HG_OPT_USERNAME);
command.add(user);
}
if (closeBranch) {
command.add(HG_OPT_CLOSE_BRANCH);
}
File tempfile = null;
try {
if (commitMessage == null || commitMessage.length() == 0) {
commitMessage = HG_COMMIT_DEFAULT_MESSAGE;
}
// Create temporary file.
tempfile = Files.createTempFile(HG_COMMIT_TEMPNAME, HG_COMMIT_TEMPNAME_SUFFIX).toFile();
// Write to temp file
BufferedWriter out = new BufferedWriter(ENCODING == null
? new OutputStreamWriter(new FileOutputStream(tempfile))
: new OutputStreamWriter(new FileOutputStream(tempfile), ENCODING));
out.write(commitMessage);
out.close();
command.add(HG_COMMIT_OPT_LOGFILE_CMD);
command.add(tempfile.getAbsolutePath());
String repoPath = repository.getAbsolutePath();
if (!repoPath.endsWith(File.separator)) {
repoPath = repoPath + File.separator;
}
for(File f: commitFiles){
if (f.getAbsolutePath().length() <= repoPath.length()) {
// list contains the root itself
command.add(f.getAbsolutePath());
} else {
command.add(f.getAbsolutePath().substring(repoPath.length()));
}
}
if(Utilities.isWindows()) {
int size = 0;
// Count size of command
for (String line : command) {
size += line.length();
}
if (isTooLongCommand(size)) {
throw new HgException.HgTooLongArgListException(NbBundle.getMessage(HgCommand.class, "MSG_ARG_LIST_TOO_LONG_ERR", command.get(1), command.size() -2 )); //NOI18N
}
}
List list = exec(command);
//#132984: range of issues with upgrade to Hg 1.0, new restriction whereby you cannot commit using explicit file names after a merge.
if (!list.isEmpty() && isCommitAfterMerge(list.get(list.size() -1))) {
throw new HgException(COMMIT_AFTER_MERGE);
}
if (!list.isEmpty()
&& (isErrorNotTracked(list.get(0)) ||
isErrorCannotReadCommitMsg(list.get(0)) ||
isErrorAbort(list.get(list.size() -1)) ||
isErrorAbort(list.get(0))))
handleError(command, list, NbBundle.getMessage(HgCommand.class, "MSG_COMMIT_FAILED"), logger);
}catch (IOException ex){
throw new HgException(NbBundle.getMessage(HgCommand.class, "MSG_FAILED_TO_READ_COMMIT_MESSAGE"));
}finally{
if (commitMessage != null && tempfile != null){
tempfile.delete();
}
}
}
/**
* Rename a source file to a destination file.
* mercurial hg rename
*
* @param File repository of the mercurial repository's root directory
* @param File of sourceFile which was renamed
* @param File of destFile to which sourceFile has been renaned
* @param boolean whether to do a rename --after
* @return void
* @throws org.netbeans.modules.mercurial.HgException
*/
public static void doRename(File repository, File sourceFile, File destFile, OutputLogger logger) throws HgException {
doRename(repository, sourceFile, destFile, false, logger);
}
private static void doRename(File repository, File sourceFile, File destFile, boolean bAfter, OutputLogger logger) throws HgException {
if (repository == null) return;
List command = new ArrayList();
command.add(getHgCommand());
command.add(HG_RENAME_CMD);
if (bAfter) command.add(HG_RENAME_AFTER_CMD);
command.add(HG_OPT_REPOSITORY);
command.add(repository.getAbsolutePath());
command.add(HG_OPT_CWD_CMD);
command.add(repository.getAbsolutePath());
String repoPath = repository.getAbsolutePath();
if (!repoPath.endsWith(File.separator)) {
repoPath = repoPath + File.separator;
}
command.add(sourceFile.getAbsolutePath().substring(repoPath.length()));
command.add(destFile.getAbsolutePath().substring(repoPath.length()));
List list = exec(command);
if (!list.isEmpty() &&
isErrorAbort(list.get(list.size() -1))) {
if (!bAfter || !isErrorAbortNoFilesToCopy(list.get(list.size() -1))) {
handleError(command, list, NbBundle.getMessage(HgCommand.class, "MSG_RENAME_FAILED"), logger);
}
}
}
/**
* Mark a source file as having been renamed to a destination file.
* mercurial hg rename -A.
*
* @param File repository of the mercurial repository's root directory
* @param File of sourceFile which was renamed
* @param File of destFile to which sourceFile has been renaned
* @return void
* @throws org.netbeans.modules.mercurial.HgException
*/
public static void doRenameAfter(File repository, File sourceFile, File destFile, OutputLogger logger) throws HgException {
doRename(repository, sourceFile, destFile, true, logger);
}
/**
* Copy a source file to a destination file.
* mercurial hg copy
*
* @param File repository of the mercurial repository's root directory
* @param File of sourceFile which was copied
* @param File of destFile to which sourceFile has been copied
* @param boolean whether to do a copy --after
* @return void
* @throws org.netbeans.modules.mercurial.HgException
*/
public static void doCopy (File repository, File sourceFile, File destFile, boolean bAfter, OutputLogger logger) throws HgException {
if (repository == null) return;
List command = new ArrayList();
command.add(getHgCommand());
command.add(HG_COPY_CMD);
if (bAfter) command.add(HG_COPY_AFTER_CMD);
command.add(HG_OPT_REPOSITORY);
command.add(repository.getAbsolutePath());
command.add(HG_OPT_CWD_CMD);
command.add(repository.getAbsolutePath());
command.add(sourceFile.getAbsolutePath().substring(repository.getAbsolutePath().length() + 1));
command.add(destFile.getAbsolutePath().substring(repository.getAbsolutePath().length() + 1));
List list = exec(command);
if (!list.isEmpty() &&
isErrorAbort(list.get(list.size() -1))) {
if (!bAfter || !isErrorAbortNoFilesToCopy(list.get(list.size() -1))) {
handleError(command, list, NbBundle.getMessage(HgCommand.class, "MSG_COPY_FAILED"), logger);
}
}
}
/**
* Adds the cmdOutput of Locally New files to the mercurial Repository
* Their status will change to added and they will be added on the next
* mercurial hg add.
*
* @param File repository of the mercurial repository's root directory
* @param List of files to be added to hg
* @return void
* @throws org.netbeans.modules.mercurial.HgException
*/
public static void doAdd(File repository, List addFiles, OutputLogger logger) throws HgException {
if (repository == null) return;
if (addFiles.isEmpty()) return;
List basicCommand = new ArrayList();
basicCommand.add(getHgCommand());
basicCommand.add(HG_ADD_CMD);
basicCommand.add(HG_OPT_REPOSITORY);
basicCommand.add(repository.getAbsolutePath());
List> attributeGroups = splitAttributes(repository, basicCommand, addFiles, false);
for (List attributes : attributeGroups) {
List command = new ArrayList(basicCommand);
command.addAll(attributes);
List list = exec(command);
if (!list.isEmpty() && !isErrorAlreadyTracked(list.get(0)) && !isAddingLine(list.get(0))) {
if (getFilesWithPerformanceWarning(list).isEmpty()) {
// XXX we could notify the user about the performance warning and abort the command
handleError(command, list, list.get(0), logger);
}
}
}
}
/**
* Reverts the cmdOutput of files in the mercurial Repository to the specified revision
*
* @param File repository of the mercurial repository's root directory
* @param List of files to be reverted
* @param String revision to be reverted to
* @return void
* @throws org.netbeans.modules.mercurial.HgException
*/
public static void doRevert(File repository, List revertFiles,
String revision, boolean doBackup, OutputLogger logger) throws HgException {
if (repository == null) return;
if (revertFiles.isEmpty()) return;
final List command = new ArrayList();
command.add(getHgCommand());
command.add(HG_REVERT_CMD);
if(!doBackup){
command.add(HG_REVERT_NOBACKUP_CMD);
}
command.add(HG_OPT_REPOSITORY);
command.add(repository.getAbsolutePath());
if (revision != null){
command.add(HG_FLAG_REV_CMD);
command.add(revision);
}
for(File f: revertFiles){
command.add(f.getAbsolutePath());
}
List list = exec(command);
if (!list.isEmpty() && isErrorNoChangeNeeded(list.get(0)))
handleError(command, list, NbBundle.getMessage(HgCommand.class, "MSG_REVERT_FAILED"), logger);
}
/**
* Removes newly added files and folders under revertFiles
* @param repository
* @param revertFiles
* @param excludedPaths
* @param logger
* @throws HgException
*/
public static void doPurge (File repository, List revertFiles, List excludedPaths, OutputLogger logger) throws HgException {
if (repository == null) return;
final List command = new ArrayList();
command.add(getHgCommand());
command.add(HG_PURGE_CMD);
command.add(HG_CONFIG_OPTION_CMD);
command.add(HG_EXT_PURGE);
command.add(HG_OPT_REPOSITORY);
command.add(repository.getAbsolutePath());
for (String excluded : excludedPaths) {
command.add(HG_OPT_EXCLUDE);
command.add(excluded);
}
for (File f : revertFiles){
command.add(f.getAbsolutePath());
}
List list = exec(command);
if (!list.isEmpty())
handleError(command, list, NbBundle.getMessage(HgCommand.class, "MSG_REVERT_FAILED"), logger);
}
/**
* Adds a Locally New file to the mercurial Repository
* The status will change to added and they will be added on the next
* mercurial hg commit.
*
* @param File repository of the mercurial repository's root directory
* @param File of file to be added to hg
* @return void
* @throws org.netbeans.modules.mercurial.HgException
*/
public static void doAdd(File repository, File file, OutputLogger logger) throws HgException {
if (repository == null) return;
if (file == null) return;
if (file.isDirectory()) return;
// We do not look for file to ignore as we should not here
// with a file to be ignored.
List command = new ArrayList();
command.add(getHgCommand());
command.add(HG_ADD_CMD);
command.add(HG_OPT_REPOSITORY);
command.add(repository.getAbsolutePath());
command.add(file.getAbsolutePath());
List list = exec(command);
if (!list.isEmpty() && isErrorAlreadyTracked(list.get(0)))
handleError(command, list, NbBundle.getMessage(HgCommand.class, "MSG_ALREADY_TRACKED"), logger);
}
/**
* Get the annotations for the specified file
*
* @param File repository of the mercurial repository
* @param File file to be annotated
* @param String revision of the file to be annotated
* @return List cmdOutput of the annotated lines of the file
* @throws org.netbeans.modules.mercurial.HgException
*/
public static List doAnnotate(File repository, File file, String revision, OutputLogger logger) throws HgException {
if (repository == null) return null;
List command = new ArrayList();
command.add(getHgCommand());
command.add(HG_ANNOTATE_CMD);
command.add(HG_OPT_REPOSITORY);
command.add(repository.getAbsolutePath());
if (revision != null) {
command.add(HG_FLAG_REV_CMD);
command.add(revision);
}
command.add(HG_ANNOTATE_FLAGN_CMD);
command.add(HG_ANNOTATE_FLAGU_CMD);
command.add(HG_ANNOTATE_FLAGL_CMD);
command.add(HG_OPT_FOLLOW);
command.add(file.getAbsolutePath());
List list = exec(command);
if (!list.isEmpty()) {
if (isErrorNoRepository(list.get(0))) {
handleError(command, list, NbBundle.getMessage(HgCommand.class, "MSG_NO_REPOSITORY_ERR"), logger);
} else if (isErrorNoSuchFile(list.get(0))) {
// This can happen if we have multiple heads and the wrong
// one was picked by default hg annotation
if (revision == null) {
String rev = getLastRevision(repository, file);
if (rev != null) {
list = doAnnotate(repository, file, rev, logger);
} else {
list = null;
}
} else {
list = null;
}
}
}
return list;
}
public static List doAnnotate(File repository, File file, OutputLogger logger) throws HgException {
return doAnnotate(repository, file, null, logger);
}
/**
* Returns the current branch for a repository
*
* @param File repository of the mercurial repository's root directory
* @return current branch
* @throws org.netbeans.modules.mercurial.HgException
*/
public static String getBranch (File repository) throws HgException {
if (repository == null) return null;
List command = new ArrayList();
command.add(getHgCommand());
command.add(HG_BRANCH_CMD);
command.add(HG_OPT_REPOSITORY);
command.add(repository.getAbsolutePath());
List list = exec(command);
if (!list.isEmpty()){
return list.get(0);
}else{
return null;
}
}
/**
* Returns the revision number for the heads in a repository
*
* @param File repository of the mercurial repository's root directory
* @return List of revision numbers.
* @throws org.netbeans.modules.mercurial.HgException
*/
public static List getHeadRevisions(File repository) throws HgException {
return getHeadInfo(repository, true, HG_REV_TEMPLATE_CMD, false);
}
/**
* Returns the revision number for the heads in a repository
*
* @param String repository of the mercurial repository
* @return List of revision numbers.
* @throws org.netbeans.modules.mercurial.HgException
*/
public static List getHeadRevisions(String repository) throws HgException {
return getHeadInfo(repository, true, HG_REV_TEMPLATE_CMD, false);
}
/**
* Returns the info of heads in repository
*
* @param File repository of the mercurial repository's root directory
* @param onlyTopologicalHeads only topological heads, without any children
* @return head info.
* @throws org.netbeans.modules.mercurial.HgException
*/
public static HgLogMessage[] getHeadRevisionsInfo (File repository, boolean onlyTopologicalHeads, OutputLogger logger) throws HgException {
List list = getHeadInfo(repository, onlyTopologicalHeads, HG_LOG_BASIC_CHANGESET_NAME, true);
if (!list.isEmpty()) {
if (isErrorNoRepository(list.get(0))) {
handleError(null, list, NbBundle.getMessage(HgCommand.class, "MSG_NO_REPOSITORY_ERR"), logger); //NOI18N
} else if (isErrorAbort(list.get(0))) {
handleError(null, list, NbBundle.getMessage(HgCommand.class, "MSG_COMMAND_ABORTED"), logger); //NOI18N
}
}
List messages = processLogMessages(repository, null, list, false);
return messages.toArray(new HgLogMessage[0]);
}
public static HgBranch[] getBranches (File repository, OutputLogger logger) throws HgException {
List list = getHeadInfo(repository, false, HG_LOG_BASIC_CHANGESET_NAME, true);
if (!list.isEmpty()) {
if (isErrorNoRepository(list.get(0))) {
handleError(null, list, NbBundle.getMessage(HgCommand.class, "MSG_NO_REPOSITORY_ERR"), logger); //NOI18N
} else if (isErrorAbort(list.get(0))) {
handleError(null, list, NbBundle.getMessage(HgCommand.class, "MSG_COMMAND_ABORTED"), logger); //NOI18N
}
}
List heads = processLogMessages(repository, null, list, false);
list = getBranches(repository);
if (!list.isEmpty()) {
if (isErrorNoRepository(list.get(0))) {
handleError(null, list, NbBundle.getMessage(HgCommand.class, "MSG_NO_REPOSITORY_ERR"), logger); //NOI18N
} else if (isErrorAbort(list.get(0))) {
handleError(null, list, NbBundle.getMessage(HgCommand.class, "MSG_COMMAND_ABORTED"), logger); //NOI18N
}
}
return processBranches(list, heads);
}
public static void markBranch (File repository, String branchName, OutputLogger logger) throws HgException {
List command = new ArrayList();
command.add(getHgCommand());
command.add(HG_BRANCH_CMD);
command.add(HG_OPT_REPOSITORY);
command.add(repository.getAbsolutePath());
command.add(branchName);
List list = exec(command);
if (!list.isEmpty()) {
if (isErrorNoRepository(list.get(0))) {
handleError(command, list, NbBundle.getMessage(HgCommand.class, "MSG_NO_REPOSITORY_ERR"), logger); //NOI18N
} else if (isErrorAbort(list.get(0))) {
handleError(command, list, NbBundle.getMessage(HgCommand.class, "MSG_COMMAND_ABORTED"), logger); //NOI18N
}
}
WorkingCopyInfo.refreshAsync(repository);
}
public static HgTag[] getTags (File repository, OutputLogger logger) throws HgException {
List list = getTags(repository);
if (!list.isEmpty()) {
if (isErrorNoRepository(list.get(0))) {
handleError(null, list, NbBundle.getMessage(HgCommand.class, "MSG_NO_REPOSITORY_ERR"), logger); //NOI18N
} else if (isErrorAbort(list.get(0))) {
handleError(null, list, NbBundle.getMessage(HgCommand.class, "MSG_COMMAND_ABORTED"), logger); //NOI18N
}
}
return processTags(list, repository, logger);
}
public static void createTag (File repository, String tagName, String message, String revision, boolean isLocal, OutputLogger logger) throws HgException {
List command = new ArrayList();
command.add(getHgCommand());
command.add(HG_TAG_CMD);
command.add(HG_OPT_REPOSITORY);
command.add(repository.getAbsolutePath());
if (isLocal) {
command.add(HG_TAG_OPT_LOCAL);
} else if (message != null && !message.isEmpty()) {
command.add(HG_TAG_OPT_MESSAGE);
command.add(message);
}
if (revision != null && !revision.isEmpty()) {
command.add(HG_TAG_OPT_REVISION);
command.add(revision);
}
command.add(tagName);
List list = exec(command);
if (!list.isEmpty()) {
if (isErrorNoRepository(list.get(0))) {
handleError(command, list, NbBundle.getMessage(HgCommand.class, "MSG_NO_REPOSITORY_ERR"), logger); //NOI18N
} else if (isErrorAbort(list.get(0))) {
handleError(command, list, NbBundle.getMessage(HgCommand.class, "MSG_COMMAND_ABORTED"), logger); //NOI18N
}
}
}
public static void removeTag (File repository, String tagName, boolean isLocal, String message, OutputLogger logger) throws HgException {
List command = new ArrayList();
command.add(getHgCommand());
command.add(HG_TAG_CMD);
command.add(HG_OPT_REPOSITORY);
command.add(repository.getAbsolutePath());
if (isLocal) {
command.add(HG_TAG_OPT_LOCAL);
} else if (message != null && !message.isEmpty()) {
command.add(HG_TAG_OPT_MESSAGE);
command.add(message);
}
command.add(HG_TAG_OPT_REMOVE);
command.add(tagName);
List