123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883 |
- /*
- * Copyright (C) 2008, Robin Rosenberg <robin.rosenberg@dewire.com>
- * Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org>
- * and other copyright owners as documented in the project's IP log.
- *
- * This program and the accompanying materials are made available
- * under the terms of the Eclipse Distribution License v1.0 which
- * accompanies this distribution, is reproduced below, and is
- * available at http://www.eclipse.org/org/documents/edl-v10.php
- *
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or
- * without modification, are permitted provided that the following
- * conditions are met:
- *
- * - Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * - Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following
- * disclaimer in the documentation and/or other materials provided
- * with the distribution.
- *
- * - Neither the name of the Eclipse Foundation, Inc. nor the
- * names of its contributors may be used to endorse or promote
- * products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
- * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
- * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
- * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
- * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
- package org.eclipse.jgit.transport;
-
- import static org.eclipse.jgit.lib.RefDatabase.ALL;
-
- import java.io.File;
- import java.io.FileNotFoundException;
- import java.io.FileOutputStream;
- import java.io.IOException;
- import java.text.MessageFormat;
- import java.util.ArrayList;
- import java.util.Collection;
- import java.util.HashMap;
- import java.util.HashSet;
- import java.util.Iterator;
- import java.util.LinkedList;
- import java.util.List;
- import java.util.Map;
- import java.util.Set;
-
- import org.eclipse.jgit.errors.CompoundException;
- import org.eclipse.jgit.errors.CorruptObjectException;
- import org.eclipse.jgit.errors.MissingObjectException;
- import org.eclipse.jgit.errors.TransportException;
- import org.eclipse.jgit.internal.JGitText;
- import org.eclipse.jgit.internal.storage.file.ObjectDirectory;
- import org.eclipse.jgit.internal.storage.file.PackIndex;
- import org.eclipse.jgit.internal.storage.file.PackLock;
- import org.eclipse.jgit.internal.storage.file.UnpackedObject;
- import org.eclipse.jgit.lib.AnyObjectId;
- import org.eclipse.jgit.lib.Constants;
- import org.eclipse.jgit.lib.FileMode;
- import org.eclipse.jgit.lib.MutableObjectId;
- import org.eclipse.jgit.lib.ObjectChecker;
- import org.eclipse.jgit.lib.ObjectId;
- import org.eclipse.jgit.lib.ObjectInserter;
- import org.eclipse.jgit.lib.ObjectLoader;
- import org.eclipse.jgit.lib.ObjectReader;
- import org.eclipse.jgit.lib.ProgressMonitor;
- import org.eclipse.jgit.lib.Ref;
- import org.eclipse.jgit.lib.Repository;
- import org.eclipse.jgit.revwalk.DateRevQueue;
- import org.eclipse.jgit.revwalk.RevCommit;
- import org.eclipse.jgit.revwalk.RevFlag;
- import org.eclipse.jgit.revwalk.RevObject;
- import org.eclipse.jgit.revwalk.RevTag;
- import org.eclipse.jgit.revwalk.RevTree;
- import org.eclipse.jgit.revwalk.RevWalk;
- import org.eclipse.jgit.treewalk.TreeWalk;
- import org.eclipse.jgit.util.FileUtils;
-
- /**
- * Generic fetch support for dumb transport protocols.
- * <p>
- * Since there are no Git-specific smarts on the remote side of the connection
- * the client side must determine which objects it needs to copy in order to
- * completely fetch the requested refs and their history. The generic walk
- * support in this class parses each individual object (once it has been copied
- * to the local repository) and examines the list of objects that must also be
- * copied to create a complete history. Objects which are already available
- * locally are retained (and not copied), saving bandwidth for incremental
- * fetches. Pack files are copied from the remote repository only as a last
- * resort, as the entire pack must be copied locally in order to access any
- * single object.
- * <p>
- * This fetch connection does not actually perform the object data transfer.
- * Instead it delegates the transfer to a {@link WalkRemoteObjectDatabase},
- * which knows how to read individual files from the remote repository and
- * supply the data as a standard Java InputStream.
- *
- * @see WalkRemoteObjectDatabase
- */
- class WalkFetchConnection extends BaseFetchConnection {
- /** The repository this transport fetches into, or pushes out of. */
- private final Repository local;
-
- /** If not null the validator for received objects. */
- private final ObjectChecker objCheck;
-
- /**
- * List of all remote repositories we may need to get objects out of.
- * <p>
- * The first repository in the list is the one we were asked to fetch from;
- * the remaining repositories point to the alternate locations we can fetch
- * objects through.
- */
- private final List<WalkRemoteObjectDatabase> remotes;
-
- /** Most recently used item in {@link #remotes}. */
- private int lastRemoteIdx;
-
- private final RevWalk revWalk;
-
- private final TreeWalk treeWalk;
-
- /** Objects whose direct dependents we know we have (or will have). */
- private final RevFlag COMPLETE;
-
- /** Objects that have already entered {@link #workQueue}. */
- private final RevFlag IN_WORK_QUEUE;
-
- /** Commits that have already entered {@link #localCommitQueue}. */
- private final RevFlag LOCALLY_SEEN;
-
- /** Commits already reachable from all local refs. */
- private final DateRevQueue localCommitQueue;
-
- /** Objects we need to copy from the remote repository. */
- private LinkedList<ObjectId> workQueue;
-
- /** Databases we have not yet obtained the list of packs from. */
- private final LinkedList<WalkRemoteObjectDatabase> noPacksYet;
-
- /** Databases we have not yet obtained the alternates from. */
- private final LinkedList<WalkRemoteObjectDatabase> noAlternatesYet;
-
- /** Packs we have discovered, but have not yet fetched locally. */
- private final LinkedList<RemotePack> unfetchedPacks;
-
- /**
- * Packs whose indexes we have looked at in {@link #unfetchedPacks}.
- * <p>
- * We try to avoid getting duplicate copies of the same pack through
- * multiple alternates by only looking at packs whose names are not yet in
- * this collection.
- */
- private final Set<String> packsConsidered;
-
- private final MutableObjectId idBuffer = new MutableObjectId();
-
- /**
- * Errors received while trying to obtain an object.
- * <p>
- * If the fetch winds up failing because we cannot locate a specific object
- * then we need to report all errors related to that object back to the
- * caller as there may be cascading failures.
- */
- private final HashMap<ObjectId, List<Throwable>> fetchErrors;
-
- private String lockMessage;
-
- private final List<PackLock> packLocks;
-
- /** Inserter to write objects onto {@link #local}. */
- private final ObjectInserter inserter;
-
- /** Inserter to read objects from {@link #local}. */
- private final ObjectReader reader;
-
- WalkFetchConnection(final WalkTransport t, final WalkRemoteObjectDatabase w) {
- Transport wt = (Transport)t;
- local = wt.local;
- objCheck = wt.isCheckFetchedObjects() ? new ObjectChecker() : null;
- inserter = local.newObjectInserter();
- reader = local.newObjectReader();
-
- remotes = new ArrayList<WalkRemoteObjectDatabase>();
- remotes.add(w);
-
- unfetchedPacks = new LinkedList<RemotePack>();
- packsConsidered = new HashSet<String>();
-
- noPacksYet = new LinkedList<WalkRemoteObjectDatabase>();
- noPacksYet.add(w);
-
- noAlternatesYet = new LinkedList<WalkRemoteObjectDatabase>();
- noAlternatesYet.add(w);
-
- fetchErrors = new HashMap<ObjectId, List<Throwable>>();
- packLocks = new ArrayList<PackLock>(4);
-
- revWalk = new RevWalk(reader);
- revWalk.setRetainBody(false);
- treeWalk = new TreeWalk(reader);
- COMPLETE = revWalk.newFlag("COMPLETE"); //$NON-NLS-1$
- IN_WORK_QUEUE = revWalk.newFlag("IN_WORK_QUEUE"); //$NON-NLS-1$
- LOCALLY_SEEN = revWalk.newFlag("LOCALLY_SEEN"); //$NON-NLS-1$
-
- localCommitQueue = new DateRevQueue();
- workQueue = new LinkedList<ObjectId>();
- }
-
- public boolean didFetchTestConnectivity() {
- return true;
- }
-
- @Override
- protected void doFetch(final ProgressMonitor monitor,
- final Collection<Ref> want, final Set<ObjectId> have)
- throws TransportException {
- markLocalRefsComplete(have);
- queueWants(want);
-
- while (!monitor.isCancelled() && !workQueue.isEmpty()) {
- final ObjectId id = workQueue.removeFirst();
- if (!(id instanceof RevObject) || !((RevObject) id).has(COMPLETE))
- downloadObject(monitor, id);
- process(id);
- }
- }
-
- public Collection<PackLock> getPackLocks() {
- return packLocks;
- }
-
- public void setPackLockMessage(final String message) {
- lockMessage = message;
- }
-
- @Override
- public void close() {
- inserter.release();
- reader.release();
- for (final RemotePack p : unfetchedPacks) {
- if (p.tmpIdx != null)
- p.tmpIdx.delete();
- }
- for (final WalkRemoteObjectDatabase r : remotes)
- r.close();
- }
-
- private void queueWants(final Collection<Ref> want)
- throws TransportException {
- final HashSet<ObjectId> inWorkQueue = new HashSet<ObjectId>();
- for (final Ref r : want) {
- final ObjectId id = r.getObjectId();
- try {
- final RevObject obj = revWalk.parseAny(id);
- if (obj.has(COMPLETE))
- continue;
- if (inWorkQueue.add(id)) {
- obj.add(IN_WORK_QUEUE);
- workQueue.add(obj);
- }
- } catch (MissingObjectException e) {
- if (inWorkQueue.add(id))
- workQueue.add(id);
- } catch (IOException e) {
- throw new TransportException(MessageFormat.format(JGitText.get().cannotRead, id.name()), e);
- }
- }
- }
-
- private void process(final ObjectId id) throws TransportException {
- final RevObject obj;
- try {
- if (id instanceof RevObject) {
- obj = (RevObject) id;
- if (obj.has(COMPLETE))
- return;
- revWalk.parseHeaders(obj);
- } else {
- obj = revWalk.parseAny(id);
- if (obj.has(COMPLETE))
- return;
- }
- } catch (IOException e) {
- throw new TransportException(MessageFormat.format(JGitText.get().cannotRead, id.name()), e);
- }
-
- switch (obj.getType()) {
- case Constants.OBJ_BLOB:
- processBlob(obj);
- break;
- case Constants.OBJ_TREE:
- processTree(obj);
- break;
- case Constants.OBJ_COMMIT:
- processCommit(obj);
- break;
- case Constants.OBJ_TAG:
- processTag(obj);
- break;
- default:
- throw new TransportException(MessageFormat.format(JGitText.get().unknownObjectType, id.name()));
- }
-
- // If we had any prior errors fetching this object they are
- // now resolved, as the object was parsed successfully.
- //
- fetchErrors.remove(id);
- }
-
- private void processBlob(final RevObject obj) throws TransportException {
- try {
- if (reader.has(obj, Constants.OBJ_BLOB))
- obj.add(COMPLETE);
- else
- throw new TransportException(MessageFormat.format(JGitText
- .get().cannotReadBlob, obj.name()),
- new MissingObjectException(obj, Constants.TYPE_BLOB));
- } catch (IOException error) {
- throw new TransportException(MessageFormat.format(
- JGitText.get().cannotReadBlob, obj.name()), error);
- }
- }
-
- private void processTree(final RevObject obj) throws TransportException {
- try {
- treeWalk.reset(obj);
- while (treeWalk.next()) {
- final FileMode mode = treeWalk.getFileMode(0);
- final int sType = mode.getObjectType();
-
- switch (sType) {
- case Constants.OBJ_BLOB:
- case Constants.OBJ_TREE:
- treeWalk.getObjectId(idBuffer, 0);
- needs(revWalk.lookupAny(idBuffer, sType));
- continue;
-
- default:
- if (FileMode.GITLINK.equals(mode))
- continue;
- treeWalk.getObjectId(idBuffer, 0);
- throw new CorruptObjectException(MessageFormat.format(JGitText.get().invalidModeFor
- , mode, idBuffer.name(), treeWalk.getPathString(), obj.getId().name()));
- }
- }
- } catch (IOException ioe) {
- throw new TransportException(MessageFormat.format(JGitText.get().cannotReadTree, obj.name()), ioe);
- }
- obj.add(COMPLETE);
- }
-
- private void processCommit(final RevObject obj) throws TransportException {
- final RevCommit commit = (RevCommit) obj;
- markLocalCommitsComplete(commit.getCommitTime());
- needs(commit.getTree());
- for (final RevCommit p : commit.getParents())
- needs(p);
- obj.add(COMPLETE);
- }
-
- private void processTag(final RevObject obj) {
- final RevTag tag = (RevTag) obj;
- needs(tag.getObject());
- obj.add(COMPLETE);
- }
-
- private void needs(final RevObject obj) {
- if (obj.has(COMPLETE))
- return;
- if (!obj.has(IN_WORK_QUEUE)) {
- obj.add(IN_WORK_QUEUE);
- workQueue.add(obj);
- }
- }
-
- private void downloadObject(final ProgressMonitor pm, final AnyObjectId id)
- throws TransportException {
- if (alreadyHave(id))
- return;
-
- for (;;) {
- // Try a pack file we know about, but don't have yet. Odds are
- // that if it has this object, it has others related to it so
- // getting the pack is a good bet.
- //
- if (downloadPackedObject(pm, id))
- return;
-
- // Search for a loose object over all alternates, starting
- // from the one we last successfully located an object through.
- //
- final String idStr = id.name();
- final String subdir = idStr.substring(0, 2);
- final String file = idStr.substring(2);
- final String looseName = subdir + "/" + file; //$NON-NLS-1$
-
- for (int i = lastRemoteIdx; i < remotes.size(); i++) {
- if (downloadLooseObject(id, looseName, remotes.get(i))) {
- lastRemoteIdx = i;
- return;
- }
- }
- for (int i = 0; i < lastRemoteIdx; i++) {
- if (downloadLooseObject(id, looseName, remotes.get(i))) {
- lastRemoteIdx = i;
- return;
- }
- }
-
- // Try to obtain more pack information and search those.
- //
- while (!noPacksYet.isEmpty()) {
- final WalkRemoteObjectDatabase wrr = noPacksYet.removeFirst();
- final Collection<String> packNameList;
- try {
- pm.beginTask("Listing packs", ProgressMonitor.UNKNOWN);
- packNameList = wrr.getPackNames();
- } catch (IOException e) {
- // Try another repository.
- //
- recordError(id, e);
- continue;
- } finally {
- pm.endTask();
- }
-
- if (packNameList == null || packNameList.isEmpty())
- continue;
- for (final String packName : packNameList) {
- if (packsConsidered.add(packName))
- unfetchedPacks.add(new RemotePack(wrr, packName));
- }
- if (downloadPackedObject(pm, id))
- return;
- }
-
- // Try to expand the first alternate we haven't expanded yet.
- //
- Collection<WalkRemoteObjectDatabase> al = expandOneAlternate(id, pm);
- if (al != null && !al.isEmpty()) {
- for (final WalkRemoteObjectDatabase alt : al) {
- remotes.add(alt);
- noPacksYet.add(alt);
- noAlternatesYet.add(alt);
- }
- continue;
- }
-
- // We could not obtain the object. There may be reasons why.
- //
- List<Throwable> failures = fetchErrors.get(id);
- final TransportException te;
-
- te = new TransportException(MessageFormat.format(JGitText.get().cannotGet, id.name()));
- if (failures != null && !failures.isEmpty()) {
- if (failures.size() == 1)
- te.initCause(failures.get(0));
- else
- te.initCause(new CompoundException(failures));
- }
- throw te;
- }
- }
-
- private boolean alreadyHave(final AnyObjectId id) throws TransportException {
- try {
- return reader.has(id);
- } catch (IOException error) {
- throw new TransportException(MessageFormat.format(
- JGitText.get().cannotReadObject, id.name()), error);
- }
- }
-
- private boolean downloadPackedObject(final ProgressMonitor monitor,
- final AnyObjectId id) throws TransportException {
- // Search for the object in a remote pack whose index we have,
- // but whose pack we do not yet have.
- //
- final Iterator<RemotePack> packItr = unfetchedPacks.iterator();
- while (packItr.hasNext() && !monitor.isCancelled()) {
- final RemotePack pack = packItr.next();
- try {
- pack.openIndex(monitor);
- } catch (IOException err) {
- // If the index won't open its either not found or
- // its a format we don't recognize. In either case
- // we may still be able to obtain the object from
- // another source, so don't consider it a failure.
- //
- recordError(id, err);
- packItr.remove();
- continue;
- }
-
- if (monitor.isCancelled()) {
- // If we were cancelled while the index was opening
- // the open may have aborted. We can't search an
- // unopen index.
- //
- return false;
- }
-
- if (!pack.index.hasObject(id)) {
- // Not in this pack? Try another.
- //
- continue;
- }
-
- // It should be in the associated pack. Download that
- // and attach it to the local repository so we can use
- // all of the contained objects.
- //
- try {
- pack.downloadPack(monitor);
- } catch (IOException err) {
- // If the pack failed to download, index correctly,
- // or open in the local repository we may still be
- // able to obtain this object from another pack or
- // an alternate.
- //
- recordError(id, err);
- continue;
- } finally {
- // If the pack was good its in the local repository
- // and Repository.hasObject(id) will succeed in the
- // future, so we do not need this data anymore. If
- // it failed the index and pack are unusable and we
- // shouldn't consult them again.
- //
- try {
- if (pack.tmpIdx != null)
- FileUtils.delete(pack.tmpIdx);
- } catch (IOException e) {
- throw new TransportException(e.getMessage(), e);
- }
- packItr.remove();
- }
-
- if (!alreadyHave(id)) {
- // What the hell? This pack claimed to have
- // the object, but after indexing we didn't
- // actually find it in the pack.
- //
- recordError(id, new FileNotFoundException(MessageFormat.format(
- JGitText.get().objectNotFoundIn, id.name(), pack.packName)));
- continue;
- }
-
- // Complete any other objects that we can.
- //
- final Iterator<ObjectId> pending = swapFetchQueue();
- while (pending.hasNext()) {
- final ObjectId p = pending.next();
- if (pack.index.hasObject(p)) {
- pending.remove();
- process(p);
- } else {
- workQueue.add(p);
- }
- }
- return true;
-
- }
- return false;
- }
-
- private Iterator<ObjectId> swapFetchQueue() {
- final Iterator<ObjectId> r = workQueue.iterator();
- workQueue = new LinkedList<ObjectId>();
- return r;
- }
-
- private boolean downloadLooseObject(final AnyObjectId id,
- final String looseName, final WalkRemoteObjectDatabase remote)
- throws TransportException {
- try {
- final byte[] compressed = remote.open(looseName).toArray();
- verifyAndInsertLooseObject(id, compressed);
- return true;
- } catch (FileNotFoundException e) {
- // Not available in a loose format from this alternate?
- // Try another strategy to get the object.
- //
- recordError(id, e);
- return false;
- } catch (IOException e) {
- throw new TransportException(MessageFormat.format(JGitText.get().cannotDownload, id.name()), e);
- }
- }
-
- private void verifyAndInsertLooseObject(final AnyObjectId id,
- final byte[] compressed) throws IOException {
- final ObjectLoader uol;
- try {
- uol = UnpackedObject.parse(compressed, id);
- } catch (CorruptObjectException parsingError) {
- // Some HTTP servers send back a "200 OK" status with an HTML
- // page that explains the requested file could not be found.
- // These servers are most certainly misconfigured, but many
- // of them exist in the world, and many of those are hosting
- // Git repositories.
- //
- // Since an HTML page is unlikely to hash to one of our loose
- // objects we treat this condition as a FileNotFoundException
- // and attempt to recover by getting the object from another
- // source.
- //
- final FileNotFoundException e;
- e = new FileNotFoundException(id.name());
- e.initCause(parsingError);
- throw e;
- }
-
- final int type = uol.getType();
- final byte[] raw = uol.getCachedBytes();
- if (objCheck != null) {
- try {
- objCheck.check(type, raw);
- } catch (CorruptObjectException e) {
- throw new TransportException(MessageFormat.format(JGitText.get().transportExceptionInvalid
- , Constants.typeString(type), id.name(), e.getMessage()));
- }
- }
-
- ObjectId act = inserter.insert(type, raw);
- if (!AnyObjectId.equals(id, act)) {
- throw new TransportException(MessageFormat.format(
- JGitText.get().incorrectHashFor, id.name(), act.name(),
- Constants.typeString(type),
- Integer.valueOf(compressed.length)));
- }
- inserter.flush();
- }
-
- private Collection<WalkRemoteObjectDatabase> expandOneAlternate(
- final AnyObjectId id, final ProgressMonitor pm) {
- while (!noAlternatesYet.isEmpty()) {
- final WalkRemoteObjectDatabase wrr = noAlternatesYet.removeFirst();
- try {
- pm.beginTask(JGitText.get().listingAlternates, ProgressMonitor.UNKNOWN);
- Collection<WalkRemoteObjectDatabase> altList = wrr
- .getAlternates();
- if (altList != null && !altList.isEmpty())
- return altList;
- } catch (IOException e) {
- // Try another repository.
- //
- recordError(id, e);
- } finally {
- pm.endTask();
- }
- }
- return null;
- }
-
- private void markLocalRefsComplete(final Set<ObjectId> have) throws TransportException {
- Map<String, Ref> refs;
- try {
- refs = local.getRefDatabase().getRefs(ALL);
- } catch (IOException e) {
- throw new TransportException(e.getMessage(), e);
- }
- for (final Ref r : refs.values()) {
- try {
- markLocalObjComplete(revWalk.parseAny(r.getObjectId()));
- } catch (IOException readError) {
- throw new TransportException(MessageFormat.format(JGitText.get().localRefIsMissingObjects, r.getName()), readError);
- }
- }
- for (final ObjectId id : have) {
- try {
- markLocalObjComplete(revWalk.parseAny(id));
- } catch (IOException readError) {
- throw new TransportException(MessageFormat.format(JGitText.get().transportExceptionMissingAssumed, id.name()), readError);
- }
- }
- }
-
- private void markLocalObjComplete(RevObject obj) throws IOException {
- while (obj.getType() == Constants.OBJ_TAG) {
- obj.add(COMPLETE);
- obj = ((RevTag) obj).getObject();
- revWalk.parseHeaders(obj);
- }
-
- switch (obj.getType()) {
- case Constants.OBJ_BLOB:
- obj.add(COMPLETE);
- break;
- case Constants.OBJ_COMMIT:
- pushLocalCommit((RevCommit) obj);
- break;
- case Constants.OBJ_TREE:
- markTreeComplete((RevTree) obj);
- break;
- }
- }
-
- private void markLocalCommitsComplete(final int until)
- throws TransportException {
- try {
- for (;;) {
- final RevCommit c = localCommitQueue.peek();
- if (c == null || c.getCommitTime() < until)
- return;
- localCommitQueue.next();
-
- markTreeComplete(c.getTree());
- for (final RevCommit p : c.getParents())
- pushLocalCommit(p);
- }
- } catch (IOException err) {
- throw new TransportException(JGitText.get().localObjectsIncomplete, err);
- }
- }
-
- private void pushLocalCommit(final RevCommit p)
- throws MissingObjectException, IOException {
- if (p.has(LOCALLY_SEEN))
- return;
- revWalk.parseHeaders(p);
- p.add(LOCALLY_SEEN);
- p.add(COMPLETE);
- p.carry(COMPLETE);
- localCommitQueue.add(p);
- }
-
- private void markTreeComplete(final RevTree tree) throws IOException {
- if (tree.has(COMPLETE))
- return;
- tree.add(COMPLETE);
- treeWalk.reset(tree);
- while (treeWalk.next()) {
- final FileMode mode = treeWalk.getFileMode(0);
- final int sType = mode.getObjectType();
-
- switch (sType) {
- case Constants.OBJ_BLOB:
- treeWalk.getObjectId(idBuffer, 0);
- revWalk.lookupAny(idBuffer, sType).add(COMPLETE);
- continue;
-
- case Constants.OBJ_TREE: {
- treeWalk.getObjectId(idBuffer, 0);
- final RevObject o = revWalk.lookupAny(idBuffer, sType);
- if (!o.has(COMPLETE)) {
- o.add(COMPLETE);
- treeWalk.enterSubtree();
- }
- continue;
- }
- default:
- if (FileMode.GITLINK.equals(mode))
- continue;
- treeWalk.getObjectId(idBuffer, 0);
- throw new CorruptObjectException(MessageFormat.format(JGitText.get().corruptObjectInvalidMode3
- , mode, idBuffer.name(), treeWalk.getPathString(), tree.name()));
- }
- }
- }
-
- private void recordError(final AnyObjectId id, final Throwable what) {
- final ObjectId objId = id.copy();
- List<Throwable> errors = fetchErrors.get(objId);
- if (errors == null) {
- errors = new ArrayList<Throwable>(2);
- fetchErrors.put(objId, errors);
- }
- errors.add(what);
- }
-
- private class RemotePack {
- final WalkRemoteObjectDatabase connection;
-
- final String packName;
-
- final String idxName;
-
- File tmpIdx;
-
- PackIndex index;
-
- RemotePack(final WalkRemoteObjectDatabase c, final String pn) {
- connection = c;
- packName = pn;
- idxName = packName.substring(0, packName.length() - 5) + ".idx"; //$NON-NLS-1$
-
- String tn = idxName;
- if (tn.startsWith("pack-")) //$NON-NLS-1$
- tn = tn.substring(5);
- if (tn.endsWith(".idx")) //$NON-NLS-1$
- tn = tn.substring(0, tn.length() - 4);
-
- if (local.getObjectDatabase() instanceof ObjectDirectory) {
- tmpIdx = new File(((ObjectDirectory) local.getObjectDatabase())
- .getDirectory(),
- "walk-" + tn + ".walkidx"); //$NON-NLS-1$ //$NON-NLS-2$
- }
- }
-
- void openIndex(final ProgressMonitor pm) throws IOException {
- if (index != null)
- return;
- if (tmpIdx == null)
- tmpIdx = File.createTempFile("jgit-walk-", ".idx"); //$NON-NLS-1$ //$NON-NLS-2$
- else if (tmpIdx.isFile()) {
- try {
- index = PackIndex.open(tmpIdx);
- return;
- } catch (FileNotFoundException err) {
- // Fall through and get the file.
- }
- }
-
- final WalkRemoteObjectDatabase.FileStream s;
- s = connection.open("pack/" + idxName); //$NON-NLS-1$
- pm.beginTask("Get " + idxName.substring(0, 12) + "..idx", //$NON-NLS-1$ //$NON-NLS-2$
- s.length < 0 ? ProgressMonitor.UNKNOWN
- : (int) (s.length / 1024));
- try {
- final FileOutputStream fos = new FileOutputStream(tmpIdx);
- try {
- final byte[] buf = new byte[2048];
- int cnt;
- while (!pm.isCancelled() && (cnt = s.in.read(buf)) >= 0) {
- fos.write(buf, 0, cnt);
- pm.update(cnt / 1024);
- }
- } finally {
- fos.close();
- }
- } catch (IOException err) {
- FileUtils.delete(tmpIdx);
- throw err;
- } finally {
- s.in.close();
- }
- pm.endTask();
-
- if (pm.isCancelled()) {
- FileUtils.delete(tmpIdx);
- return;
- }
-
- try {
- index = PackIndex.open(tmpIdx);
- } catch (IOException e) {
- FileUtils.delete(tmpIdx);
- throw e;
- }
- }
-
- void downloadPack(final ProgressMonitor monitor) throws IOException {
- String name = "pack/" + packName; //$NON-NLS-1$
- WalkRemoteObjectDatabase.FileStream s = connection.open(name);
- PackParser parser = inserter.newPackParser(s.in);
- parser.setAllowThin(false);
- parser.setObjectChecker(objCheck);
- parser.setLockMessage(lockMessage);
- PackLock lock = parser.parse(monitor);
- if (lock != null)
- packLocks.add(lock);
- inserter.flush();
- }
- }
- }
|