| /* |
| * Copyright 2000-2014 JetBrains s.r.o. |
| * |
| * Licensed 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.zmlx.hg4idea.log; |
| |
| |
| import com.intellij.openapi.diagnostic.Logger; |
| import com.intellij.openapi.util.Couple; |
| import com.intellij.openapi.util.text.StringUtil; |
| import com.intellij.util.ArrayUtil; |
| import com.intellij.util.Function; |
| import com.intellij.util.SmartList; |
| import org.jetbrains.annotations.NotNull; |
| import org.jetbrains.annotations.Nullable; |
| import org.zmlx.hg4idea.HgRevisionNumber; |
| import org.zmlx.hg4idea.util.HgChangesetUtil; |
| import org.zmlx.hg4idea.util.HgUtil; |
| import org.zmlx.hg4idea.util.HgVersion; |
| |
| import java.text.ParseException; |
| import java.text.SimpleDateFormat; |
| import java.util.ArrayList; |
| import java.util.Arrays; |
| import java.util.Date; |
| import java.util.List; |
| |
| /** |
| * Parse one log command line and create appropriate type of commit info or revision info. |
| * see {@link HgHistoryUtil} |
| * |
| * @param <CommitT> |
| */ |
| public abstract class HgBaseLogParser<CommitT> implements Function<String, CommitT> { |
| private static final Logger LOG = Logger.getInstance(HgBaseLogParser.class); |
| |
| private static final int REVISION_INDEX = 0; |
| private static final int CHANGESET_INDEX = 1; |
| private static final int PARENTS_INDEX = 2; |
| private static final int DATE_INDEX = 3; |
| private static final int AUTHOR_INDEX = 4; |
| |
| protected static final int MESSAGE_INDEX = 5; |
| protected static final int BRANCH_INDEX = 6; |
| |
| protected static final int FILES_ADDED_INDEX = 7; |
| protected static final int FILES_MODIFIED_INDEX = 8; |
| protected static final int FILES_DELETED_INDEX = 9; |
| protected static final int FILES_COPIED_INDEX = 10; |
| |
| private static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss Z"); |
| |
| |
| @Nullable |
| public CommitT convert(@NotNull String line) { |
| |
| // we need to get all attributes, include empty trailing strings, so use non-positive limit as second argument |
| List<String> attributes = StringUtil.split(line, HgChangesetUtil.ITEM_SEPARATOR, true, false); |
| int numAttributes = attributes.size(); |
| if (numAttributes <= AUTHOR_INDEX) { |
| LOG.info("Hg Log Command was cancelled or failed"); |
| return null; |
| } |
| try { |
| String revisionString = attributes.get(REVISION_INDEX); |
| String changeset = attributes.get(CHANGESET_INDEX); |
| String parentsString = attributes.get(PARENTS_INDEX); |
| |
| SmartList<HgRevisionNumber> parents = parseParentRevisions(parentsString, revisionString); |
| |
| Date revisionDate = DATE_FORMAT.parse(attributes.get(DATE_INDEX)); |
| Couple<String> authorAndEmail = HgUtil.parseUserNameAndEmail(attributes.get(AUTHOR_INDEX)); |
| return convertDetails(revisionString, changeset, parents, revisionDate, authorAndEmail.first, authorAndEmail.second, attributes); |
| } |
| catch (ParseException e) { |
| LOG.warn("Error parsing date in line " + line); |
| return null; |
| } |
| catch (NumberFormatException e) { |
| LOG.warn("Error parsing rev in line " + line); |
| return null; |
| } |
| } |
| |
| @Override |
| public CommitT fun(String s) { |
| return convert(s); |
| } |
| |
| @Nullable |
| protected abstract CommitT convertDetails(@NotNull String rev, |
| @NotNull String changeset, |
| @NotNull SmartList<HgRevisionNumber> parents, |
| @NotNull Date revisionDate, |
| @NotNull String author, |
| @NotNull String email, |
| @NotNull List<String> attributes); |
| |
| @NotNull |
| public static List<String> constructDefaultTemplate(HgVersion currentVersion) { |
| List<String> templates = new ArrayList<String>(); |
| templates.add("{rev}"); |
| templates.add("{node}"); |
| if (currentVersion.isParentRevisionTemplateSupported()) { |
| templates.add("{p1rev}:{p1node} {p2rev}:{p2node}"); |
| } |
| else { |
| templates.add("{parents}"); |
| } |
| templates.addAll(Arrays.asList("{date|isodatesec}", "{author}")); |
| return templates; |
| } |
| |
| @NotNull |
| public static String[] constructFullTemplateArgument(boolean includeFiles, @NotNull HgVersion currentVersion) { |
| List<String> templates = new ArrayList<String>(); |
| templates.add("{rev}"); |
| templates.add("{node}"); |
| if (currentVersion.isParentRevisionTemplateSupported()) { |
| templates.add("{p1rev}:{p1node} {p2rev}:{p2node}"); |
| } |
| else { |
| templates.add("{parents}"); |
| } |
| templates.addAll(Arrays.asList("{date|isodatesec}", "{author}", "{desc}", "{branch}")); |
| if (!includeFiles) { |
| return ArrayUtil.toStringArray(templates); |
| } |
| templates.addAll(Arrays.asList("{file_adds}", "{file_mods}", "{file_dels}")); |
| templates |
| .add(currentVersion.isBuiltInFunctionSupported() ? "{join(file_copies,'" + HgChangesetUtil.FILE_SEPARATOR + "')}" : "{file_copies}"); |
| return ArrayUtil.toStringArray(templates); |
| } |
| |
| @NotNull |
| protected static SmartList<HgRevisionNumber> parseParentRevisions(@NotNull String parentsString, @NotNull String currentRevisionString) { |
| SmartList<HgRevisionNumber> parents = new SmartList<HgRevisionNumber>(); |
| if (StringUtil.isEmptyOrSpaces(parentsString)) { |
| // parents shouldn't be empty only if not supported |
| Long revision = Long.valueOf(currentRevisionString); |
| HgRevisionNumber parentRevision = HgRevisionNumber.getLocalInstance(String.valueOf(revision - 1)); |
| parents.add(parentRevision); |
| return parents; |
| } |
| //hg returns parents in the format 'rev:node rev:node ' (note the trailing space) |
| List<String> parentStrings = StringUtil.split(parentsString.trim(), " "); |
| for (String parentString : parentStrings) { |
| List<String> parentParts = StringUtil.split(parentString, ":"); |
| //if revision has only 1 parent and "--debug" argument were added or if appropriate parent template were used, |
| // its second parent has revision number -1 |
| if (Integer.valueOf(parentParts.get(0)) >= 0) { |
| parents.add(HgRevisionNumber.getInstance(parentParts.get(0), parentParts.get(1))); |
| } |
| } |
| return parents; |
| } |
| |
| @NotNull |
| protected static String parseAdditionalStringAttribute(final List<String> attributes, int index) { |
| int numAttributes = attributes.size(); |
| if (numAttributes > index) { |
| return attributes.get(index); |
| } |
| LOG.warn("Couldn't parse hg log commit info attribute " + index); |
| return ""; |
| } |
| } |
| |