Mercurial > hg4j
diff src/org/tmatesoft/hg/repo/HgTags.java @ 610:5c68567b3645
Refresh tags, branches, bookmarks and ignore when their files (or csets in the repo) are changed
author | Artem Tikhomirov <tikhomirov.artem@gmail.com> |
---|---|
date | Thu, 09 May 2013 21:06:48 +0200 |
parents | d9c07e1432c4 |
children | 6526d8adbc0f |
line wrap: on
line diff
--- a/src/org/tmatesoft/hg/repo/HgTags.java Wed May 08 17:11:45 2013 +0200 +++ b/src/org/tmatesoft/hg/repo/HgTags.java Thu May 09 21:06:48 2013 +0200 @@ -16,6 +16,9 @@ */ package org.tmatesoft.hg.repo; +import static org.tmatesoft.hg.repo.HgRepositoryFiles.HgLocalTags; +import static org.tmatesoft.hg.repo.HgRepositoryFiles.HgTags; +import static org.tmatesoft.hg.util.LogFacility.Severity.*; import static org.tmatesoft.hg.util.LogFacility.Severity.Error; import static org.tmatesoft.hg.util.LogFacility.Severity.Warn; @@ -24,6 +27,7 @@ import java.io.FileReader; import java.io.IOException; import java.io.Reader; +import java.io.StringReader; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; @@ -34,6 +38,11 @@ import org.tmatesoft.hg.core.HgBadNodeidFormatException; import org.tmatesoft.hg.core.Nodeid; +import org.tmatesoft.hg.internal.ByteArrayChannel; +import org.tmatesoft.hg.internal.ChangelogMonitor; +import org.tmatesoft.hg.internal.FileChangeMonitor; +import org.tmatesoft.hg.internal.Internals; +import org.tmatesoft.hg.util.CancelledException; /** * @see http://mercurial.selenic.com/wiki/TagDesign @@ -45,38 +54,83 @@ // global tags come from ".hgtags" // local come from ".hg/localtags" - private final HgRepository repo; + private final Internals repo; private final Map<Nodeid, List<String>> globalToName; private final Map<Nodeid, List<String>> localToName; private final Map<String, List<Nodeid>> globalFromName; private final Map<String, List<Nodeid>> localFromName; + private FileChangeMonitor globalTagsFileMonitor, localTagsFileMonitor; + private ChangelogMonitor repoChangeMonitor; + private Map<String, TagInfo> tags; - /*package-local*/ HgTags(HgRepository hgRepo) { - repo = hgRepo; + /*package-local*/ HgTags(Internals internalRepo) { + repo = internalRepo; globalToName = new HashMap<Nodeid, List<String>>(); localToName = new HashMap<Nodeid, List<String>>(); globalFromName = new TreeMap<String, List<Nodeid>>(); localFromName = new TreeMap<String, List<Nodeid>>(); } - /*package-local*/ void readLocal(File localTags) throws IOException { - if (localTags == null || localTags.isDirectory()) { - throw new IllegalArgumentException(String.valueOf(localTags)); - } - read(localTags, localToName, localFromName); + /*package-local*/ void read() throws HgInvalidControlFileException { + readTagsFromHistory(); + readGlobal(); + readLocal(); } - /*package-local*/ void readGlobal(File globalTags) throws IOException { - if (globalTags == null || globalTags.isDirectory()) { - throw new IllegalArgumentException(String.valueOf(globalTags)); + private void readTagsFromHistory() throws HgInvalidControlFileException { + HgDataFile hgTags = repo.getRepo().getFileNode(HgTags.getPath()); + if (hgTags.exists()) { + for (int i = 0; i <= hgTags.getLastRevision(); i++) { // TODO post-1.0 in fact, would be handy to have walk(start,end) + // method for data files as well, though it looks odd. + try { + ByteArrayChannel sink = new ByteArrayChannel(); + hgTags.content(i, sink); + final String content = new String(sink.toArray(), "UTF8"); + readGlobal(new StringReader(content)); + } catch (CancelledException ex) { + // IGNORE, can't happen, we did not configure cancellation + repo.getLog().dump(getClass(), Debug, ex, null); + } catch (IOException ex) { + // UnsupportedEncodingException can't happen (UTF8) + // only from readGlobal. Need to reconsider exceptions thrown from there: + // BufferedReader wraps String and unlikely to throw IOException, perhaps, log is enough? + repo.getLog().dump(getClass(), Error, ex, null); + // XXX need to decide what to do this. failure to read single revision shall not break complete cycle + } + } } - read(globalTags, globalToName, globalFromName); + if (repoChangeMonitor == null) { + repoChangeMonitor = new ChangelogMonitor(repo.getRepo()); + } + repoChangeMonitor.touch(); + } + + private void readLocal() throws HgInvalidControlFileException { + File localTags = repo.getRepositoryFile(HgLocalTags); + if (localTags.canRead() && localTags.isFile()) { + read(localTags, localToName, localFromName); + } + if (localTagsFileMonitor == null) { + localTagsFileMonitor = new FileChangeMonitor(localTags); + } + localTagsFileMonitor.touch(this); + } + + private void readGlobal() throws HgInvalidControlFileException { + File globalTags = repo.getRepositoryFile(HgTags); // XXX replace with HgDataFile.workingCopy + if (globalTags.canRead() && globalTags.isFile()) { + read(globalTags, globalToName, globalFromName); + } + if (globalTagsFileMonitor == null) { + globalTagsFileMonitor = new FileChangeMonitor(globalTags); + } + globalTagsFileMonitor.touch(this); } - /*package-local*/ void readGlobal(Reader globalTags) throws IOException { + private void readGlobal(Reader globalTags) throws IOException { BufferedReader r = null; try { r = new BufferedReader(globalTags); @@ -88,7 +142,7 @@ } } - private void read(File f, Map<Nodeid,List<String>> nid2name, Map<String, List<Nodeid>> name2nid) throws IOException { + private void read(File f, Map<Nodeid,List<String>> nid2name, Map<String, List<Nodeid>> name2nid) throws HgInvalidControlFileException { if (!f.canRead()) { return; } @@ -96,9 +150,17 @@ try { r = new BufferedReader(new FileReader(f)); read(r, nid2name, name2nid); + } catch (IOException ex) { + repo.getLog().dump(getClass(), Error, ex, null); + throw new HgInvalidControlFileException("Failed to read tags", ex, f); } finally { if (r != null) { - r.close(); + try { + r.close(); + } catch (IOException ex) { + // since it's read operation, do not treat close failure as error, but let user know, anyway + repo.getLog().dump(getClass(), Warn, ex, null); + } } } } @@ -112,7 +174,7 @@ } final int spacePos = line.indexOf(' '); if (line.length() < 40+2 /*nodeid, space and at least single-char tagname*/ || spacePos != 40) { - repo.getSessionContext().getLog().dump(getClass(), Warn, "Bad tags line: %s", line); + repo.getLog().dump(getClass(), Warn, "Bad tags line: %s", line); continue; } try { @@ -154,7 +216,7 @@ revTags.add(tagName); } } catch (HgBadNodeidFormatException ex) { - repo.getSessionContext().getLog().dump(getClass(), Error, "Bad revision '%s' in line '%s':%s", line.substring(0, spacePos), line, ex.getMessage()); + repo.getLog().dump(getClass(), Error, "Bad revision '%s' in line '%s':%s", line.substring(0, spacePos), line, ex.getMessage()); } } } @@ -217,6 +279,23 @@ return rv; } + // can be called only after instance has been initialized (#read() invoked) + /*package-local*/void reloadIfChanged() throws HgInvalidControlFileException { + assert repoChangeMonitor != null; + assert localTagsFileMonitor != null; + assert globalTagsFileMonitor != null; + if (repoChangeMonitor.isChanged() || globalTagsFileMonitor.changed(this)) { + globalFromName.clear(); + globalToName.clear(); + readTagsFromHistory(); + readGlobal(); + tags = null; + } + if (localTagsFileMonitor.changed(this)) { + readLocal(); + tags = null; + } + } public final class TagInfo { private final String name; @@ -235,8 +314,8 @@ public String branch() throws HgInvalidControlFileException { if (branch == null) { - int x = repo.getChangelog().getRevisionIndex(revision()); - branch = repo.getChangelog().range(x, x).get(0).branch(); + int x = repo.getRepo().getChangelog().getRevisionIndex(revision()); + branch = repo.getRepo().getChangelog().range(x, x).get(0).branch(); } return branch; }