tikhomirov@10: /* tikhomirov@59: * Copyright (c) 2010, 2011 Artem Tikhomirov tikhomirov@10: */ tikhomirov@10: package com.tmate.hgkit.ll; tikhomirov@10: tikhomirov@10: import java.io.File; tikhomirov@10: import java.io.IOException; tikhomirov@10: import java.util.Collections; tikhomirov@18: import java.util.LinkedHashMap; tikhomirov@18: import java.util.Map; tikhomirov@18: import java.util.TreeSet; tikhomirov@10: tikhomirov@10: import com.tmate.hgkit.fs.DataAccess; tikhomirov@10: import com.tmate.hgkit.fs.DataAccessProvider; tikhomirov@10: tikhomirov@10: /** tikhomirov@10: * @see http://mercurial.selenic.com/wiki/DirState tikhomirov@10: * @see http://mercurial.selenic.com/wiki/FileFormats#dirstate tikhomirov@10: * @author artem tikhomirov@10: */ tikhomirov@10: public class HgDirstate { tikhomirov@10: tikhomirov@59: private final DataAccessProvider accessProvider; tikhomirov@10: private final File dirstateFile; tikhomirov@18: private Map normal; tikhomirov@18: private Map added; tikhomirov@18: private Map removed; tikhomirov@18: private Map merged; tikhomirov@10: tikhomirov@59: /*package-local*/ HgDirstate() { tikhomirov@59: // empty instance tikhomirov@59: accessProvider = null; tikhomirov@59: dirstateFile = null; tikhomirov@59: } tikhomirov@59: tikhomirov@59: public HgDirstate(DataAccessProvider dap, File dirstate) { tikhomirov@59: accessProvider = dap; tikhomirov@59: dirstateFile = dirstate; tikhomirov@10: } tikhomirov@10: tikhomirov@10: private void read() { tikhomirov@18: normal = added = removed = merged = Collections.emptyMap(); tikhomirov@59: if (dirstateFile == null || !dirstateFile.exists()) { tikhomirov@10: return; tikhomirov@10: } tikhomirov@59: DataAccess da = accessProvider.create(dirstateFile); tikhomirov@10: if (da.isEmpty()) { tikhomirov@10: return; tikhomirov@10: } tikhomirov@18: // not sure linked is really needed here, just for ease of debug tikhomirov@18: normal = new LinkedHashMap(); tikhomirov@18: added = new LinkedHashMap(); tikhomirov@18: removed = new LinkedHashMap(); tikhomirov@18: merged = new LinkedHashMap(); tikhomirov@10: try { tikhomirov@10: // XXX skip(40) if we don't need these? tikhomirov@10: byte[] parents = new byte[40]; tikhomirov@10: da.readBytes(parents, 0, 40); tikhomirov@10: parents = null; tikhomirov@10: do { tikhomirov@10: final byte state = da.readByte(); tikhomirov@10: final int fmode = da.readInt(); tikhomirov@10: final int size = da.readInt(); tikhomirov@10: final int time = da.readInt(); tikhomirov@10: final int nameLen = da.readInt(); tikhomirov@10: String fn1 = null, fn2 = null; tikhomirov@10: byte[] name = new byte[nameLen]; tikhomirov@10: da.readBytes(name, 0, nameLen); tikhomirov@10: for (int i = 0; i < nameLen; i++) { tikhomirov@10: if (name[i] == 0) { tikhomirov@11: fn1 = new String(name, 0, i, "UTF-8"); // XXX unclear from documentation what encoding is used there tikhomirov@11: fn2 = new String(name, i+1, nameLen - i - 1, "UTF-8"); // need to check with different system codepages tikhomirov@10: break; tikhomirov@10: } tikhomirov@10: } tikhomirov@10: if (fn1 == null) { tikhomirov@10: fn1 = new String(name); tikhomirov@10: } tikhomirov@10: Record r = new Record(fmode, size, time, fn1, fn2); tikhomirov@10: if (state == 'n') { tikhomirov@18: normal.put(r.name1, r); tikhomirov@10: } else if (state == 'a') { tikhomirov@18: added.put(r.name1, r); tikhomirov@10: } else if (state == 'r') { tikhomirov@18: removed.put(r.name1, r); tikhomirov@10: } else if (state == 'm') { tikhomirov@18: merged.put(r.name1, r); tikhomirov@10: } else { tikhomirov@10: // FIXME log error? tikhomirov@10: } tikhomirov@10: } while (!da.isEmpty()); tikhomirov@10: } catch (IOException ex) { tikhomirov@10: ex.printStackTrace(); // FIXME log error, clean dirstate? tikhomirov@10: } finally { tikhomirov@10: da.done(); tikhomirov@10: } tikhomirov@10: } tikhomirov@10: tikhomirov@18: // new, modifiable collection tikhomirov@18: /*package-local*/ TreeSet all() { tikhomirov@18: read(); tikhomirov@18: TreeSet rv = new TreeSet(); tikhomirov@18: @SuppressWarnings("unchecked") tikhomirov@18: Map[] all = new Map[] { normal, added, removed, merged }; tikhomirov@18: for (int i = 0; i < all.length; i++) { tikhomirov@18: for (Record r : all[i].values()) { tikhomirov@18: rv.add(r.name1); tikhomirov@18: } tikhomirov@18: } tikhomirov@18: return rv; tikhomirov@18: } tikhomirov@18: tikhomirov@18: /*package-local*/ Record checkNormal(String fname) { tikhomirov@18: return normal.get(fname); tikhomirov@18: } tikhomirov@18: tikhomirov@18: /*package-local*/ Record checkAdded(String fname) { tikhomirov@18: return added.get(fname); tikhomirov@18: } tikhomirov@18: /*package-local*/ Record checkRemoved(String fname) { tikhomirov@18: return removed.get(fname); tikhomirov@18: } tikhomirov@18: /*package-local*/ Record checkMerged(String fname) { tikhomirov@18: return merged.get(fname); tikhomirov@18: } tikhomirov@18: tikhomirov@18: tikhomirov@18: tikhomirov@18: tikhomirov@10: public void dump() { tikhomirov@10: read(); tikhomirov@10: @SuppressWarnings("unchecked") tikhomirov@18: Map[] all = new Map[] { normal, added, removed, merged }; tikhomirov@10: char[] x = new char[] {'n', 'a', 'r', 'm' }; tikhomirov@10: for (int i = 0; i < all.length; i++) { tikhomirov@18: for (Record r : all[i].values()) { tikhomirov@14: System.out.printf("%c %3o%6d %30tc\t\t%s", x[i], r.mode, r.size, (long) r.time * 1000, r.name1); tikhomirov@10: if (r.name2 != null) { tikhomirov@10: System.out.printf(" --> %s", r.name2); tikhomirov@10: } tikhomirov@10: System.out.println(); tikhomirov@10: } tikhomirov@10: System.out.println(); tikhomirov@10: } tikhomirov@10: } tikhomirov@10: tikhomirov@18: /*package-local*/ static class Record { tikhomirov@10: final int mode; tikhomirov@10: final int size; tikhomirov@10: final int time; tikhomirov@10: final String name1; tikhomirov@10: final String name2; tikhomirov@10: tikhomirov@10: public Record(int fmode, int fsize, int ftime, String name1, String name2) { tikhomirov@10: mode = fmode; tikhomirov@10: size = fsize; tikhomirov@10: time = ftime; tikhomirov@10: this.name1 = name1; tikhomirov@10: this.name2 = name2; tikhomirov@10: tikhomirov@10: } tikhomirov@10: } tikhomirov@10: }