org.spearce.egit.core.op.CloneOperation.java Source code

Java tutorial

Introduction

Here is the source code for org.spearce.egit.core.op.CloneOperation.java

Source

/*******************************************************************************
 * Copyright (C) 2007, Dave Watson <dwatson@mimvista.com>
 * Copyright (C) 2008, Robin Rosenberg <robin.rosenberg@dewire.com>
 * Copyright (C) 2008, Roger C. Soares <rogersoares@intelinet.com.br>
 * Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org>
 * Copyright (C) 2008, Marek Zawirski <marek.zawirski@gmail.com>
 *
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * See LICENSE for the full license text, also available.
 *******************************************************************************/
package org.spearce.egit.core.op;

import java.io.File;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.net.URISyntaxException;
import java.util.Collection;

import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.SubProgressMonitor;
import org.eclipse.jface.operation.IRunnableWithProgress;
import org.eclipse.osgi.util.NLS;
import org.spearce.egit.core.CoreText;
import org.spearce.egit.core.EclipseGitProgressTransformer;
import org.spearce.jgit.errors.NotSupportedException;
import org.spearce.jgit.errors.TransportException;
import org.spearce.jgit.lib.Commit;
import org.spearce.jgit.lib.Constants;
import org.spearce.jgit.lib.GitIndex;
import org.spearce.jgit.lib.Ref;
import org.spearce.jgit.lib.RefUpdate;
import org.spearce.jgit.lib.Repository;
import org.spearce.jgit.lib.Tree;
import org.spearce.jgit.lib.WorkDirCheckout;
import org.spearce.jgit.transport.FetchResult;
import org.spearce.jgit.transport.RefSpec;
import org.spearce.jgit.transport.RemoteConfig;
import org.spearce.jgit.transport.Transport;
import org.spearce.jgit.transport.URIish;

/**
 * Clones a repository from a remote location to a local location.
 */
public class CloneOperation implements IRunnableWithProgress {
    private final URIish uri;

    private final boolean allSelected;

    private final Collection<Ref> selectedBranches;

    private final File workdir;

    private final String branch;

    private final String remoteName;

    private Repository local;

    private RemoteConfig remoteConfig;

    private FetchResult fetchResult;

    /**
     * Create a new clone operation.
     * 
     * @param uri
     *            remote we should fetch from.
     * @param allSelected
     *            true when all branches have to be fetched (indicates wildcard
     *            in created fetch refspec), false otherwise.
     * @param selectedBranches
     *            collection of branches to fetch. Ignored when allSelected is
     *            true.
     * @param workdir
     *            working directory to clone to. The directory may or may not
     *            already exist.
     * @param branch
     *            branch to initially clone from.
     * @param remoteName
     *            name of created remote config as source remote (typically
     *            named "origin").
     */
    public CloneOperation(final URIish uri, final boolean allSelected, final Collection<Ref> selectedBranches,
            final File workdir, final String branch, final String remoteName) {
        this.uri = uri;
        this.allSelected = allSelected;
        this.selectedBranches = selectedBranches;
        this.workdir = workdir;
        this.branch = branch;
        this.remoteName = remoteName;
    }

    public void run(final IProgressMonitor pm) throws InvocationTargetException, InterruptedException {
        final IProgressMonitor monitor;
        if (pm == null)
            monitor = new NullProgressMonitor();
        else
            monitor = pm;

        try {
            monitor.beginTask(NLS.bind(CoreText.CloneOperation_title, uri), 5000);
            try {
                doInit(new SubProgressMonitor(monitor, 100));
                doFetch(new SubProgressMonitor(monitor, 4000));
                doCheckout(new SubProgressMonitor(monitor, 900));
            } finally {
                closeLocal();
            }
        } catch (final Exception e) {
            delete(workdir);
            if (monitor.isCanceled())
                throw new InterruptedException();
            else
                throw new InvocationTargetException(e);
        } finally {
            monitor.done();
        }
    }

    private void closeLocal() {
        if (local != null) {
            local.close();
            local = null;
        }
    }

    private void doInit(final IProgressMonitor monitor) throws URISyntaxException, IOException {
        monitor.setTaskName("Initializing local repository");

        final File gitdir = new File(workdir, ".git");
        local = new Repository(gitdir);
        local.create();
        local.writeSymref(Constants.HEAD, branch);

        remoteConfig = new RemoteConfig(local.getConfig(), remoteName);
        remoteConfig.addURI(uri);

        final String dst = Constants.R_REMOTES + remoteConfig.getName();
        RefSpec wcrs = new RefSpec();
        wcrs = wcrs.setForceUpdate(true);
        wcrs = wcrs.setSourceDestination(Constants.R_HEADS + "*", dst + "/*");

        if (allSelected) {
            remoteConfig.addFetchRefSpec(wcrs);
        } else {
            for (final Ref ref : selectedBranches)
                if (wcrs.matchSource(ref))
                    remoteConfig.addFetchRefSpec(wcrs.expandFromSource(ref));
        }

        remoteConfig.update(local.getConfig());
        local.getConfig().save();
    }

    private void doFetch(final IProgressMonitor monitor) throws NotSupportedException, TransportException {
        final Transport tn = Transport.open(local, remoteConfig);
        try {
            final EclipseGitProgressTransformer pm;
            pm = new EclipseGitProgressTransformer(monitor);
            fetchResult = tn.fetch(pm, null);
        } finally {
            tn.close();
        }
    }

    private void doCheckout(final IProgressMonitor monitor) throws IOException {
        final Ref head = fetchResult.getAdvertisedRef(branch);
        if (head == null || head.getObjectId() == null)
            return;

        final GitIndex index = new GitIndex(local);
        final Commit mapCommit = local.mapCommit(head.getObjectId());
        final Tree tree = mapCommit.getTree();
        final RefUpdate u;
        final WorkDirCheckout co;

        u = local.updateRef(Constants.HEAD);
        u.setNewObjectId(mapCommit.getCommitId());
        u.forceUpdate();

        monitor.setTaskName("Checking out files");
        co = new WorkDirCheckout(local, local.getWorkDir(), index, tree);
        co.checkout();
        monitor.setTaskName("Writing index");
        index.write();
    }

    private static void delete(final File d) {
        if (d.isDirectory()) {
            final File[] items = d.listFiles();
            if (items != null) {
                for (final File c : items)
                    delete(c);
            }
        }
        d.delete();
    }
}