blob: 0c701aa49d9fcdbc1a0cd7fc2112d7cc7b4d9df0 [file] [log] [blame]
Stuart McCulloch26e7a5a2011-10-17 10:31:43 +00001package aQute.lib.deployer;
2
3import java.io.*;
4import java.util.*;
5import java.util.jar.*;
6import java.util.regex.*;
7
8import aQute.bnd.service.*;
9import aQute.lib.io.*;
10import aQute.lib.osgi.*;
11import aQute.libg.reporter.*;
12import aQute.libg.version.*;
13
14public class FileRepo implements Plugin, RepositoryPlugin, Refreshable, RegistryPlugin {
15 public static String LOCATION = "location";
16 public static String READONLY = "readonly";
17 public static String NAME = "name";
18
19 File[] EMPTY_FILES = new File[0];
20 protected File root;
21 Registry registry;
22 boolean canWrite = true;
23 Pattern REPO_FILE = Pattern
24 .compile("([-a-zA-z0-9_\\.]+)-([0-9\\.]+|latest)\\.(jar|lib)");
25 Reporter reporter;
26 boolean dirty;
27 String name;
28
29 public FileRepo() {}
30
31 public FileRepo(String name, File location, boolean canWrite) {
32 this.name = name;
33 this.root = location;
34 this.canWrite = canWrite;
35 }
36
37 protected void init() throws Exception {
38 // for extensions
39 }
40
41 public void setProperties(Map<String, String> map) {
42 String location = (String) map.get(LOCATION);
43 if (location == null)
44 throw new IllegalArgumentException(
45 "Location must be set on a FileRepo plugin");
46
47 root = new File(location);
48 if (!root.isDirectory())
49 throw new IllegalArgumentException(
50 "Repository is not a valid directory " + root);
51
52 String readonly = (String) map.get(READONLY);
53 if (readonly != null && Boolean.valueOf(readonly).booleanValue())
54 canWrite = false;
55
56 name = (String) map.get(NAME);
57 }
58
59 /**
60 * Get a list of URLs to bundles that are constrained by the bsn and
61 * versionRange.
62 */
63 public File[] get(String bsn, String versionRange)
64 throws Exception {
65 init();
66
67 // If the version is set to project, we assume it is not
68 // for us. A project repo will then get it.
69 if (versionRange != null && versionRange.equals("project"))
70 return null;
71
72 //
73 // Check if the entry exists
74 //
75 File f = new File(root, bsn);
76 if (!f.isDirectory())
77 return null;
78
79 //
80 // The version range we are looking for can
81 // be null (for all) or a version range.
82 //
83 VersionRange range;
84 if (versionRange == null || versionRange.equals("latest")) {
85 range = new VersionRange("0");
86 } else
87 range = new VersionRange(versionRange);
88
89 //
90 // Iterator over all the versions for this BSN.
91 // Create a sorted map over the version as key
92 // and the file as URL as value. Only versions
93 // that match the desired range are included in
94 // this list.
95 //
96 File instances[] = f.listFiles();
97 SortedMap<Version, File> versions = new TreeMap<Version, File>();
98 for (int i = 0; i < instances.length; i++) {
99 Matcher m = REPO_FILE.matcher(instances[i].getName());
100 if (m.matches() && m.group(1).equals(bsn)) {
101 String versionString = m.group(2);
102 Version version;
103 if (versionString.equals("latest"))
104 version = new Version(Integer.MAX_VALUE);
105 else
106 version = new Version(versionString);
107
108 if (range.includes(version)
109 || versionString.equals(versionRange))
110 versions.put(version, instances[i]);
111 }
112 }
113
114 File[] files = (File[]) versions.values().toArray(EMPTY_FILES);
115 if ("latest".equals(versionRange) && files.length > 0) {
116 return new File[] { files[files.length - 1] };
117 }
118 return files;
119 }
120
121 public boolean canWrite() {
122 return canWrite;
123 }
124
125 public File put(Jar jar) throws Exception {
126 init();
127 dirty = true;
128
129 Manifest manifest = jar.getManifest();
130 if (manifest == null)
131 throw new IllegalArgumentException("No manifest in JAR: " + jar);
132
133 String bsn = manifest.getMainAttributes().getValue(
134 Analyzer.BUNDLE_SYMBOLICNAME);
135 if (bsn == null)
136 throw new IllegalArgumentException("No Bundle SymbolicName set");
137
138 Map<String, Map<String, String>> b = Processor.parseHeader(bsn, null);
139 if (b.size() != 1)
140 throw new IllegalArgumentException("Multiple bsn's specified " + b);
141
142 for (String key : b.keySet()) {
143 bsn = key;
144 if (!Verifier.SYMBOLICNAME.matcher(bsn).matches())
145 throw new IllegalArgumentException(
146 "Bundle SymbolicName has wrong format: " + bsn);
147 }
148
149 String versionString = manifest.getMainAttributes().getValue(
150 Analyzer.BUNDLE_VERSION);
151 Version version;
152 if (versionString == null)
153 version = new Version();
154 else
155 version = new Version(versionString);
156
157 File dir = new File(root, bsn);
158 dir.mkdirs();
159 String fName = bsn + "-" + version.getMajor() + "."
160 + version.getMinor() + "." + version.getMicro() + ".jar";
161 File file = new File(dir, fName);
162
163 reporter.trace("Updating " + file.getAbsolutePath());
164 if (!file.exists() || file.lastModified() < jar.lastModified()) {
165 jar.write(file);
166 reporter.progress("Updated " + file.getAbsolutePath());
167 fireBundleAdded(jar, file);
168 } else {
169 reporter.progress("Did not update " + jar
170 + " because repo has a newer version");
171 reporter.trace("NOT Updating " + fName + " (repo is newer)");
172 }
173
174 File latest = new File(dir, bsn + "-latest.jar");
175 if (latest.exists() && latest.lastModified() < jar.lastModified()) {
176 jar.write(latest);
177 file = latest;
178 }
179
180 return file;
181 }
182
183 protected void fireBundleAdded(Jar jar, File file) {
184 if (registry == null)
185 return;
186 List<RepositoryListenerPlugin> listeners = registry.getPlugins(RepositoryListenerPlugin.class);
187 for (RepositoryListenerPlugin listener : listeners) {
188 try {
189 listener.bundleAdded(this, jar, file);
190 } catch (Exception e) {
191 if (reporter != null)
192 reporter.warning("Repository listener threw an unexpected exception: %s", e);
193 }
194 }
195 }
196
197 public void setLocation(String string) {
198 root = new File(string);
199 if (!root.isDirectory())
200 throw new IllegalArgumentException("Invalid repository directory");
201 }
202
203 public void setReporter(Reporter reporter) {
204 this.reporter = reporter;
205 }
206
207 public List<String> list(String regex) throws Exception {
208 init();
209 Instruction pattern = null;
210 if (regex != null)
211 pattern = Instruction.getPattern(regex);
212
213 List<String> result = new ArrayList<String>();
214 if (root == null) {
215 if (reporter != null) reporter.error("FileRepo root directory is not set.");
216 } else {
217 File[] list = root.listFiles();
218 if (list != null) {
219 for (File f : list) {
220 if (!f.isDirectory()) continue; // ignore non-directories
221 String fileName = f.getName();
222 if (fileName.charAt(0) == '.') continue; // ignore hidden files
223 if (pattern == null || pattern.matches(fileName))
224 result.add(fileName);
225 }
226 } else
227 if ( reporter != null)
228 reporter.error("FileRepo root directory (%s) does not exist", root);
229 }
230
231 return result;
232 }
233
234 public List<Version> versions(String bsn) throws Exception {
235 init();
236 File dir = new File(root, bsn);
237 if (dir.isDirectory()) {
238 String versions[] = dir.list();
239 List<Version> list = new ArrayList<Version>();
240 for (String v : versions) {
241 Matcher m = REPO_FILE.matcher(v);
242 if (m.matches()) {
243 String version = m.group(2);
244 if (version.equals("latest"))
245 version = "99";
246 list.add(new Version(version));
247 }
248 }
249 return list;
250 }
251 return null;
252 }
253
254 public String toString() {
255 return String
256 .format("%-40s r/w=%s", root.getAbsolutePath(), canWrite());
257 }
258
259 public File getRoot() {
260 return root;
261 }
262
263 public boolean refresh() {
264 if (dirty) {
265 dirty = false;
266 return true;
267 } else
268 return false;
269 }
270
271 public String getName() {
272 if (name == null) {
273 return toString();
274 }
275 return name;
276 }
277 public File get(String bsn, String version, Strategy strategy, Map<String,String> properties) throws Exception {
278 if ( version == null)
279 version = "0.0.0";
280
281 if ( strategy == Strategy.EXACT) {
282 VersionRange vr = new VersionRange(version);
283 if ( vr.isRange())
284 return null;
285
286 File file = IO.getFile(root, bsn + "/" + version +"/" + bsn + "-" + version + ".jar");
287 if ( file.isFile())
288 return file;
289 else
290 return null;
291
292 }
293 File[] files = get(bsn, version);
294 if ( files == null || files.length == 0)
295 return null;
296
297 if (files.length >= 0) {
298 switch (strategy) {
299 case LOWEST:
300 return files[0];
301 case HIGHEST:
302 return files[files.length - 1];
303 }
304 }
305 return null;
306 }
307
308 public void setRegistry(Registry registry) {
309 this.registry = registry;
310 }
311}