Mercurial > hg4j
diff src/org/tmatesoft/hg/repo/HgDirstate.java @ 74:6f1b88693d48
Complete refactoring to org.tmatesoft
author | Artem Tikhomirov <tikhomirov.artem@gmail.com> |
---|---|
date | Mon, 24 Jan 2011 03:14:45 +0100 |
parents | src/com/tmate/hgkit/ll/HgDirstate.java@b771e94a4f7c |
children | d55d4eedfc57 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/org/tmatesoft/hg/repo/HgDirstate.java Mon Jan 24 03:14:45 2011 +0100 @@ -0,0 +1,179 @@ +/* + * Copyright (c) 2010-2011 TMate Software Ltd + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * For information on how to redistribute this software under + * the terms of a license other than GNU General Public License + * contact TMate Software at support@svnkit.com + */ +package org.tmatesoft.hg.repo; + +import java.io.File; +import java.io.IOException; +import java.util.Collections; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.TreeSet; + +import org.tmatesoft.hg.internal.DataAccess; +import org.tmatesoft.hg.internal.DataAccessProvider; + + +/** + * @see http://mercurial.selenic.com/wiki/DirState + * @see http://mercurial.selenic.com/wiki/FileFormats#dirstate + * + * @author Artem Tikhomirov + * @author TMate Software Ltd. + */ +public class HgDirstate { + + private final DataAccessProvider accessProvider; + private final File dirstateFile; + private Map<String, Record> normal; + private Map<String, Record> added; + private Map<String, Record> removed; + private Map<String, Record> merged; + + /*package-local*/ HgDirstate() { + // empty instance + accessProvider = null; + dirstateFile = null; + } + + public HgDirstate(DataAccessProvider dap, File dirstate) { + accessProvider = dap; + dirstateFile = dirstate; + } + + private void read() { + normal = added = removed = merged = Collections.<String, Record>emptyMap(); + if (dirstateFile == null || !dirstateFile.exists()) { + return; + } + DataAccess da = accessProvider.create(dirstateFile); + if (da.isEmpty()) { + return; + } + // not sure linked is really needed here, just for ease of debug + normal = new LinkedHashMap<String, Record>(); + added = new LinkedHashMap<String, Record>(); + removed = new LinkedHashMap<String, Record>(); + merged = new LinkedHashMap<String, Record>(); + try { + // XXX skip(40) if we don't need these? + byte[] parents = new byte[40]; + da.readBytes(parents, 0, 40); + parents = null; + do { + final byte state = da.readByte(); + final int fmode = da.readInt(); + final int size = da.readInt(); + final int time = da.readInt(); + final int nameLen = da.readInt(); + String fn1 = null, fn2 = null; + byte[] name = new byte[nameLen]; + da.readBytes(name, 0, nameLen); + for (int i = 0; i < nameLen; i++) { + if (name[i] == 0) { + fn1 = new String(name, 0, i, "UTF-8"); // XXX unclear from documentation what encoding is used there + fn2 = new String(name, i+1, nameLen - i - 1, "UTF-8"); // need to check with different system codepages + break; + } + } + if (fn1 == null) { + fn1 = new String(name); + } + Record r = new Record(fmode, size, time, fn1, fn2); + if (state == 'n') { + normal.put(r.name1, r); + } else if (state == 'a') { + added.put(r.name1, r); + } else if (state == 'r') { + removed.put(r.name1, r); + } else if (state == 'm') { + merged.put(r.name1, r); + } else { + // FIXME log error? + } + } while (!da.isEmpty()); + } catch (IOException ex) { + ex.printStackTrace(); // FIXME log error, clean dirstate? + } finally { + da.done(); + } + } + + // new, modifiable collection + /*package-local*/ TreeSet<String> all() { + read(); + TreeSet<String> rv = new TreeSet<String>(); + @SuppressWarnings("unchecked") + Map<String, Record>[] all = new Map[] { normal, added, removed, merged }; + for (int i = 0; i < all.length; i++) { + for (Record r : all[i].values()) { + rv.add(r.name1); + } + } + return rv; + } + + /*package-local*/ Record checkNormal(String fname) { + return normal.get(fname); + } + + /*package-local*/ Record checkAdded(String fname) { + return added.get(fname); + } + /*package-local*/ Record checkRemoved(String fname) { + return removed.get(fname); + } + /*package-local*/ Record checkMerged(String fname) { + return merged.get(fname); + } + + + + + public void dump() { + read(); + @SuppressWarnings("unchecked") + Map<String, Record>[] all = new Map[] { normal, added, removed, merged }; + char[] x = new char[] {'n', 'a', 'r', 'm' }; + for (int i = 0; i < all.length; i++) { + for (Record r : all[i].values()) { + System.out.printf("%c %3o%6d %30tc\t\t%s", x[i], r.mode, r.size, (long) r.time * 1000, r.name1); + if (r.name2 != null) { + System.out.printf(" --> %s", r.name2); + } + System.out.println(); + } + System.out.println(); + } + } + + /*package-local*/ static class Record { + final int mode; + final int size; + final int time; + final String name1; + final String name2; + + public Record(int fmode, int fsize, int ftime, String name1, String name2) { + mode = fmode; + size = fsize; + time = ftime; + this.name1 = name1; + this.name2 = name2; + + } + } +}