Package org.tmatesoft.hg.repo

Source Code of org.tmatesoft.hg.repo.HgBookmarks

/*
* Copyright (c) 2012-2013 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@hg4j.com
*/
package org.tmatesoft.hg.repo;

import static org.tmatesoft.hg.util.LogFacility.Severity.Error;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.Map;

import org.tmatesoft.hg.core.HgIOException;
import org.tmatesoft.hg.core.HgRepositoryLockException;
import org.tmatesoft.hg.core.Nodeid;
import org.tmatesoft.hg.internal.FileChangeMonitor;
import org.tmatesoft.hg.internal.Internals;
import org.tmatesoft.hg.internal.LineReader;
import org.tmatesoft.hg.util.LogFacility;

/**
* Access to bookmarks state
*
* @see http://mercurial.selenic.com/wiki/Bookmarks
* @author Artem Tikhomirov
* @author TMate Software Ltd.
*/
public final class HgBookmarks {
  private final Internals repo;
  private Map<String, Nodeid> bookmarks = Collections.emptyMap();
  private String activeBookmark;
  private FileChangeMonitor activeTracker, bmFileTracker;

  HgBookmarks(Internals internals) {
    repo = internals;
  }
 
  /*package-local*/ void read() throws HgRuntimeException {
    readBookmarks();
    readActiveBookmark();
  }
 
  private void readBookmarks() throws HgRuntimeException {
    final LogFacility log = repo.getLog();
    File all = repo.getRepositoryFile(HgRepositoryFiles.Bookmarks);
    try {
      LinkedHashMap<String, Nodeid> bm = new LinkedHashMap<String, Nodeid>();
      if (all.canRead() && all.isFile()) {
        LineReader lr1 = new LineReader(all, log);
        ArrayList<String> c = new ArrayList<String>();
        lr1.read(new LineReader.SimpleLineCollector(), c);
        for (String s : c) {
          int x = s.indexOf(' ');
          try {
            if (x > 0) {
              Nodeid nid = Nodeid.fromAscii(s.substring(0, x));
              String name = new String(s.substring(x+1));
              if (repo.getRepo().getChangelog().isKnown(nid)) {
                // copy name part not to drag complete line
                bm.put(name, nid);
              } else {
                log.dump(getClass(), LogFacility.Severity.Info, "Bookmark %s points to non-existent revision %s, ignored.", name, nid);
              }
            } else {
              log.dump(getClass(), LogFacility.Severity.Warn, "Can't parse bookmark entry: %s", s);
            }
          } catch (IllegalArgumentException ex) {
            log.dump(getClass(), LogFacility.Severity.Warn, ex, String.format("Can't parse bookmark entry: %s", s));
          }
        }
        bookmarks = bm;
      } else {
        bookmarks = Collections.emptyMap();
      }
      if (bmFileTracker == null) {
        bmFileTracker = new FileChangeMonitor(all);
      }
      bmFileTracker.touch(this);
    } catch (HgInvalidControlFileException ex) {
      // do not translate HgInvalidControlFileException into another HgInvalidControlFileException
      // but only HgInvalidFileException
      throw ex;
    } catch (HgIOException ex) {
      throw new HgInvalidControlFileException(ex, true);
    }
  }

  private void readActiveBookmark() throws HgInvalidControlFileException {
    activeBookmark = null;
    File active = repo.getRepositoryFile(HgRepositoryFiles.BookmarksCurrent);
    try {
      if (active.canRead() && active.isFile()) {
        LineReader lr2 = new LineReader(active, repo.getLog());
        ArrayList<String> c = new ArrayList<String>(2);
        lr2.read(new LineReader.SimpleLineCollector(), c);
        if (c.size() > 0) {
          activeBookmark = c.get(0);
        }
      }
      if (activeTracker == null) {
        activeTracker = new FileChangeMonitor(active);
      }
      activeTracker.touch(this);
    } catch (HgIOException ex) {
      throw new HgInvalidControlFileException(ex, true);
    }
  }
 
  /*package-local*/void reloadIfChanged() throws HgRuntimeException {
    assert activeTracker != null;
    assert bmFileTracker != null;
    if (bmFileTracker.changed(this)) {
      readBookmarks();
    }
    if (activeTracker.changed(this)) {
      readActiveBookmark();
    }
  }


  /**
   * Tell name of the active bookmark
   * @return <code>null</code> if none active
   */
  public String getActiveBookmarkName() {
    return activeBookmark;
  }

  /**
   * Retrieve revision associated with the named bookmark.
   *
   * @param bookmarkName name of the bookmark
   * @return revision or <code>null</code> if bookmark is not known
   */
  public Nodeid getRevision(String bookmarkName) {
    return bookmarks.get(bookmarkName);
  }

  /**
   * Retrieve all bookmarks known in the repository
   * @return collection with names, never <code>null</code>
   */
  public Collection<String> getAllBookmarks() {
    // bookmarks are initialized with atomic assignment,
    // hence can use view (not a synchronized copy) here
    return Collections.unmodifiableSet(bookmarks.keySet());
  }

  /**
   * Update currently bookmark with new commit.
   * Note, child has to be descendant of a p1 or p2
   *
   * @param p1 first parent, or <code>null</code>
   * @param p2 second parent, or <code>null</code>
   * @param child new commit, descendant of one of the parents, not <code>null</code>
   * @throws HgIOException if failed to write updated bookmark information
   * @throws HgRepositoryLockException  if failed to lock repository for modifications
   */
  public void updateActive(Nodeid p1, Nodeid p2, Nodeid child) throws HgIOException, HgRepositoryLockException {
    if (activeBookmark == null) {
      return;
    }
    Nodeid activeRev = getRevision(activeBookmark);
    if (!activeRev.equals(p1) && !activeRev.equals(p2)) {
      return; // TestCommit#testNoBookmarkUpdate
    }
    if (child.equals(activeRev)) {
      return;
    }
    LinkedHashMap<String, Nodeid> copy = new LinkedHashMap<String, Nodeid>(bookmarks);
    copy.put(activeBookmark, child);
    bookmarks = copy;
    write();
  }
 
  private void write() throws HgIOException, HgRepositoryLockException {
    File bookmarksFile = repo.getRepositoryFile(HgRepositoryFiles.Bookmarks);
    HgRepositoryLock workingDirLock = repo.getRepo().getWorkingDirLock();
    FileWriter fileWriter = null;
    workingDirLock.acquire();
    try {
      fileWriter = new FileWriter(bookmarksFile);
      for (String bm : bookmarks.keySet()) {
        Nodeid nid = bookmarks.get(bm);
        fileWriter.write(String.format("%s %s\n", nid.toString(), bm));
      }
      fileWriter.flush();
    } catch (IOException ex) {
      throw new HgIOException("Failed to serialize bookmarks", ex, bookmarksFile);
    } finally {
      try {
        if (fileWriter != null) {
          fileWriter.close();
        }
      } catch (IOException ex) {
        repo.getLog().dump(getClass(), Error, ex, null);
      }
      workingDirLock.release();
    }
  }
}
TOP

Related Classes of org.tmatesoft.hg.repo.HgBookmarks

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.