1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45 package org.eclipse.jgit.transport;
46
47 import java.io.File;
48 import java.io.FileNotFoundException;
49 import java.io.FileOutputStream;
50 import java.io.IOException;
51 import java.text.MessageFormat;
52 import java.util.ArrayList;
53 import java.util.Collection;
54 import java.util.HashMap;
55 import java.util.HashSet;
56 import java.util.Iterator;
57 import java.util.LinkedList;
58 import java.util.List;
59 import java.util.Set;
60
61 import org.eclipse.jgit.errors.CompoundException;
62 import org.eclipse.jgit.errors.CorruptObjectException;
63 import org.eclipse.jgit.errors.MissingObjectException;
64 import org.eclipse.jgit.errors.TransportException;
65 import org.eclipse.jgit.internal.JGitText;
66 import org.eclipse.jgit.internal.storage.file.ObjectDirectory;
67 import org.eclipse.jgit.internal.storage.file.PackIndex;
68 import org.eclipse.jgit.internal.storage.file.PackLock;
69 import org.eclipse.jgit.internal.storage.file.UnpackedObject;
70 import org.eclipse.jgit.lib.AnyObjectId;
71 import org.eclipse.jgit.lib.Constants;
72 import org.eclipse.jgit.lib.FileMode;
73 import org.eclipse.jgit.lib.MutableObjectId;
74 import org.eclipse.jgit.lib.ObjectChecker;
75 import org.eclipse.jgit.lib.ObjectId;
76 import org.eclipse.jgit.lib.ObjectInserter;
77 import org.eclipse.jgit.lib.ObjectLoader;
78 import org.eclipse.jgit.lib.ObjectReader;
79 import org.eclipse.jgit.lib.ProgressMonitor;
80 import org.eclipse.jgit.lib.Ref;
81 import org.eclipse.jgit.lib.Repository;
82 import org.eclipse.jgit.revwalk.DateRevQueue;
83 import org.eclipse.jgit.revwalk.RevCommit;
84 import org.eclipse.jgit.revwalk.RevFlag;
85 import org.eclipse.jgit.revwalk.RevObject;
86 import org.eclipse.jgit.revwalk.RevTag;
87 import org.eclipse.jgit.revwalk.RevTree;
88 import org.eclipse.jgit.revwalk.RevWalk;
89 import org.eclipse.jgit.treewalk.TreeWalk;
90 import org.eclipse.jgit.util.FileUtils;
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113 class WalkFetchConnection extends BaseFetchConnection {
114
115 final Repository local;
116
117
118 final ObjectChecker objCheck;
119
120
121
122
123
124
125
126
127 private final List<WalkRemoteObjectDatabase> remotes;
128
129
130 private int lastRemoteIdx;
131
132 private final RevWalk revWalk;
133
134 private final TreeWalk treeWalk;
135
136
137 private final RevFlag COMPLETE;
138
139
140 private final RevFlag IN_WORK_QUEUE;
141
142
143 private final RevFlag LOCALLY_SEEN;
144
145
146 private final DateRevQueue localCommitQueue;
147
148
149 private LinkedList<ObjectId> workQueue;
150
151
152 private final LinkedList<WalkRemoteObjectDatabase> noPacksYet;
153
154
155 private final LinkedList<WalkRemoteObjectDatabase> noAlternatesYet;
156
157
158 private final LinkedList<RemotePack> unfetchedPacks;
159
160
161
162
163
164
165
166
167 private final Set<String> packsConsidered;
168
169 private final MutableObjectIdml#MutableObjectId">MutableObjectId idBuffer = new MutableObjectId();
170
171
172
173
174
175
176
177
178 private final HashMap<ObjectId, List<Throwable>> fetchErrors;
179
180 String lockMessage;
181
182 final List<PackLock> packLocks;
183
184
185 final ObjectInserter inserter;
186
187
188 private final ObjectReader reader;
189
190 WalkFetchConnection(WalkTransport t, WalkRemoteObjectDatabase w) {
191 Transport wt = (Transport)t;
192 local = wt.local;
193 objCheck = wt.getObjectChecker();
194 inserter = local.newObjectInserter();
195 reader = inserter.newReader();
196
197 remotes = new ArrayList<>();
198 remotes.add(w);
199
200 unfetchedPacks = new LinkedList<>();
201 packsConsidered = new HashSet<>();
202
203 noPacksYet = new LinkedList<>();
204 noPacksYet.add(w);
205
206 noAlternatesYet = new LinkedList<>();
207 noAlternatesYet.add(w);
208
209 fetchErrors = new HashMap<>();
210 packLocks = new ArrayList<>(4);
211
212 revWalk = new RevWalk(reader);
213 revWalk.setRetainBody(false);
214 treeWalk = new TreeWalk(reader);
215 COMPLETE = revWalk.newFlag("COMPLETE");
216 IN_WORK_QUEUE = revWalk.newFlag("IN_WORK_QUEUE");
217 LOCALLY_SEEN = revWalk.newFlag("LOCALLY_SEEN");
218
219 localCommitQueue = new DateRevQueue();
220 workQueue = new LinkedList<>();
221 }
222
223
224 @Override
225 public boolean didFetchTestConnectivity() {
226 return true;
227 }
228
229
230 @Override
231 protected void doFetch(final ProgressMonitor monitor,
232 final Collection<Ref> want, final Set<ObjectId> have)
233 throws TransportException {
234 markLocalRefsComplete(have);
235 queueWants(want);
236
237 while (!monitor.isCancelled() && !workQueue.isEmpty()) {
238 final ObjectId id = workQueue.removeFirst();
239 if (!(id instanceof RevObject../../../../org/eclipse/jgit/revwalk/RevObject.html#RevObject">RevObject) || !((RevObject) id).has(COMPLETE))
240 downloadObject(monitor, id);
241 process(id);
242 }
243
244 try {
245 inserter.flush();
246 } catch (IOException e) {
247 throw new TransportException(e.getMessage(), e);
248 }
249 }
250
251
252 @Override
253 public Collection<PackLock> getPackLocks() {
254 return packLocks;
255 }
256
257
258 @Override
259 public void setPackLockMessage(String message) {
260 lockMessage = message;
261 }
262
263
264 @Override
265 public void close() {
266 inserter.close();
267 reader.close();
268 for (RemotePack p : unfetchedPacks) {
269 if (p.tmpIdx != null)
270 p.tmpIdx.delete();
271 }
272 for (WalkRemoteObjectDatabase r : remotes)
273 r.close();
274 }
275
276 private void queueWants(Collection<Ref> want)
277 throws TransportException {
278 final HashSet<ObjectId> inWorkQueue = new HashSet<>();
279 for (Ref r : want) {
280 final ObjectId id = r.getObjectId();
281 if (id == null) {
282 throw new NullPointerException(MessageFormat.format(
283 JGitText.get().transportProvidedRefWithNoObjectId, r.getName()));
284 }
285 try {
286 final RevObject obj = revWalk.parseAny(id);
287 if (obj.has(COMPLETE))
288 continue;
289 if (inWorkQueue.add(id)) {
290 obj.add(IN_WORK_QUEUE);
291 workQueue.add(obj);
292 }
293 } catch (MissingObjectException e) {
294 if (inWorkQueue.add(id))
295 workQueue.add(id);
296 } catch (IOException e) {
297 throw new TransportException(MessageFormat.format(JGitText.get().cannotRead, id.name()), e);
298 }
299 }
300 }
301
302 private void process(ObjectId id) throws TransportException {
303 final RevObject obj;
304 try {
305 if (id instanceof RevObject) {
306 obj = (RevObject) id;
307 if (obj.has(COMPLETE))
308 return;
309 revWalk.parseHeaders(obj);
310 } else {
311 obj = revWalk.parseAny(id);
312 if (obj.has(COMPLETE))
313 return;
314 }
315 } catch (IOException e) {
316 throw new TransportException(MessageFormat.format(JGitText.get().cannotRead, id.name()), e);
317 }
318
319 switch (obj.getType()) {
320 case Constants.OBJ_BLOB:
321 processBlob(obj);
322 break;
323 case Constants.OBJ_TREE:
324 processTree(obj);
325 break;
326 case Constants.OBJ_COMMIT:
327 processCommit(obj);
328 break;
329 case Constants.OBJ_TAG:
330 processTag(obj);
331 break;
332 default:
333 throw new TransportException(MessageFormat.format(JGitText.get().unknownObjectType, id.name()));
334 }
335
336
337
338
339 fetchErrors.remove(id);
340 }
341
342 private void processBlob(RevObject obj) throws TransportException {
343 try {
344 if (reader.has(obj, Constants.OBJ_BLOB))
345 obj.add(COMPLETE);
346 else
347 throw new TransportException(MessageFormat.format(JGitText
348 .get().cannotReadBlob, obj.name()),
349 new MissingObjectException(obj, Constants.TYPE_BLOB));
350 } catch (IOException error) {
351 throw new TransportException(MessageFormat.format(
352 JGitText.get().cannotReadBlob, obj.name()), error);
353 }
354 }
355
356 private void processTree(RevObject obj) throws TransportException {
357 try {
358 treeWalk.reset(obj);
359 while (treeWalk.next()) {
360 final FileMode mode = treeWalk.getFileMode(0);
361 final int sType = mode.getObjectType();
362
363 switch (sType) {
364 case Constants.OBJ_BLOB:
365 case Constants.OBJ_TREE:
366 treeWalk.getObjectId(idBuffer, 0);
367 needs(revWalk.lookupAny(idBuffer, sType));
368 continue;
369
370 default:
371 if (FileMode.GITLINK.equals(mode))
372 continue;
373 treeWalk.getObjectId(idBuffer, 0);
374 throw new CorruptObjectException(MessageFormat.format(JGitText.get().invalidModeFor
375 , mode, idBuffer.name(), treeWalk.getPathString(), obj.getId().name()));
376 }
377 }
378 } catch (IOException ioe) {
379 throw new TransportException(MessageFormat.format(JGitText.get().cannotReadTree, obj.name()), ioe);
380 }
381 obj.add(COMPLETE);
382 }
383
384 private void processCommit(RevObject obj) throws TransportException {
385 final RevCommit../../../org/eclipse/jgit/revwalk/RevCommit.html#RevCommit">RevCommit commit = (RevCommit) obj;
386 markLocalCommitsComplete(commit.getCommitTime());
387 needs(commit.getTree());
388 for (RevCommit p : commit.getParents())
389 needs(p);
390 obj.add(COMPLETE);
391 }
392
393 private void processTag(RevObject obj) {
394 final RevTagf="../../../../org/eclipse/jgit/revwalk/RevTag.html#RevTag">RevTag tag = (RevTag) obj;
395 needs(tag.getObject());
396 obj.add(COMPLETE);
397 }
398
399 private void needs(RevObject obj) {
400 if (obj.has(COMPLETE))
401 return;
402 if (!obj.has(IN_WORK_QUEUE)) {
403 obj.add(IN_WORK_QUEUE);
404 workQueue.add(obj);
405 }
406 }
407
408 private void downloadObject(ProgressMonitor pm, AnyObjectId id)
409 throws TransportException {
410 if (alreadyHave(id))
411 return;
412
413 for (;;) {
414
415
416
417
418 if (downloadPackedObject(pm, id))
419 return;
420
421
422
423
424 final String idStr = id.name();
425 final String subdir = idStr.substring(0, 2);
426 final String file = idStr.substring(2);
427 final String looseName = subdir + "/" + file;
428
429 for (int i = lastRemoteIdx; i < remotes.size(); i++) {
430 if (downloadLooseObject(id, looseName, remotes.get(i))) {
431 lastRemoteIdx = i;
432 return;
433 }
434 }
435 for (int i = 0; i < lastRemoteIdx; i++) {
436 if (downloadLooseObject(id, looseName, remotes.get(i))) {
437 lastRemoteIdx = i;
438 return;
439 }
440 }
441
442
443
444 while (!noPacksYet.isEmpty()) {
445 final WalkRemoteObjectDatabase wrr = noPacksYet.removeFirst();
446 final Collection<String> packNameList;
447 try {
448 pm.beginTask(JGitText.get().listingPacks,
449 ProgressMonitor.UNKNOWN);
450 packNameList = wrr.getPackNames();
451 } catch (IOException e) {
452
453
454 recordError(id, e);
455 continue;
456 } finally {
457 pm.endTask();
458 }
459
460 if (packNameList == null || packNameList.isEmpty())
461 continue;
462 for (String packName : packNameList) {
463 if (packsConsidered.add(packName))
464 unfetchedPacks.add(new RemotePack(wrr, packName));
465 }
466 if (downloadPackedObject(pm, id))
467 return;
468 }
469
470
471
472 Collection<WalkRemoteObjectDatabase> al = expandOneAlternate(id, pm);
473 if (al != null && !al.isEmpty()) {
474 for (WalkRemoteObjectDatabase alt : al) {
475 remotes.add(alt);
476 noPacksYet.add(alt);
477 noAlternatesYet.add(alt);
478 }
479 continue;
480 }
481
482
483
484 List<Throwable> failures = fetchErrors.get(id);
485 final TransportException te;
486
487 te = new TransportException(MessageFormat.format(JGitText.get().cannotGet, id.name()));
488 if (failures != null && !failures.isEmpty()) {
489 if (failures.size() == 1)
490 te.initCause(failures.get(0));
491 else
492 te.initCause(new CompoundException(failures));
493 }
494 throw te;
495 }
496 }
497
498 private boolean alreadyHave(AnyObjectId id) throws TransportException {
499 try {
500 return reader.has(id);
501 } catch (IOException error) {
502 throw new TransportException(MessageFormat.format(
503 JGitText.get().cannotReadObject, id.name()), error);
504 }
505 }
506
507 private boolean downloadPackedObject(final ProgressMonitor monitor,
508 final AnyObjectId id) throws TransportException {
509
510
511
512 final Iterator<RemotePack> packItr = unfetchedPacks.iterator();
513 while (packItr.hasNext() && !monitor.isCancelled()) {
514 final RemotePack pack = packItr.next();
515 try {
516 pack.openIndex(monitor);
517 } catch (IOException err) {
518
519
520
521
522
523 recordError(id, err);
524 packItr.remove();
525 continue;
526 }
527
528 if (monitor.isCancelled()) {
529
530
531
532
533 return false;
534 }
535
536 if (!pack.index.hasObject(id)) {
537
538
539 continue;
540 }
541
542
543
544
545
546 try {
547 pack.downloadPack(monitor);
548 } catch (IOException err) {
549
550
551
552
553
554 recordError(id, err);
555 continue;
556 } finally {
557
558
559
560
561
562
563 try {
564 if (pack.tmpIdx != null)
565 FileUtils.delete(pack.tmpIdx);
566 } catch (IOException e) {
567 throw new TransportException(e.getMessage(), e);
568 }
569 packItr.remove();
570 }
571
572 if (!alreadyHave(id)) {
573
574
575
576
577 recordError(id, new FileNotFoundException(MessageFormat.format(
578 JGitText.get().objectNotFoundIn, id.name(), pack.packName)));
579 continue;
580 }
581
582
583
584 final Iterator<ObjectId> pending = swapFetchQueue();
585 while (pending.hasNext()) {
586 final ObjectId p = pending.next();
587 if (pack.index.hasObject(p)) {
588 pending.remove();
589 process(p);
590 } else {
591 workQueue.add(p);
592 }
593 }
594 return true;
595
596 }
597 return false;
598 }
599
600 private Iterator<ObjectId> swapFetchQueue() {
601 final Iterator<ObjectId> r = workQueue.iterator();
602 workQueue = new LinkedList<>();
603 return r;
604 }
605
606 private boolean downloadLooseObject(final AnyObjectId id,
607 final String looseName, final WalkRemoteObjectDatabase remote)
608 throws TransportException {
609 try {
610 final byte[] compressed = remote.open(looseName).toArray();
611 verifyAndInsertLooseObject(id, compressed);
612 return true;
613 } catch (FileNotFoundException e) {
614
615
616
617 recordError(id, e);
618 return false;
619 } catch (IOException e) {
620 throw new TransportException(MessageFormat.format(JGitText.get().cannotDownload, id.name()), e);
621 }
622 }
623
624 private void verifyAndInsertLooseObject(final AnyObjectId id,
625 final byte[] compressed) throws IOException {
626 final ObjectLoader uol;
627 try {
628 uol = UnpackedObject.parse(compressed, id);
629 } catch (CorruptObjectException parsingError) {
630
631
632
633
634
635
636
637
638
639
640
641 final FileNotFoundException e;
642 e = new FileNotFoundException(id.name());
643 e.initCause(parsingError);
644 throw e;
645 }
646
647 final int type = uol.getType();
648 final byte[] raw = uol.getCachedBytes();
649 if (objCheck != null) {
650 try {
651 objCheck.check(id, type, raw);
652 } catch (CorruptObjectException e) {
653 throw new TransportException(MessageFormat.format(
654 JGitText.get().transportExceptionInvalid,
655 Constants.typeString(type), id.name(), e.getMessage()));
656 }
657 }
658
659 ObjectId act = inserter.insert(type, raw);
660 if (!AnyObjectId.equals(id, act)) {
661 throw new TransportException(MessageFormat.format(
662 JGitText.get().incorrectHashFor, id.name(), act.name(),
663 Constants.typeString(type),
664 Integer.valueOf(compressed.length)));
665 }
666 }
667
668 private Collection<WalkRemoteObjectDatabase> expandOneAlternate(
669 final AnyObjectId id, final ProgressMonitor pm) {
670 while (!noAlternatesYet.isEmpty()) {
671 final WalkRemoteObjectDatabase wrr = noAlternatesYet.removeFirst();
672 try {
673 pm.beginTask(JGitText.get().listingAlternates, ProgressMonitor.UNKNOWN);
674 Collection<WalkRemoteObjectDatabase> altList = wrr
675 .getAlternates();
676 if (altList != null && !altList.isEmpty())
677 return altList;
678 } catch (IOException e) {
679
680
681 recordError(id, e);
682 } finally {
683 pm.endTask();
684 }
685 }
686 return null;
687 }
688
689 private void markLocalRefsComplete(Set<ObjectId> have) throws TransportException {
690 List<Ref> refs;
691 try {
692 refs = local.getRefDatabase().getRefs();
693 } catch (IOException e) {
694 throw new TransportException(e.getMessage(), e);
695 }
696 for (Ref r : refs) {
697 try {
698 markLocalObjComplete(revWalk.parseAny(r.getObjectId()));
699 } catch (IOException readError) {
700 throw new TransportException(MessageFormat.format(JGitText.get().localRefIsMissingObjects, r.getName()), readError);
701 }
702 }
703 for (ObjectId id : have) {
704 try {
705 markLocalObjComplete(revWalk.parseAny(id));
706 } catch (IOException readError) {
707 throw new TransportException(MessageFormat.format(JGitText.get().transportExceptionMissingAssumed, id.name()), readError);
708 }
709 }
710 }
711
712 private void markLocalObjComplete(RevObject obj) throws IOException {
713 while (obj.getType() == Constants.OBJ_TAG) {
714 obj.add(COMPLETE);
715 obj = ((RevTag) obj).getObject();
716 revWalk.parseHeaders(obj);
717 }
718
719 switch (obj.getType()) {
720 case Constants.OBJ_BLOB:
721 obj.add(COMPLETE);
722 break;
723 case Constants.OBJ_COMMIT:
724 pushLocalCommit((RevCommit) obj);
725 break;
726 case Constants.OBJ_TREE:
727 markTreeComplete((RevTree) obj);
728 break;
729 }
730 }
731
732 private void markLocalCommitsComplete(int until)
733 throws TransportException {
734 try {
735 for (;;) {
736 final RevCommit c = localCommitQueue.peek();
737 if (c == null || c.getCommitTime() < until)
738 return;
739 localCommitQueue.next();
740
741 markTreeComplete(c.getTree());
742 for (RevCommit p : c.getParents())
743 pushLocalCommit(p);
744 }
745 } catch (IOException err) {
746 throw new TransportException(JGitText.get().localObjectsIncomplete, err);
747 }
748 }
749
750 private void pushLocalCommit(RevCommit p)
751 throws MissingObjectException, IOException {
752 if (p.has(LOCALLY_SEEN))
753 return;
754 revWalk.parseHeaders(p);
755 p.add(LOCALLY_SEEN);
756 p.add(COMPLETE);
757 p.carry(COMPLETE);
758 localCommitQueue.add(p);
759 }
760
761 private void markTreeComplete(RevTree tree) throws IOException {
762 if (tree.has(COMPLETE))
763 return;
764 tree.add(COMPLETE);
765 treeWalk.reset(tree);
766 while (treeWalk.next()) {
767 final FileMode mode = treeWalk.getFileMode(0);
768 final int sType = mode.getObjectType();
769
770 switch (sType) {
771 case Constants.OBJ_BLOB:
772 treeWalk.getObjectId(idBuffer, 0);
773 revWalk.lookupAny(idBuffer, sType).add(COMPLETE);
774 continue;
775
776 case Constants.OBJ_TREE: {
777 treeWalk.getObjectId(idBuffer, 0);
778 final RevObject o = revWalk.lookupAny(idBuffer, sType);
779 if (!o.has(COMPLETE)) {
780 o.add(COMPLETE);
781 treeWalk.enterSubtree();
782 }
783 continue;
784 }
785 default:
786 if (FileMode.GITLINK.equals(mode))
787 continue;
788 treeWalk.getObjectId(idBuffer, 0);
789 throw new CorruptObjectException(MessageFormat.format(JGitText.get().corruptObjectInvalidMode3
790 , mode, idBuffer.name(), treeWalk.getPathString(), tree.name()));
791 }
792 }
793 }
794
795 private void recordError(AnyObjectId id, Throwable what) {
796 final ObjectId objId = id.copy();
797 List<Throwable> errors = fetchErrors.get(objId);
798 if (errors == null) {
799 errors = new ArrayList<>(2);
800 fetchErrors.put(objId, errors);
801 }
802 errors.add(what);
803 }
804
805 private class RemotePack {
806 final WalkRemoteObjectDatabase connection;
807
808 final String packName;
809
810 final String idxName;
811
812 File tmpIdx;
813
814 PackIndex index;
815
816 RemotePack(WalkRemoteObjectDatabase c, String pn) {
817 connection = c;
818 packName = pn;
819 idxName = packName.substring(0, packName.length() - 5) + ".idx";
820
821 String tn = idxName;
822 if (tn.startsWith("pack-"))
823 tn = tn.substring(5);
824 if (tn.endsWith(".idx"))
825 tn = tn.substring(0, tn.length() - 4);
826
827 if (local.getObjectDatabase() instanceof ObjectDirectory) {
828 tmpIdx = new File(((ObjectDirectory) local.getObjectDatabase())
829 .getDirectory(),
830 "walk-" + tn + ".walkidx");
831 }
832 }
833
834 void openIndex(ProgressMonitor pm) throws IOException {
835 if (index != null)
836 return;
837 if (tmpIdx == null)
838 tmpIdx = File.createTempFile("jgit-walk-", ".idx");
839 else if (tmpIdx.isFile()) {
840 try {
841 index = PackIndex.open(tmpIdx);
842 return;
843 } catch (FileNotFoundException err) {
844
845 }
846 }
847
848 final WalkRemoteObjectDatabase.FileStream s;
849 s = connection.open("pack/" + idxName);
850 pm.beginTask("Get " + idxName.substring(0, 12) + "..idx",
851 s.length < 0 ? ProgressMonitor.UNKNOWN
852 : (int) (s.length / 1024));
853 try (FileOutputStream fos = new FileOutputStream(tmpIdx)) {
854 final byte[] buf = new byte[2048];
855 int cnt;
856 while (!pm.isCancelled() && (cnt = s.in.read(buf)) >= 0) {
857 fos.write(buf, 0, cnt);
858 pm.update(cnt / 1024);
859 }
860 } catch (IOException err) {
861 FileUtils.delete(tmpIdx);
862 throw err;
863 } finally {
864 s.in.close();
865 }
866 pm.endTask();
867
868 if (pm.isCancelled()) {
869 FileUtils.delete(tmpIdx);
870 return;
871 }
872
873 try {
874 index = PackIndex.open(tmpIdx);
875 } catch (IOException e) {
876 FileUtils.delete(tmpIdx);
877 throw e;
878 }
879 }
880
881 void downloadPack(ProgressMonitor monitor) throws IOException {
882 String name = "pack/" + packName;
883 WalkRemoteObjectDatabase.FileStream s = connection.open(name);
884 try {
885 PackParser parser = inserter.newPackParser(s.in);
886 parser.setAllowThin(false);
887 parser.setObjectChecker(objCheck);
888 parser.setLockMessage(lockMessage);
889 PackLock lock = parser.parse(monitor);
890 if (lock != null)
891 packLocks.add(lock);
892 } finally {
893 s.in.close();
894 }
895 }
896 }
897 }