org.locationtech.geogig.porcelain.InitOp.java Source code

Java tutorial

Introduction

Here is the source code for org.locationtech.geogig.porcelain.InitOp.java

Source

/* Copyright (c) 2012-2016 Boundless and others.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Distribution License v1.0
 * which accompanies this distribution, and is available at
 * https://www.eclipse.org/org/documents/edl-v10.html
 *
 * Contributors:
 * Gabriel Roldan (Boundless) - initial implementation
 */
package org.locationtech.geogig.porcelain;

import static com.google.common.base.Optional.absent;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.Serializable;
import java.net.URI;
import java.util.Map;
import java.util.Map.Entry;

import org.locationtech.geogig.di.CanRunDuringConflict;
import org.locationtech.geogig.model.ObjectId;
import org.locationtech.geogig.model.Ref;
import org.locationtech.geogig.model.RevTree;
import org.locationtech.geogig.plumbing.RefParse;
import org.locationtech.geogig.plumbing.ResolveGeogigURI;
import org.locationtech.geogig.plumbing.UpdateRef;
import org.locationtech.geogig.plumbing.UpdateSymRef;
import org.locationtech.geogig.remote.AbstractMappedRemoteRepo;
import org.locationtech.geogig.repository.AbstractGeoGigOp;
import org.locationtech.geogig.repository.Hints;
import org.locationtech.geogig.repository.Platform;
import org.locationtech.geogig.repository.Repository;
import org.locationtech.geogig.repository.RepositoryConnectionException;
import org.locationtech.geogig.repository.RepositoryResolver;
import org.locationtech.geogig.storage.ConfigDatabase;
import org.locationtech.geogig.storage.ConfigException;
import org.locationtech.geogig.storage.ObjectStore;
import org.locationtech.geogig.storage.PluginDefaults;
import org.locationtech.geogig.storage.VersionedFormat;

import com.google.common.base.Optional;
import com.google.common.base.Preconditions;
import com.google.common.base.Throwables;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Maps;
import com.google.common.io.Files;
import com.google.inject.Inject;

/**
 * Creates or "initializes" a repository in the {@link Platform#pwd() working directory}.
 * <p>
 * This command tries to find an existing {@code .geogig} repository directory in the current
 * directory's hierarchy. It is safe to call it from inside a directory that's a child of a
 * repository.
 * <p>
 * If no repository directory is found, then a new one is created on the current directory.
 * 
 * @see ResolveGeogigURI
 * @see RefParse
 * @see UpdateRef
 * @see UpdateSymRef
 */
@CanRunDuringConflict
public class InitOp extends AbstractGeoGigOp<Repository> {

    private Map<String, String> config;

    private String filterFile;

    private Hints hints;

    /**
     * Constructs a new {@code InitOp} with the specified parameters.
     * 
     * @param platform where to get the current directory from
     * @param hints may contain where to get the repository from (using the
     *        {@link Hints#REPOSITORY_URL} argument)
     */
    @Inject
    public InitOp(Hints hints) {
        this.config = Maps.newTreeMap();
        this.hints = hints;
    }

    public InitOp setConfig(Map<String, String> suppliedConfiguration) {
        this.config = ImmutableMap.copyOf(suppliedConfiguration);
        return this;
    }

    /**
     * @deprecated must provide repository URI in {@link Hints} instead
     */
    @Deprecated
    public InitOp setTarget(File targetRepoDirectory) {
        return this;
    }

    public InitOp setFilterFile(String filterFile) {
        this.filterFile = filterFile;
        return this;
    }

    /**
     * Executes the Init operation.
     * 
     * @return the initialized repository
     * @throws IllegalStateException if a repository cannot be created on the current directory or
     *         re-initialized in the current dir or one if its parents as determined by
     *         {@link ResolveGeogigURI}
     */
    @Override
    protected Repository _call() {
        final Platform platform = platform();
        Optional<URI> resolvedURI = new ResolveGeogigURI(platform, hints).call();
        if (!resolvedURI.isPresent()) {
            resolvedURI = Optional.of(platform.pwd().getAbsoluteFile().toURI());
        }

        URI repoURI = resolvedURI.get();

        final RepositoryResolver repoInitializer = RepositoryResolver.lookup(repoURI);
        final boolean repoExisted = repoInitializer.repoExists(repoURI);

        repoInitializer.initialize(repoURI, context());

        Map<String, String> effectiveConfigBuilder = Maps.newTreeMap();
        Optional<Serializable> repoName = hints.get(Hints.REPOSITORY_NAME);
        if (repoName.isPresent()) {
            effectiveConfigBuilder.put("repo.name", String.valueOf(repoName.get()));
        }

        if (filterFile != null) {
            try {

                File oldFilterFile = new File(filterFile);
                if (!oldFilterFile.exists()) {
                    throw new FileNotFoundException("No filter file found at " + filterFile + ".");
                }

                repository().blobStore().putBlob(AbstractMappedRemoteRepo.SPARSE_FILTER_BLOB_KEY,
                        Files.toByteArray(oldFilterFile));
            } catch (Exception e) {
                throw new IllegalStateException(
                        "Unable to copy filter file at path " + filterFile + " to the new repository.", e);
            }
        }

        Repository repository;
        try {
            if (!repoExisted) {
                // use a config database appropriate for the kind of repo URI
                try (ConfigDatabase configDB = repoInitializer.getConfigDatabase(repoURI, context)) {
                    PluginDefaults defaults = context.pluginDefaults();
                    addDefaults(configDB, defaults, effectiveConfigBuilder);
                    if (config != null) {
                        effectiveConfigBuilder.putAll(config);
                    }
                    try {
                        for (Entry<String, String> pair : effectiveConfigBuilder.entrySet()) {
                            String key = pair.getKey();
                            String value = pair.getValue();
                            configDB.put(key, value);
                        }
                        repository = repository();
                        repository.configure();
                    } catch (RepositoryConnectionException e) {
                        throw new IllegalStateException(
                                "Unable to initialize repository for the first time: " + e.getMessage(), e);
                    }
                }
            } else {
                repository = repository();
            }
            try {
                repository.open();
                // make sure the repo has the empty tree
                ObjectStore objectDatabase = repository.objectDatabase();
                objectDatabase.put(RevTree.EMPTY);
            } catch (RepositoryConnectionException e) {
                throw new IllegalStateException("Error opening repository databases: " + e.getMessage(), e);
            }
        } catch (ConfigException e) {
            throw e;
        } catch (Exception e) {
            Throwables.propagateIfInstanceOf(e, IllegalStateException.class);
            throw new IllegalStateException("Can't access repository at '" + repoURI + "'", e);
        }

        if (!repoExisted) {
            try {
                createDefaultRefs();
            } catch (IllegalStateException e) {
                Throwables.propagate(e);
            }
        }
        return repository;
    }

    private void addDefaults(ConfigDatabase configDB, PluginDefaults defaults, Map<String, String> configProps) {

        final String refsKey = "storage.refs";
        final String objectsKey = "storage.objects";
        final String graphKey = "storage.graph";

        final Map<String, String> providedConfig = configDB.getAll();

        Optional<VersionedFormat> refs;
        Optional<VersionedFormat> objects;
        Optional<VersionedFormat> graph;

        refs = providedConfig.containsKey(refsKey) ? absent() : defaults.getRefs();
        objects = providedConfig.containsKey(objectsKey) ? absent() : defaults.getObjects();
        graph = providedConfig.containsKey(graphKey) ? absent() : defaults.getGraph();

        if (refs.isPresent()) {
            configProps.put(refsKey, refs.get().getFormat());
            configProps.put(refs.get().getFormat() + ".version", refs.get().getVersion());
        }
        if (objects.isPresent()) {
            configProps.put(objectsKey, objects.get().getFormat());
            configProps.put(objects.get().getFormat() + ".version", objects.get().getVersion());
        }
        if (graph.isPresent()) {
            configProps.put(graphKey, graph.get().getFormat());
            configProps.put(graph.get().getFormat() + ".version", graph.get().getVersion());
        }
    }

    private void createDefaultRefs() {
        Optional<Ref> master = command(RefParse.class).setName(Ref.MASTER).call();
        Preconditions.checkState(!master.isPresent(), Ref.MASTER + " was already initialized.");
        command(UpdateRef.class).setName(Ref.MASTER).setNewValue(ObjectId.NULL)
                .setReason("Repository initialization").call();

        Optional<Ref> head = command(RefParse.class).setName(Ref.HEAD).call();
        Preconditions.checkState(!head.isPresent(), Ref.HEAD + " was already initialized.");
        command(UpdateSymRef.class).setName(Ref.HEAD).setNewValue(Ref.MASTER).setReason("Repository initialization")
                .call();

        Optional<Ref> workhead = command(RefParse.class).setName(Ref.WORK_HEAD).call();
        Preconditions.checkState(!workhead.isPresent(), Ref.WORK_HEAD + " was already initialized.");
        command(UpdateRef.class).setName(Ref.WORK_HEAD).setNewValue(RevTree.EMPTY.getId())
                .setReason("Repository initialization").call();

        Optional<Ref> stagehead = command(RefParse.class).setName(Ref.STAGE_HEAD).call();
        Preconditions.checkState(!stagehead.isPresent(), Ref.STAGE_HEAD + " was already initialized.");
        command(UpdateRef.class).setName(Ref.STAGE_HEAD).setNewValue(RevTree.EMPTY.getId())
                .setReason("Repository initialization").call();

    }
}