1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package org.xnap.commons.pkg;
21
22 import java.io.BufferedReader;
23 import java.io.BufferedWriter;
24 import java.io.File;
25 import java.io.FileInputStream;
26 import java.io.FileWriter;
27 import java.io.IOException;
28 import java.io.InputStream;
29 import java.io.InputStreamReader;
30 import java.net.URL;
31 import java.util.Hashtable;
32 import java.util.Iterator;
33 import java.util.LinkedList;
34 import java.util.List;
35 import java.util.Properties;
36 import java.util.SortedSet;
37 import java.util.StringTokenizer;
38 import java.util.TreeSet;
39 import java.util.zip.GZIPInputStream;
40
41 /***
42 *
43 */
44 public class PackageManager
45 {
46
47
48
49
50
51 /***
52 * A sorted list of PackageInfo objects.
53 */
54 private TreeSet packages = new TreeSet();
55 private Hashtable packageListByProvides = new Hashtable();
56
57
58
59 public PackageManager()
60 {
61 }
62
63
64
65 /***
66 * Adds a package. If info is not valid or a package with the same
67 * name and version already exists the package is not added.
68 */
69 public void add(PackageInfo info)
70 {
71 if (info.isValid()) {
72 if (packages.contains(info)) {
73 SortedSet tailSet = packages.tailSet(info);
74 PackageInfo old = (PackageInfo)tailSet.first();
75 if (old.isInstalled()) {
76 old.setAvailable(true);
77
78 return;
79 }
80 else {
81 remove(old);
82 info.setNew(old.isNew());
83 }
84 }
85 packages.add(info);
86 info.setAvailable(true);
87
88 if (info.getProvides() != null) {
89 StringTokenizer t
90 = new StringTokenizer(info.getProvides(), ",");
91 while (t.hasMoreTokens()) {
92 String name = t.nextToken().trim();
93 LinkedList list
94 = (LinkedList)packageListByProvides.get(name);
95 if (list == null) {
96 list = new LinkedList();
97 packageListByProvides.put(name, list);
98 }
99 list.add(info);
100 }
101 }
102 }
103 }
104
105 public PackageInfo[] getConflicts(PackageInfo info)
106 throws ParseException
107 {
108 LinkedList packageTokens = new LinkedList();
109 DefaultDependencyParser parser = new DefaultDependencyParser();
110 AbstractToken token = parser.parseConflicts(info);
111 if (token instanceof CommaToken) {
112 AbstractToken[] depends = ((CommaToken)token).depends;
113 for (int i = 0; i < depends.length; i++) {
114 if (depends[i] instanceof PackageToken) {
115 packageTokens.add(depends[i]);
116 }
117 }
118 }
119 else if (token instanceof PackageToken) {
120 packageTokens.add(token);
121 }
122
123 LinkedList infos = new LinkedList();
124 for (Iterator it = packageTokens.iterator(); it.hasNext();) {
125 addConflicts(infos, (PackageToken)it.next());
126 }
127 return (PackageInfo[])infos.toArray(new PackageInfo[0]);
128 }
129
130 private void addConflicts(List list, PackageToken token)
131 {
132
133 for (Iterator it = tailSet(token.name).iterator(); it.hasNext();) {
134 PackageInfo info = (PackageInfo)it.next();
135 if (info.getPackage().equals(token.name)) {
136 if (token.compareMode == null
137 || token.equalsVersion(info.compareToVersion
138 (token.version))) {
139
140 list.add(info);
141 }
142 }
143 else {
144 break;
145 }
146 }
147 }
148
149 /***
150 * Returns a list of urls.
151 *
152 * @return the empty string
153 */
154 public String getDefaultSources()
155 {
156 return "";
157 }
158
159 /***
160 *
161 * @exception ParseException thrown, if package file is invalid
162 * @exception UnsatisfiedDependenciesException thrown, if
163 * dependencies are not satisfied
164 */
165 public PackageInfo[] getDependencies(PackageInfo info)
166 throws ParseException, UnsatisfiedDependenciesException
167 {
168 DependencyGraph graph = new DependencyGraph(this);
169 graph.add(info);
170 graph.buildDependencies(new DefaultDependencyParser());
171
172 DefaultResolver r = new DefaultResolver(graph, true);
173 r.resolve();
174 return r.getRequired();
175 }
176
177 /***
178 * Marks all packages that are not installed as unavailable. Marks
179 * all packages as not new.
180 */
181 public void markAllUnavailable()
182 {
183 for (Iterator i = packages(); i.hasNext();) {
184 PackageInfo info = (PackageInfo)i.next();
185 info.setAvailable(info.isInstalled());
186 info.setNew(false);
187 }
188 }
189
190 /***
191 * Reads package information from a control file.
192 *
193 * @param file the control file
194 */
195 public void read(File file, Properties table) throws IOException
196 {
197 FileInputStream in = new FileInputStream(file);
198 try {
199 read(in, table);
200 }
201 finally {
202 in.close();
203 }
204 }
205
206 public void read(File file) throws IOException
207 {
208 read(file, null);
209 }
210
211 /***
212 * Reads package information from a url.
213 *
214 * @param location the package file url
215 * @param downloadUrl the base location of the package files
216 */
217 public void read(String location, Properties table) throws IOException
218 {
219 URL url = new URL(location);
220 InputStream in = url.openStream();
221 try {
222 if (location.endsWith(".gz")) {
223 in = new GZIPInputStream(url.openStream());
224 }
225 read(in, table);
226 }
227 finally {
228 in.close();
229 }
230 }
231
232 /***
233 * Reads package information from a stream.
234 *
235 * @param inStream the stream
236 * @param flags additional flags that are added to the {@link
237 * PackageInfo} record; if null, flags are ignored
238 */
239 public void read(InputStream inStream, Properties flags)
240 throws IOException
241 {
242 BufferedReader in
243 = new BufferedReader(new InputStreamReader(inStream));
244
245 Properties p;
246 while ((p = PackageInfoReader.readNext(in)) != null) {
247 PackageInfo info = new PackageInfo(p);
248 if (flags != null) {
249 info.putAll(flags);
250 }
251 add(info);
252 }
253 }
254
255 public void remove(PackageInfo info)
256 {
257 packages.remove(info);
258 if (info.getProvides() != null) {
259 StringTokenizer t
260 = new StringTokenizer(info.getProvides(), ",");
261 while (t.hasMoreTokens()) {
262 String name = t.nextToken().trim();
263 LinkedList list
264 = (LinkedList)packageListByProvides.get(name);
265 if (list != null) {
266 list.remove(info);
267 }
268 }
269 }
270 }
271
272 /***
273 * Removes all packages that are marked as unavailable.
274 */
275 public void removeUnavailable()
276 {
277 LinkedList toRemove = new LinkedList();
278 for (Iterator i = packages(); i.hasNext();) {
279 PackageInfo info = (PackageInfo)i.next();
280 if (!(info.isInstalled() || info.isAvailable())) {
281 toRemove.add(info);
282 }
283 }
284
285 for (Iterator i = toRemove.iterator(); i.hasNext();) {
286 remove((PackageInfo)i.next());
287 }
288 }
289
290 /***
291 * Returns an iterator over all {@link PackageInfo} objects.
292 */
293 public Iterator packages()
294 {
295 return packages.iterator();
296 }
297
298 /***
299 * Returns the number of packages.
300 */
301 public int getPackageCount()
302 {
303 return packages.size();
304 }
305
306 /***
307 * Returns a package by name.
308 */
309 public PackageInfo getPackage(String packageName)
310 {
311 SortedSet set = tailSet(packageName);
312 if (!set.isEmpty()) {
313 PackageInfo info = (PackageInfo)set.first();
314 if (info.getPackage().equals(packageName)) {
315 return info;
316 }
317 }
318 return null;
319 }
320
321 public SortedSet tailSet(String packageName)
322 {
323 return packages.tailSet(new PackageInfo(packageName));
324 }
325
326 /***
327 * Returns an array of packages that provide packageName.
328 */
329 public PackageInfo[] getProviders(String packageName)
330 {
331 LinkedList list = (LinkedList)packageListByProvides.get(packageName);
332 return (list != null)
333 ? (PackageInfo[])list.toArray(new PackageInfo[0])
334 : null;
335 }
336
337 public void write(File file, Properties flags) throws IOException
338 {
339 BufferedWriter out = new BufferedWriter(new FileWriter(file));
340 try {
341 for (Iterator i = packages.iterator(); i.hasNext();) {
342 PackageInfo info = (PackageInfo)i.next();
343 if (flags == null || info.containsProperties(flags)) {
344 PackageInfoWriter.write(out, info.getProperties());
345 }
346 }
347 }
348 finally {
349 try {
350 out.close();
351 }
352 catch (IOException e) {
353 }
354 }
355 }
356
357 }
358