comparison src/org/tmatesoft/hg/repo/HgRepository.java @ 74:6f1b88693d48

Complete refactoring to org.tmatesoft
author Artem Tikhomirov <tikhomirov.artem@gmail.com>
date Mon, 24 Jan 2011 03:14:45 +0100
parents src/com/tmate/hgkit/ll/HgRepository.java@0e499fed9b3d
children c677e1593919
comparison
equal deleted inserted replaced
73:0d279bcc4442 74:6f1b88693d48
1 /*
2 * Copyright (c) 2010-2011 TMate Software Ltd
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; version 2 of the License.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * For information on how to redistribute this software under
14 * the terms of a license other than GNU General Public License
15 * contact TMate Software at support@svnkit.com
16 */
17 package org.tmatesoft.hg.repo;
18
19 import java.io.File;
20 import java.io.IOException;
21 import java.lang.ref.SoftReference;
22 import java.util.HashMap;
23
24 import org.tmatesoft.hg.core.Path;
25 import org.tmatesoft.hg.internal.DataAccessProvider;
26 import org.tmatesoft.hg.internal.RequiresFile;
27 import org.tmatesoft.hg.util.FileWalker;
28 import org.tmatesoft.hg.util.PathRewrite;
29
30
31
32 /**
33 * Shall be as state-less as possible, all the caching happens outside the repo, in commands/walkers
34 *
35 * @author Artem Tikhomirov
36 * @author TMate Software Ltd.
37 */
38 public final class HgRepository {
39
40 public static final int TIP = -1;
41 public static final int BAD_REVISION = Integer.MIN_VALUE;
42 public static final int WORKING_COPY = -2;
43
44 // temp aux marker method
45 public static IllegalStateException notImplemented() {
46 return new IllegalStateException("Not implemented");
47 }
48
49 private final File repoDir; // .hg folder
50 private final String repoLocation;
51 private final DataAccessProvider dataAccess;
52 private final PathRewrite normalizePath = new PathRewrite() {
53
54 public String rewrite(String path) {
55 // TODO handle . and .. (although unlikely to face them from GUI client)
56 path = path.replace('\\', '/').replace("//", "/");
57 if (path.startsWith("/")) {
58 path = path.substring(1);
59 }
60 return path;
61 }
62 };
63 private final PathRewrite dataPathHelper;
64 private final PathRewrite repoPathHelper;
65
66 private Changelog changelog;
67 private HgManifest manifest;
68 private HgTags tags;
69 // XXX perhaps, shall enable caching explicitly
70 private final HashMap<Path, SoftReference<RevlogStream>> streamsCache = new HashMap<Path, SoftReference<RevlogStream>>();
71
72 private final org.tmatesoft.hg.internal.Internals impl = new org.tmatesoft.hg.internal.Internals();
73
74 HgRepository(String repositoryPath) {
75 repoDir = null;
76 repoLocation = repositoryPath;
77 dataAccess = null;
78 dataPathHelper = repoPathHelper = null;
79 }
80
81 HgRepository(File repositoryRoot) throws IOException {
82 assert ".hg".equals(repositoryRoot.getName()) && repositoryRoot.isDirectory();
83 repoDir = repositoryRoot;
84 repoLocation = repositoryRoot.getParentFile().getCanonicalPath();
85 dataAccess = new DataAccessProvider();
86 parseRequires();
87 dataPathHelper = impl.buildDataFilesHelper();
88 repoPathHelper = impl.buildRepositoryFilesHelper();
89 }
90
91
92 public String getLocation() {
93 return repoLocation;
94 }
95
96 public boolean isInvalid() {
97 return repoDir == null || !repoDir.exists() || !repoDir.isDirectory();
98 }
99
100 public Changelog getChangelog() {
101 if (this.changelog == null) {
102 String storagePath = repoPathHelper.rewrite("00changelog.i");
103 RevlogStream content = resolve(Path.create(storagePath));
104 this.changelog = new Changelog(this, content);
105 }
106 return this.changelog;
107 }
108
109 public HgManifest getManifest() {
110 if (this.manifest == null) {
111 RevlogStream content = resolve(Path.create(repoPathHelper.rewrite("00manifest.i")));
112 this.manifest = new HgManifest(this, content);
113 }
114 return this.manifest;
115 }
116
117 public final HgTags getTags() {
118 if (tags == null) {
119 tags = new HgTags();
120 }
121 return tags;
122 }
123
124 public HgDataFile getFileNode(String path) {
125 String nPath = normalizePath.rewrite(path);
126 String storagePath = dataPathHelper.rewrite(nPath);
127 return getFileNode(Path.create(storagePath));
128 }
129
130 public HgDataFile getFileNode(Path path) {
131 RevlogStream content = resolve(path);
132 // XXX no content when no file? or HgDataFile.exists() to detect that? How about files that were removed in previous releases?
133 return new HgDataFile(this, path, content);
134 }
135
136 public PathRewrite getPathHelper() { // Really need to be public?
137 return normalizePath;
138 }
139
140 /*package-local*/ File getRepositoryRoot() {
141 return repoDir;
142 }
143
144 // XXX package-local, unless there are cases when required from outside (guess, working dir/revision walkers may hide dirstate access and no public visibility needed)
145 /*package-local*/ final HgDirstate loadDirstate() {
146 return new HgDirstate(getDataAccess(), new File(repoDir, "dirstate"));
147 }
148
149 // package-local, see comment for loadDirstate
150 /*package-local*/ final HgIgnore loadIgnore() {
151 return new HgIgnore(this);
152 }
153
154 /*package-local*/ DataAccessProvider getDataAccess() {
155 return dataAccess;
156 }
157
158 // FIXME not sure repository shall create walkers
159 /*package-local*/ FileWalker createWorkingDirWalker() {
160 return new FileWalker(repoDir.getParentFile());
161 }
162
163 /**
164 * Perhaps, should be separate interface, like ContentLookup
165 * path - repository storage path (i.e. one usually with .i or .d)
166 */
167 /*package-local*/ RevlogStream resolve(Path path) {
168 final SoftReference<RevlogStream> ref = streamsCache.get(path);
169 RevlogStream cached = ref == null ? null : ref.get();
170 if (cached != null) {
171 return cached;
172 }
173 File f = new File(repoDir, path.toString());
174 if (f.exists()) {
175 RevlogStream s = new RevlogStream(dataAccess, f);
176 streamsCache.put(path, new SoftReference<RevlogStream>(s));
177 return s;
178 }
179 return null; // XXX empty stream instead?
180 }
181
182 private void parseRequires() {
183 new RequiresFile().parse(impl, new File(repoDir, "requires"));
184 }
185 }