/** * Adds a set of refs to the set of packed-refs. Only non-symbolic refs are added. If a ref with * the given name already existed in packed-refs it is updated with the new value. Each loose ref * which was added to the packed-ref file is deleted. If a given ref can't be locked it will not * be added to the pack file. * * @param refs the refs to be added. Must be fully qualified. * @throws IOException */ public void pack(List<String> refs) throws IOException { if (refs.size() == 0) return; FS fs = parent.getFS(); // Lock the packed refs file and read the content LockFile lck = new LockFile(packedRefsFile); if (!lck.lock()) throw new IOException(MessageFormat.format(JGitText.get().cannotLock, packedRefsFile)); try { final PackedRefList packed = getPackedRefs(); RefList<Ref> cur = readPackedRefs(); // Iterate over all refs to be packed for (String refName : refs) { Ref ref = readRef(refName, cur); if (ref.isSymbolic()) continue; // can't pack symbolic refs // Add/Update it to packed-refs int idx = cur.find(refName); if (idx >= 0) cur = cur.set(idx, peeledPackedRef(ref)); else cur = cur.add(idx, peeledPackedRef(ref)); } // The new content for packed-refs is collected. Persist it. commitPackedRefs(lck, cur, packed); // Now delete the loose refs which are now packed for (String refName : refs) { // Lock the loose ref File refFile = fileFor(refName); if (!fs.exists(refFile)) continue; LockFile rLck = new LockFile(refFile); if (!rLck.lock()) continue; try { LooseRef currentLooseRef = scanRef(null, refName); if (currentLooseRef == null || currentLooseRef.isSymbolic()) continue; Ref packedRef = cur.get(refName); ObjectId clr_oid = currentLooseRef.getObjectId(); if (clr_oid != null && clr_oid.equals(packedRef.getObjectId())) { RefList<LooseRef> curLoose, newLoose; do { curLoose = looseRefs.get(); int idx = curLoose.find(refName); if (idx < 0) break; newLoose = curLoose.remove(idx); } while (!looseRefs.compareAndSet(curLoose, newLoose)); int levels = levelsIn(refName) - 2; delete(refFile, levels, rLck); } } finally { rLck.unlock(); } } // Don't fire refsChanged. The refs have not change, only their // storage. } finally { lck.unlock(); } }
private void scanOne(String name) { LooseRef cur; if (curIdx < curLoose.size()) { do { cur = curLoose.get(curIdx); int cmp = RefComparator.compareTo(cur, name); if (cmp < 0) { // Reference is not loose anymore, its been deleted. // Skip the name in the new result list. if (newLoose == null) newLoose = curLoose.copy(curIdx); curIdx++; cur = null; continue; } if (cmp > 0) // Newly discovered loose reference. cur = null; break; } while (curIdx < curLoose.size()); } else cur = null; // Newly discovered loose reference. LooseRef n; try { n = scanRef(cur, name); } catch (IOException notValid) { n = null; } if (n != null) { if (cur != n && newLoose == null) newLoose = curLoose.copy(curIdx); if (newLoose != null) newLoose.add(n); if (n.isSymbolic()) symbolic.add(n); } else if (cur != null) { // Tragically, this file is no longer a loose reference. // Kill our cached entry of it. if (newLoose == null) newLoose = curLoose.copy(curIdx); } if (cur != null) curIdx++; }
LooseRef scanRef(LooseRef ref, String name) throws IOException { final File path = fileFor(name); FileSnapshot currentSnapshot = null; if (ref != null) { currentSnapshot = ref.getSnapShot(); if (!currentSnapshot.isModified(path)) return ref; name = ref.getName(); } final int limit = 4096; final byte[] buf; FileSnapshot otherSnapshot = FileSnapshot.save(path); try { buf = IO.readSome(path, limit); } catch (FileNotFoundException noFile) { if (path.exists() && path.isFile()) { throw noFile; } return null; // doesn't exist or no file; not a reference. } int n = buf.length; if (n == 0) return null; // empty file; not a reference. if (isSymRef(buf, n)) { if (n == limit) return null; // possibly truncated ref // trim trailing whitespace while (0 < n && Character.isWhitespace(buf[n - 1])) n--; if (n < 6) { String content = RawParseUtils.decode(buf, 0, n); throw new IOException(MessageFormat.format(JGitText.get().notARef, name, content)); } final String target = RawParseUtils.decode(buf, 5, n); if (ref != null && ref.isSymbolic() && ref.getTarget().getName().equals(target)) { assert (currentSnapshot != null); currentSnapshot.setClean(otherSnapshot); return ref; } return newSymbolicRef(otherSnapshot, name, target); } if (n < OBJECT_ID_STRING_LENGTH) return null; // impossibly short object identifier; not a reference. final ObjectId id; try { id = ObjectId.fromString(buf, 0); if (ref != null && !ref.isSymbolic() && id.equals(ref.getTarget().getObjectId())) { assert (currentSnapshot != null); currentSnapshot.setClean(otherSnapshot); return ref; } } catch (IllegalArgumentException notRef) { while (0 < n && Character.isWhitespace(buf[n - 1])) n--; String content = RawParseUtils.decode(buf, 0, n); IOException ioException = new IOException(MessageFormat.format(JGitText.get().notARef, name, content)); ioException.initCause(notRef); throw ioException; } return new LooseUnpeeled(otherSnapshot, name, id); }