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