Mercurial > hg4j
diff src/org/tmatesoft/hg/repo/HgChangelog.java @ 673:545b1d4cc11d
Refactor HgBundle.GroupElement (clear experimental mark), resolve few technical debt issues
author | Artem Tikhomirov <tikhomirov.artem@gmail.com> |
---|---|
date | Fri, 12 Jul 2013 20:14:24 +0200 |
parents | fba85bc1dfb8 |
children |
line wrap: on
line diff
--- a/src/org/tmatesoft/hg/repo/HgChangelog.java Fri Jul 12 16:29:06 2013 +0200 +++ b/src/org/tmatesoft/hg/repo/HgChangelog.java Fri Jul 12 20:14:24 2013 +0200 @@ -20,10 +20,8 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Calendar; -import java.util.Collections; import java.util.Date; import java.util.Formatter; -import java.util.HashMap; import java.util.List; import java.util.Locale; import java.util.Map; @@ -32,12 +30,10 @@ import org.tmatesoft.hg.core.Nodeid; import org.tmatesoft.hg.core.SessionContext; import org.tmatesoft.hg.internal.Callback; +import org.tmatesoft.hg.internal.ChangesetParser; import org.tmatesoft.hg.internal.DataAccess; -import org.tmatesoft.hg.internal.EncodingHelper; -import org.tmatesoft.hg.internal.Internals; import org.tmatesoft.hg.internal.Lifecycle; import org.tmatesoft.hg.internal.LifecycleBridge; -import org.tmatesoft.hg.internal.Pool; import org.tmatesoft.hg.internal.RevlogStream; import org.tmatesoft.hg.util.Adaptable; import org.tmatesoft.hg.util.CancelSupport; @@ -150,14 +146,14 @@ */ public static final class RawChangeset implements Cloneable /* for those that would like to keep a copy */{ // would be nice to get it immutable, but then we can't reuse instances - private/* final */Nodeid manifest; - private String user; - private String comment; - private String[] files; // shall not be modified (#clone() does shallow copy) - private Date time; - private int timezone; + /* final */Nodeid manifest; + String user; + String comment; + String[] files; // shall not be modified (#clone() does shallow copy) + Date time; + int timezone; // http://mercurial.selenic.com/wiki/PruningDeadBranches - Closing changesets can be identified by close=1 in the changeset's extra field. - private Map<String, String> extras; + Map<String, String> extras; private RawChangeset() { } @@ -241,170 +237,33 @@ } } - /** - * @see mercurial/changelog.py:read() - * - * <pre> - * format used: - * nodeid\n : manifest node in ascii - * user\n : user, no \n or \r allowed - * time tz extra\n : date (time is int or float, timezone is int) - * : extra is metadatas, encoded and separated by '\0' - * : older versions ignore it - * files\n\n : files modified by the cset, no \n or \r allowed - * (.*) : comment (free text, ideally utf-8) - * - * changelog v0 doesn't use extra - * </pre> - */ - /*package-local*/static final class ChangesetParser { - private final EncodingHelper encHelper; - // it's likely user names get repeated again and again throughout repository. - private final Pool<String> usersPool; - private final Pool<String> filesPool; - private final boolean reuseChangesetInstance; - private RawChangeset target; - - public ChangesetParser(SessionContext.Source sessionContex, boolean shallReuseCsetInstance) { - encHelper = Internals.buildFileNameEncodingHelper(sessionContex); - usersPool = new Pool<String>(); - filesPool = new Pool<String>(); - reuseChangesetInstance = shallReuseCsetInstance; + /*package-local*/static final class RawCsetFactory implements ChangesetParser.CsetFactory { + private RawChangeset cset; + + public RawCsetFactory(boolean shallReuseCsetInstance) { if (shallReuseCsetInstance) { - target = new RawChangeset(); + cset = new RawChangeset(); } } - - public void dispose() { - usersPool.clear(); - filesPool.clear(); - } - - public RawChangeset parse(DataAccess da) throws IOException, HgInvalidDataFormatException { - byte[] data = da.byteArray(); - if (!reuseChangesetInstance) { - target = new RawChangeset(); - } - init(data, 0, data.length); - return target; - } - private void init(byte[] data, int offset, int length) throws HgInvalidDataFormatException { - final int bufferEndIndex = offset + length; - final byte lineBreak = (byte) '\n'; - int breakIndex1 = indexOf(data, lineBreak, offset, bufferEndIndex); - if (breakIndex1 == -1) { - throw new HgInvalidDataFormatException("Bad Changeset data"); - } - Nodeid _nodeid = Nodeid.fromAscii(data, 0, breakIndex1); - int breakIndex2 = indexOf(data, lineBreak, breakIndex1 + 1, bufferEndIndex); - if (breakIndex2 == -1) { - throw new HgInvalidDataFormatException("Bad Changeset data"); - } - String _user; - _user = encHelper.userFromChangeset(data, breakIndex1 + 1, breakIndex2 - breakIndex1 - 1); - _user = usersPool.unify(_user); - - int breakIndex3 = indexOf(data, lineBreak, breakIndex2 + 1, bufferEndIndex); - if (breakIndex3 == -1) { - throw new HgInvalidDataFormatException("Bad Changeset data"); - } - String _timeString = new String(data, breakIndex2 + 1, breakIndex3 - breakIndex2 - 1); - int space1 = _timeString.indexOf(' '); - if (space1 == -1) { - throw new HgInvalidDataFormatException(String.format("Bad Changeset data: %s in [%d..%d]", "time string", breakIndex2+1, breakIndex3)); - } - int space2 = _timeString.indexOf(' ', space1 + 1); - if (space2 == -1) { - space2 = _timeString.length(); + public RawChangeset create(Nodeid nodeidManifest, String user, Date time, int timezone, List<String> files, String comment, Map<String, String> extrasMap) { + RawChangeset target; + if (cset != null) { + target = cset; + } else { + target = new RawChangeset(); } - long unixTime = Long.parseLong(_timeString.substring(0, space1)); - int _timezone = Integer.parseInt(_timeString.substring(space1 + 1, space2)); - // unixTime is local time, and timezone records difference of the local time to UTC. - Date _time = new Date(unixTime * 1000); - String _extras = space2 < _timeString.length() ? _timeString.substring(space2 + 1) : null; - Map<String, String> _extrasMap = parseExtras(_extras); - // - int lastStart = breakIndex3 + 1; - int breakIndex4 = indexOf(data, lineBreak, lastStart, bufferEndIndex); - ArrayList<String> _files = null; - if (breakIndex4 > lastStart) { - // if breakIndex4 == lastStart, we already found \n\n and hence there are no files (e.g. merge revision) - _files = new ArrayList<String>(5); - while (breakIndex4 != -1 && breakIndex4 + 1 < bufferEndIndex) { - String fname = encHelper.fileFromChangeset(data, lastStart, breakIndex4 - lastStart); - _files.add(filesPool.unify(fname)); - lastStart = breakIndex4 + 1; - if (data[breakIndex4 + 1] == lineBreak) { - // found \n\n - break; - } else { - breakIndex4 = indexOf(data, lineBreak, lastStart, bufferEndIndex); - } - } - if (breakIndex4 == -1 || breakIndex4 >= bufferEndIndex) { - throw new HgInvalidDataFormatException("Bad Changeset data"); - } - } else { - breakIndex4--; - } - String _comment = encHelper.commentFromChangeset(data, breakIndex4 + 2, bufferEndIndex - breakIndex4 - 2); - // change this instance at once, don't leave it partially changes in case of error - target.manifest = _nodeid; - target.user = _user; - target.time = _time; - target.timezone = _timezone; - target.files = _files == null ? new String[0] : _files.toArray(new String[_files.size()]); - target.comment = _comment; - target.extras = _extrasMap; - } - - private Map<String, String> parseExtras(String _extras) { - final String extras_branch_key = "branch"; - _extras = _extras == null ? null : _extras.trim(); - if (_extras == null || _extras.length() == 0) { - return Collections.singletonMap(extras_branch_key, HgRepository.DEFAULT_BRANCH_NAME); - } - Map<String, String> _extrasMap = new HashMap<String, String>(); - int lastIndex = 0; - do { - String pair; - int sp = _extras.indexOf('\0', lastIndex); - if (sp == -1) { - sp = _extras.length(); - } - if (sp > lastIndex) { - pair = _extras.substring(lastIndex, sp); - pair = decode(pair); - int eq = pair.indexOf(':'); - _extrasMap.put(pair.substring(0, eq), pair.substring(eq + 1)); - lastIndex = sp + 1; - } - } while (lastIndex < _extras.length()); - if (!_extrasMap.containsKey(extras_branch_key)) { - _extrasMap.put(extras_branch_key, HgRepository.DEFAULT_BRANCH_NAME); - } - return Collections.unmodifiableMap(_extrasMap); - } - - private static int indexOf(byte[] src, byte what, int startOffset, int endIndex) { - for (int i = startOffset; i < endIndex; i++) { - if (src[i] == what) { - return i; - } - } - return -1; - } - - private static String decode(String s) { - if (s != null && s.indexOf('\\') != -1) { - // TestAuxUtilities#testChangelogExtrasDecode - return s.replace("\\\\", "\\").replace("\\n", "\n").replace("\\r", "\r").replace("\\0", "\00"); - } - return s; + target.manifest = nodeidManifest; + target.user = user; + target.time = time; + target.timezone = timezone; + target.files = files == null ? new String[0] : files.toArray(new String[files.size()]); + target.comment = comment; + target.extras = extrasMap; + return target; } } - + private static class RawCsetCollector implements Inspector { final ArrayList<RawChangeset> result; @@ -430,7 +289,7 @@ public RawCsetParser(SessionContext.Source sessionContext, HgChangelog.Inspector delegate) { assert delegate != null; inspector = delegate; - csetBuilder = new ChangesetParser(sessionContext, true); + csetBuilder = new ChangesetParser(sessionContext, new RawCsetFactory(true)); inspectorLifecycle = Adaptable.Factory.getAdapter(delegate, Lifecycle.class, null); if (inspectorLifecycle == null) { ProgressSupport ph = Adaptable.Factory.getAdapter(delegate, ProgressSupport.class, null);