tikhomirov@50: /* tikhomirov@74: * Copyright (c) 2011 TMate Software Ltd tikhomirov@74: * tikhomirov@74: * This program is free software; you can redistribute it and/or modify tikhomirov@74: * it under the terms of the GNU General Public License as published by tikhomirov@74: * the Free Software Foundation; version 2 of the License. tikhomirov@74: * tikhomirov@74: * This program is distributed in the hope that it will be useful, tikhomirov@74: * but WITHOUT ANY WARRANTY; without even the implied warranty of tikhomirov@74: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the tikhomirov@74: * GNU General Public License for more details. tikhomirov@74: * tikhomirov@74: * For information on how to redistribute this software under tikhomirov@74: * the terms of a license other than GNU General Public License tikhomirov@102: * contact TMate Software at support@hg4j.com tikhomirov@50: */ tikhomirov@74: package org.tmatesoft.hg.repo; tikhomirov@50: tikhomirov@104: import java.io.BufferedReader; tikhomirov@104: import java.io.File; tikhomirov@104: import java.io.FileReader; tikhomirov@104: import java.io.IOException; tikhomirov@104: import java.util.ArrayList; tikhomirov@104: import java.util.HashMap; tikhomirov@104: import java.util.LinkedList; tikhomirov@50: import java.util.List; tikhomirov@104: import java.util.Map; tikhomirov@104: import java.util.TreeMap; tikhomirov@50: tikhomirov@74: import org.tmatesoft.hg.core.Nodeid; tikhomirov@74: tikhomirov@50: /** tikhomirov@104: * @see http://mercurial.selenic.com/wiki/TagDesign tikhomirov@74: * tikhomirov@74: * @author Artem Tikhomirov tikhomirov@74: * @author TMate Software Ltd. tikhomirov@50: */ tikhomirov@50: public class HgTags { tikhomirov@104: // global tags come from ".hgtags" tikhomirov@104: // local come from ".hg/localtags" tikhomirov@104: tikhomirov@104: private final Map> globalToName; tikhomirov@104: private final Map> localToName; tikhomirov@104: private final Map> globalFromName; tikhomirov@104: private final Map> localFromName; tikhomirov@104: tikhomirov@104: tikhomirov@104: /*package-local*/ HgTags() { tikhomirov@104: globalToName = new HashMap>(); tikhomirov@104: localToName = new HashMap>(); tikhomirov@104: globalFromName = new TreeMap>(); tikhomirov@104: localFromName = new TreeMap>(); tikhomirov@104: } tikhomirov@104: tikhomirov@104: /*package-local*/ void readLocal(File localTags) throws IOException { tikhomirov@104: if (localTags == null || localTags.isDirectory()) { tikhomirov@104: throw new IllegalArgumentException(String.valueOf(localTags)); tikhomirov@104: } tikhomirov@104: read(localTags, localToName, localFromName); tikhomirov@104: } tikhomirov@104: tikhomirov@104: /*package-local*/ void readGlobal(File globalTags) throws IOException { tikhomirov@104: if (globalTags == null || globalTags.isDirectory()) { tikhomirov@104: throw new IllegalArgumentException(String.valueOf(globalTags)); tikhomirov@104: } tikhomirov@104: read(globalTags, globalToName, globalFromName); tikhomirov@104: } tikhomirov@104: tikhomirov@104: private void read(File f, Map> nid2name, Map> name2nid) throws IOException { tikhomirov@104: if (!f.canRead()) { tikhomirov@104: return; tikhomirov@104: } tikhomirov@104: BufferedReader r = null; tikhomirov@104: try { tikhomirov@104: r = new BufferedReader(new FileReader(f)); tikhomirov@104: read(r, nid2name, name2nid); tikhomirov@104: } finally { tikhomirov@104: if (r != null) { tikhomirov@104: r.close(); tikhomirov@104: } tikhomirov@104: } tikhomirov@104: } tikhomirov@104: tikhomirov@104: private void read(BufferedReader reader, Map> nid2name, Map> name2nid) throws IOException { tikhomirov@104: String line; tikhomirov@104: while ((line = reader.readLine()) != null) { tikhomirov@104: line = line.trim(); tikhomirov@104: if (line.length() == 0) { tikhomirov@104: continue; tikhomirov@104: } tikhomirov@104: if (line.length() < 40+2 /*nodeid, space and at least single-char tagname*/) { tikhomirov@104: System.out.println("Bad tags line:" + line); // FIXME log or otherwise report (IStatus analog?) tikhomirov@104: continue; tikhomirov@104: } tikhomirov@104: int spacePos = line.indexOf(' '); tikhomirov@104: if (spacePos != -1) { tikhomirov@104: assert spacePos == 40; tikhomirov@104: final byte[] nodeidBytes = line.substring(0, spacePos).getBytes(); tikhomirov@104: Nodeid nid = Nodeid.fromAscii(nodeidBytes, 0, nodeidBytes.length); tikhomirov@104: String tagName = line.substring(spacePos+1); tikhomirov@104: List nids = name2nid.get(tagName); tikhomirov@104: if (nids == null) { tikhomirov@104: nids = new LinkedList(); tikhomirov@104: // tagName is substring of full line, thus need a copy to let the line be GC'ed tikhomirov@104: // new String(tagName.toCharArray()) is more expressive, but results in 1 extra arraycopy tikhomirov@104: tagName = new String(tagName); tikhomirov@104: name2nid.put(tagName, nids); tikhomirov@104: } tikhomirov@104: // XXX repo.getNodeidCache().nodeid(nid); tikhomirov@104: ((LinkedList) nids).addFirst(nid); tikhomirov@104: List revTags = nid2name.get(nid); tikhomirov@104: if (revTags == null) { tikhomirov@104: revTags = new LinkedList(); tikhomirov@104: nid2name.put(nid, revTags); tikhomirov@104: } tikhomirov@104: revTags.add(tagName); tikhomirov@104: } else { tikhomirov@104: System.out.println("Bad tags line:" + line); // FIXME see above tikhomirov@104: } tikhomirov@104: } tikhomirov@104: } tikhomirov@50: tikhomirov@50: public List tags(Nodeid nid) { tikhomirov@104: ArrayList rv = new ArrayList(5); tikhomirov@104: List l; tikhomirov@104: if ((l = localToName.get(nid)) != null) { tikhomirov@104: rv.addAll(l); tikhomirov@104: } tikhomirov@104: if ((l = globalToName.get(nid)) != null) { tikhomirov@104: rv.addAll(l); tikhomirov@104: } tikhomirov@104: return rv; tikhomirov@50: } tikhomirov@50: tikhomirov@50: public boolean isTagged(Nodeid nid) { tikhomirov@104: return localToName.containsKey(nid) || globalToName.containsKey(nid); tikhomirov@104: } tikhomirov@104: tikhomirov@104: public List tagged(String tagName) { tikhomirov@104: ArrayList rv = new ArrayList(5); tikhomirov@104: List l; tikhomirov@104: if ((l = localFromName.get(tagName)) != null) { tikhomirov@104: rv.addAll(l); tikhomirov@104: } tikhomirov@104: if ((l = globalFromName.get(tagName)) != null) { tikhomirov@104: rv.addAll(l); tikhomirov@104: } tikhomirov@104: return rv; tikhomirov@50: } tikhomirov@50: }