PageRenderTime 24ms CodeModel.GetById 0ms RepoModel.GetById 0ms app.codeStats 0ms

/projects/netbeans-7.3/mercurial/src/org/netbeans/modules/mercurial/HistoryRegistry.java

https://gitlab.com/essere.lab.public/qualitas.class-corpus
Java | 324 lines | 241 code | 27 blank | 56 comment | 54 complexity | bfccb5e49c0cb7a3c8918d3f617247ec MD5 | raw file
  1. /*
  2. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
  3. *
  4. * Copyright 2012 Oracle and/or its affiliates. All rights reserved.
  5. *
  6. * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
  7. * Other names may be trademarks of their respective owners.
  8. *
  9. * The contents of this file are subject to the terms of either the GNU
  10. * General Public License Version 2 only ("GPL") or the Common
  11. * Development and Distribution License("CDDL") (collectively, the
  12. * "License"). You may not use this file except in compliance with the
  13. * License. You can obtain a copy of the License at
  14. * http://www.netbeans.org/cddl-gplv2.html
  15. * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
  16. * specific language governing permissions and limitations under the
  17. * License. When distributing the software, include this License Header
  18. * Notice in each file and include the License file at
  19. * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this
  20. * particular file as subject to the "Classpath" exception as provided
  21. * by Oracle in the GPL Version 2 section of the License file that
  22. * accompanied this code. If applicable, add the following below the
  23. * License Header, with the fields enclosed by brackets [] replaced by
  24. * your own identifying information:
  25. * "Portions Copyrighted [year] [name of copyright owner]"
  26. *
  27. * If you wish your version of this file to be governed by only the CDDL
  28. * or only the GPL Version 2, indicate your decision by adding
  29. * "[Contributor] elects to include this software in this distribution
  30. * under the [CDDL or GPL Version 2] license." If you do not indicate a
  31. * single choice of license, a recipient has the option to distribute
  32. * your version of this file under either the CDDL, the GPL Version 2 or
  33. * to extend the choice of license to its licensees as provided above.
  34. * However, if you add GPL Version 2 code and therefore, elected the GPL
  35. * Version 2 license, then the option applies only if the new code is
  36. * made subject to such option by the copyright holder.
  37. *
  38. * Contributor(s):
  39. *
  40. * Portions Copyrighted 2012 Sun Microsystems, Inc.
  41. */
  42. package org.netbeans.modules.mercurial;
  43. import java.io.ByteArrayInputStream;
  44. import java.io.ByteArrayOutputStream;
  45. import java.io.DataInputStream;
  46. import java.io.DataOutputStream;
  47. import java.io.File;
  48. import java.io.IOException;
  49. import java.util.*;
  50. import java.util.Map.Entry;
  51. import java.util.logging.Level;
  52. import java.util.logging.Logger;
  53. import org.netbeans.modules.mercurial.ui.log.HgLogMessage;
  54. import org.netbeans.modules.mercurial.ui.log.HgLogMessageChangedPath;
  55. import org.netbeans.modules.mercurial.util.HgCommand;
  56. import org.netbeans.modules.mercurial.util.HgUtils;
  57. import org.netbeans.modules.versioning.historystore.Storage;
  58. import org.netbeans.modules.versioning.historystore.StorageManager;
  59. import org.openide.util.NbBundle;
  60. /**
  61. *
  62. * @author Tomas Stupka
  63. */
  64. public class HistoryRegistry {
  65. private static HistoryRegistry instance;
  66. private static final Logger LOG = Logger.getLogger("org.netbeans.modules.mercurial.HistoryRegistry"); // NOI18N
  67. // package private for test purposes
  68. static final String PERSISTED_DATA_VERSION = "1.0";
  69. private Map<File, List<HgLogMessage>> logs = Collections.synchronizedMap(new HashMap<File, List<HgLogMessage>>());
  70. // let's keep only 100 items in memory
  71. private Map<String, List<HgLogMessageChangedPath>> changesets = Collections.synchronizedMap(new LinkedHashMap<String, List<HgLogMessageChangedPath>>() {
  72. @Override
  73. protected boolean removeEldestEntry (Entry<String, List<HgLogMessageChangedPath>> eldest) {
  74. return size() >= 100;
  75. }
  76. });
  77. private HistoryRegistry() {}
  78. public synchronized static HistoryRegistry getInstance() {
  79. if(instance == null) {
  80. instance = new HistoryRegistry();
  81. }
  82. return instance;
  83. }
  84. public HgLogMessage[] getLogs(File repository, File[] files, String fromRevision, String toRevision) {
  85. HgLogMessage[] history =
  86. HgCommand.getLogMessages(
  87. repository,
  88. new HashSet(Arrays.asList(files)),
  89. fromRevision,
  90. toRevision,
  91. false, // show merges
  92. false, // get files info
  93. false, // get parents
  94. -1, // limit
  95. Collections.<String>emptyList(), // branch names
  96. OutputLogger.getLogger(repository.getAbsolutePath()), // logger
  97. false); // asc order
  98. if(history.length > 0) {
  99. for (File f : files) {
  100. logs.put(f, Arrays.asList(history));
  101. }
  102. }
  103. return history;
  104. }
  105. HgLogMessage getLog (File repository, File file, String changesetId) {
  106. List<HgLogMessage> knownLogs = logs.get(file);
  107. if (knownLogs != null) {
  108. for (HgLogMessage logMessage : knownLogs) {
  109. if (logMessage.getCSetShortID().equals(changesetId)) {
  110. return logMessage;
  111. }
  112. }
  113. }
  114. HgLogMessage[] history = HgCommand.getRevisionInfo(repository, Collections.singletonList(changesetId), OutputLogger.getLogger(repository.getAbsolutePath()));
  115. return history == null || history.length == 0 ? null : history[0];
  116. }
  117. public File getHistoryFile(final File repository, final File originalFile, final String revision, final boolean dryTry) {
  118. long t = System.currentTimeMillis();
  119. String originalPath = HgUtils.getRelativePath(originalFile);
  120. try {
  121. final List<HgLogMessage> history = logs.get(originalFile);
  122. final String path = originalPath;
  123. final String[] ret = new String[] {null};
  124. if(history != null) {
  125. HgProgressSupport support = new HgProgressSupport(NbBundle.getMessage(HistoryRegistry.class, "LBL_LookingUp"), null) { // NOI18N
  126. @Override
  127. protected void perform() {
  128. ret[0] = getRepositoryPathIntern(history, revision, repository, originalFile, path, dryTry, this);
  129. }
  130. };
  131. support.start(Mercurial.getInstance().getRequestProcessor(repository)).waitFinished();
  132. }
  133. if(ret[0] != null && !ret[0].equals(originalPath)) {
  134. return new File(repository, ret[0]);
  135. }
  136. return null;
  137. } finally {
  138. if(LOG.isLoggable(Level.FINE)) {
  139. LOG.log(Level.FINE, " resolving historyFile for {0} took {1}", new Object[]{originalPath, System.currentTimeMillis() - t}); // NOI18N
  140. }
  141. }
  142. }
  143. private String getRepositoryPathIntern(List<HgLogMessage> history, String revision, File repository, File originalFile, final String path, boolean dryTry, HgProgressSupport support) {
  144. int count = 0;
  145. String historyPath = path;
  146. Iterator<HgLogMessage> it = history.iterator();
  147. while(it.hasNext() && !revision.equals(it.next().getHgRevision().getChangesetId())) {
  148. count++;
  149. }
  150. support.getProgressHandle().switchToDeterminate(count);
  151. // XXX try dry first, might be it will lead to the in in the revision
  152. for (int i = 0; i < history.size() && !support.isCanceled(); i ++) {
  153. HgLogMessage lm = history.get(i);
  154. String historyRevision = lm.getHgRevision().getChangesetId();
  155. if(historyRevision.equals(revision)) {
  156. break;
  157. }
  158. support.getProgressHandle().progress(NbBundle.getMessage(HistoryRegistry.class, "LBL_LookingUpAtRevision", originalFile.getName(), historyRevision), i); // NOI18N
  159. List<HgLogMessageChangedPath> changePaths = lm.getChangedPaths().length == 0 ?
  160. initializeChangePaths(repository, new DefaultChangePathCollector(
  161. repository, OutputLogger.getLogger(repository.getAbsolutePath()), lm.getCSetShortID()), lm, dryTry)
  162. : Arrays.asList(lm.getChangedPaths());
  163. if(changePaths != null) {
  164. for (HgLogMessageChangedPath cp : changePaths) {
  165. String copy = cp.getCopySrcPath();
  166. if(copy != null) {
  167. if(historyPath.equals(cp.getPath())) {
  168. historyPath = copy;
  169. break;
  170. }
  171. }
  172. }
  173. }
  174. }
  175. // XXX check if found path exists in the revision we search for ...
  176. return support.isCanceled() ? path : historyPath;
  177. }
  178. public List<HgLogMessageChangedPath> initializeChangePaths (File repository, ChangePathCollector collector, HgLogMessage lm, boolean onlyCached) {
  179. assert lm.getChangedPaths().length == 0 : "Why refreshing already loaded change paths??? length=" + lm.getChangedPaths().length;
  180. String changesetId = lm.getCSetShortID();
  181. List<HgLogMessageChangedPath> changePaths = changesets.get(changesetId);
  182. if (changePaths == null) {
  183. long t1 = System.currentTimeMillis();
  184. boolean persist = true;
  185. if (!"false".equals(System.getProperty("versioning.mercurial.historycache.enable", "true"))) { //NOI18N
  186. LOG.log(Level.FINE, "loading changePaths from disk cache for {0}", new Object[] { changesetId }); //NOI18N
  187. persist = false;
  188. changePaths = loadCachedChangePaths(repository, lm.getCSetShortID());
  189. if (changePaths == null) {
  190. persist = true;
  191. LOG.log(Level.FINE, "loading changePaths from disk cache failed for {0}", new Object[] { changesetId }); //NOI18N
  192. }
  193. }
  194. if (changePaths == null && !onlyCached) {
  195. // not in mem cache and not stored on disk, let's call hg command
  196. LOG.log(Level.FINE, "loading changePaths via hg for {0}", new Object[] { changesetId }); //NOI18N
  197. HgLogMessageChangedPath[] cps = collector.getChangePaths();
  198. changePaths = Arrays.asList(cps == null ? new HgLogMessageChangedPath[0] : cps);
  199. }
  200. if (changePaths != null) {
  201. lm.refreshChangedPaths(changePaths.toArray(new HgLogMessageChangedPath[changePaths.size()]));
  202. changesets.put(changesetId, changePaths);
  203. if (persist && !changePaths.isEmpty() && !"false".equals(System.getProperty("versioning.mercurial.historycache.enable", "true"))) { //NOI18N
  204. persistPaths(repository, changePaths, lm.getCSetShortID());
  205. }
  206. }
  207. if(LOG.isLoggable(Level.FINE)) {
  208. LOG.log(Level.FINE, " loading changePaths for {0} took {1}", new Object[] { changesetId, System.currentTimeMillis() - t1}); // NOI18N
  209. }
  210. }
  211. return changePaths;
  212. }
  213. private void persistPaths (File repository, List<HgLogMessageChangedPath> changePaths, String revision) {
  214. Storage storage = StorageManager.getInstance().getStorage(repository.getAbsolutePath());
  215. ByteArrayOutputStream content = new ByteArrayOutputStream();
  216. DataOutputStream dos = new DataOutputStream(content);
  217. try {
  218. dos.writeUTF(PERSISTED_DATA_VERSION);
  219. dos.writeInt(changePaths.size());
  220. for (HgLogMessageChangedPath path : changePaths) {
  221. dos.writeUTF(path.getPath());
  222. dos.writeChar(path.getAction());
  223. dos.writeUTF(path.getCopySrcPath() == null ? "" : path.getCopySrcPath());
  224. }
  225. dos.close();
  226. LOG.log(Level.FINE, "persisting changePaths to disk cache for {0}", new Object[] { revision }); //NOI18N
  227. storage.setRevisionInfo(revision, new ByteArrayInputStream(content.toByteArray()));
  228. } catch (IOException ex) {
  229. LOG.log(Level.INFO, "Cannot persist data", ex); //NOI18N
  230. }
  231. }
  232. private List<HgLogMessageChangedPath> loadCachedChangePaths (File repository, String revision) {
  233. Storage storage = StorageManager.getInstance().getStorage(repository.getAbsolutePath());
  234. byte[] buff = storage.getRevisionInfo(revision);
  235. if (buff == null) {
  236. return null;
  237. }
  238. List<HgLogMessageChangedPath> changePaths = null;
  239. DataInputStream dis = new DataInputStream(new ByteArrayInputStream(buff));
  240. try {
  241. String version = dis.readUTF();
  242. if (PERSISTED_DATA_VERSION.equals(version)) {
  243. int len = dis.readInt();
  244. changePaths = len == 0 ? null : new ArrayList<HgLogMessageChangedPath>(len); // do not care about empty paths, test for 0
  245. for (int i = 0; i < len; ++i) {
  246. String path = dis.readUTF();
  247. char action = dis.readChar();
  248. String copyPath = dis.readUTF();
  249. changePaths.add(new HgLogMessageChangedPath(path, copyPath.isEmpty() ? null : copyPath, action));
  250. }
  251. }
  252. } catch (IOException ex) {
  253. LOG.log(Level.FINE, "changePaths from disk cache corrupted {0}", new Object[] { revision }); //NOI18N
  254. }
  255. return changePaths;
  256. }
  257. public static interface ChangePathCollector {
  258. HgLogMessageChangedPath[] getChangePaths ();
  259. }
  260. public static final class DefaultChangePathCollector implements ChangePathCollector {
  261. private final File repositoryRoot;
  262. private final OutputLogger logger;
  263. private final String changesetId;
  264. public DefaultChangePathCollector (File repositoryRoot, OutputLogger logger, String changesetId) {
  265. this.repositoryRoot = repositoryRoot;
  266. this.logger = logger;
  267. this.changesetId = changesetId;
  268. }
  269. @Override
  270. public HgLogMessageChangedPath[] getChangePaths () {
  271. HgLogMessage[] messages = HgCommand.getLogMessages(repositoryRoot,
  272. null,
  273. changesetId,
  274. changesetId,
  275. true,
  276. true,
  277. false,
  278. 1,
  279. Collections.<String>emptyList(),
  280. logger,
  281. true);
  282. return messages == null || messages.length == 0 ? new HgLogMessageChangedPath[0] : messages[0].getChangedPaths();
  283. }
  284. }
  285. /**
  286. * Test purposes for now
  287. */
  288. List<HgLogMessageChangedPath> getCachedPaths (String revision) {
  289. return changesets.get(revision);
  290. }
  291. /**
  292. * Test purposes for now
  293. */
  294. void flushCached () {
  295. changesets.clear();
  296. }
  297. }