Package org.tmatesoft.hg.internal

Source Code of org.tmatesoft.hg.internal.SubrepoManager

/*
* Copyright (c) 2011-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.internal;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import org.tmatesoft.hg.core.Nodeid;
import org.tmatesoft.hg.repo.HgInternals;
import org.tmatesoft.hg.repo.HgInvalidControlFileException;
import org.tmatesoft.hg.repo.HgRepository;
import org.tmatesoft.hg.repo.HgSubrepoLocation;
import org.tmatesoft.hg.util.Path;

/**
*
* @see http://mercurial.selenic.com/wiki/SubrepoWork
* @see http://mercurial.selenic.com/wiki/Subrepository
* @author Artem Tikhomirov
* @author TMate Software Ltd.
*/
public class SubrepoManager /* XXX RepoChangeNotifier, RepoChangeListener */{

  private final HgRepository repo;
  private List<HgSubrepoLocation> subRepos;

  public SubrepoManager(HgRepository hgRepo) {
    assert hgRepo != null;
    repo = hgRepo;
  }

  private List<HgSubrepoLocation> readActualState() throws HgInvalidControlFileException {
    File hgsubFile = new File(repo.getWorkingDir(), ".hgsub");
    if (!hgsubFile.canRead()) {
      return Collections.emptyList();
    }
    Map<String, String> state; // path -> revision
    File hgstateFile = null;
    try {
      hgstateFile = new File(repo.getWorkingDir(), ".hgsubstate");
      if (hgstateFile.canRead()) {
        state = readState(new BufferedReader(new FileReader(hgstateFile)));
      } else {
        state = Collections.emptyMap();
      }
    } catch (IOException ex) {
      throw new HgInvalidControlFileException("Subrepo state read failed", ex, hgstateFile);
    }
    try {
      BufferedReader br = new BufferedReader(new FileReader(hgsubFile));
      return readConfig(br, state);
    } catch (IOException ex) {
      throw new HgInvalidControlFileException("Subrepo state read failed", ex, hgsubFile);
    }
  }

  private List<HgSubrepoLocation> readConfig(BufferedReader br, Map<String, String> substate) throws IOException {
    try {
      String line;
      LinkedList<HgSubrepoLocation> res = new LinkedList<HgSubrepoLocation>();
      HgInternals hgRepoInternal = new HgInternals(repo);
      final Path.Source pathFactory = repo.getSessionContext().getPathFactory();
      while ((line = br.readLine()) != null) {
        int sep = line.indexOf('=');
        if (sep == -1) {
          continue;
        }
        // since both key and value are referenced from HgSubrepoLocation, doesn't make sense
        // to have separate String instances (new String(line.substring()))
        String key = line.substring(0, sep).trim();
        String value = line.substring(sep + 1).trim();
        if (key.length() == 0 || value.length() == 0) {
          // XXX log bad line?
          continue;
        }
        HgSubrepoLocation.Kind kind = HgSubrepoLocation.Kind.Hg;
        int kindEnd = value.indexOf(']', 1);
        if (value.charAt(0) == '[' && kindEnd != -1) {
          String kindStr = value.substring(1, kindEnd);
          value = value.substring(kindEnd + 1);
          if ("svn".equals(kindStr)) {
            kind = HgSubrepoLocation.Kind.SVN;
          } else if ("git".equals(kindStr)) {
            kind = HgSubrepoLocation.Kind.Git;
          }
        }
        // TODO respect paths mappings in config file
        //
        // apparently, key value can't end with '/', `hg commit` fails if it does:
        // abort: path ends in directory separator: fourth/
        Path p = pathFactory.path(key.charAt(key.length()-1) == '/' ? key : key + '/');
        String revValue = substate.get(key);
        HgSubrepoLocation loc = hgRepoInternal.newSubrepo(p, value, kind, revValue == null ? null : Nodeid.fromAscii(revValue));
        res.add(loc);
      }
      return Arrays.asList(res.toArray(new HgSubrepoLocation[res.size()]));
    } finally {
      br.close();
    }
  }

  private Map<String, String> readState(BufferedReader br) throws IOException {
    // TODO reuse for other files with <revision><space><value> format, like .hgtags
    HashMap<String, String> rv = new HashMap<String, String>();
    try {
      String line;
      while ((line = br.readLine()) != null) {
        int sep = line.trim().indexOf(' ');
        if (sep != -1) {
          rv.put(line.substring(sep+1).trim(), line.substring(0, sep).trim());
        }
      }
    } finally {
      br.close();
    }
    return rv;
  }

  /*public to allow access from HgRepository, otherwise package-local*/
  public void read() throws HgInvalidControlFileException {
    subRepos = readActualState();
  }
 
  public List<HgSubrepoLocation> all(/*int revision, or TIP|WC*/) {
    assert subRepos != null;
    return subRepos;
  }
}
TOP

Related Classes of org.tmatesoft.hg.internal.SubrepoManager

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.