com.gitblit.wicket.pages.NewRepositoryPage.java Source code

Java tutorial

Introduction

Here is the source code for com.gitblit.wicket.pages.NewRepositoryPage.java

Source

/*
 * Copyright 2014 gitblit.com.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.gitblit.wicket.pages;

import java.io.File;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import org.apache.wicket.AttributeModifier;
import org.apache.wicket.markup.html.form.Button;
import org.apache.wicket.markup.html.form.Form;
import org.apache.wicket.model.CompoundPropertyModel;
import org.apache.wicket.model.IModel;
import org.apache.wicket.model.Model;
import org.eclipse.jgit.dircache.DirCache;
import org.eclipse.jgit.dircache.DirCacheBuilder;
import org.eclipse.jgit.dircache.DirCacheEntry;
import org.eclipse.jgit.lib.CommitBuilder;
import org.eclipse.jgit.lib.Config;
import org.eclipse.jgit.lib.FileMode;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.ObjectInserter;
import org.eclipse.jgit.lib.PersonIdent;
import org.eclipse.jgit.lib.RefUpdate;
import org.eclipse.jgit.lib.RefUpdate.Result;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.revwalk.RevWalk;

import com.gitblit.Constants;
import com.gitblit.Constants.AccessRestrictionType;
import com.gitblit.Constants.AuthorizationControl;
import com.gitblit.GitBlitException;
import com.gitblit.Keys;
import com.gitblit.models.RepositoryModel;
import com.gitblit.models.UserModel;
import com.gitblit.utils.ArrayUtils;
import com.gitblit.utils.FileUtils;
import com.gitblit.utils.StringUtils;
import com.gitblit.wicket.GitBlitWebSession;
import com.gitblit.wicket.WicketUtils;
import com.gitblit.wicket.panels.AccessPolicyPanel;
import com.gitblit.wicket.panels.BooleanChoiceOption;
import com.gitblit.wicket.panels.BooleanOption;
import com.gitblit.wicket.panels.RepositoryNamePanel;
import com.google.common.base.Optional;

public class NewRepositoryPage extends RootSubPage {

    private final RepositoryModel repositoryModel;
    private IModel<Boolean> addReadmeModel;
    private Model<String> gitignoreModel;
    private IModel<Boolean> addGitflowModel;
    private IModel<Boolean> addGitignoreModel;
    private AccessPolicyPanel accessPolicyPanel;
    private RepositoryNamePanel namePanel;

    public NewRepositoryPage() {
        // create constructor
        super();
        repositoryModel = new RepositoryModel();

        setupPage(getString("gb.newRepository"), "");

        setStatelessHint(false);
        setOutputMarkupId(true);
    }

    @Override
    protected boolean requiresPageMap() {
        return true;
    }

    @Override
    protected Class<? extends BasePage> getRootNavPageClass() {
        return RepositoriesPage.class;
    }

    @Override
    protected void onInitialize() {
        super.onInitialize();

        CompoundPropertyModel<RepositoryModel> rModel = new CompoundPropertyModel<>(repositoryModel);
        Form<RepositoryModel> form = new Form<RepositoryModel>("editForm", rModel) {

            private static final long serialVersionUID = 1L;

            @Override
            protected void onSubmit() {
                try {
                    if (!namePanel.updateModel(repositoryModel)) {
                        return;
                    }
                    accessPolicyPanel.updateModel(repositoryModel);

                    repositoryModel.owners = new ArrayList<String>();
                    repositoryModel.owners.add(GitBlitWebSession.get().getUsername());

                    // setup branch defaults
                    boolean useGitFlow = addGitflowModel.getObject();

                    repositoryModel.HEAD = Constants.R_MASTER;
                    repositoryModel.mergeTo = Constants.MASTER;
                    if (useGitFlow) {
                        // tickets normally merge to develop unless they are hotfixes
                        repositoryModel.mergeTo = Constants.DEVELOP;
                    }

                    repositoryModel.allowForks = app().settings().getBoolean(Keys.web.allowForking, true);

                    // optionally generate an initial commit
                    boolean addReadme = addReadmeModel.getObject();
                    String gitignore = null;
                    boolean addGitignore = addGitignoreModel.getObject();
                    if (addGitignore) {
                        gitignore = gitignoreModel.getObject();
                        if (StringUtils.isEmpty(gitignore)) {
                            throw new GitBlitException(getString("gb.pleaseSelectGitIgnore"));
                        }
                    }

                    // init the repository
                    app().gitblit().updateRepositoryModel(repositoryModel.name, repositoryModel, true);

                    // optionally create an initial commit
                    initialCommit(repositoryModel, addReadme, gitignore, useGitFlow);

                } catch (GitBlitException e) {
                    error(e.getMessage());
                    return;
                }
                setResponsePage(SummaryPage.class, WicketUtils.newRepositoryParameter(repositoryModel.name));
            }
        };

        // do not let the browser pre-populate these fields
        form.add(new AttributeModifier("autocomplete", "off"));

        namePanel = new RepositoryNamePanel("namePanel", repositoryModel);
        form.add(namePanel);

        // prepare the default access controls
        AccessRestrictionType defaultRestriction = AccessRestrictionType.fromName(
                app().settings().getString(Keys.git.defaultAccessRestriction, AccessRestrictionType.PUSH.name()));
        if (AccessRestrictionType.NONE == defaultRestriction) {
            defaultRestriction = AccessRestrictionType.PUSH;
        }
        AuthorizationControl defaultControl = AuthorizationControl.fromName(app().settings()
                .getString(Keys.git.defaultAuthorizationControl, AuthorizationControl.NAMED.name()));

        if (AuthorizationControl.AUTHENTICATED == defaultControl) {
            defaultRestriction = AccessRestrictionType.PUSH;
        }

        repositoryModel.authorizationControl = defaultControl;
        repositoryModel.accessRestriction = defaultRestriction;

        accessPolicyPanel = new AccessPolicyPanel("accessPolicyPanel", repositoryModel);
        form.add(accessPolicyPanel);

        //
        // initial commit options
        //

        // add README
        addReadmeModel = Model.of(false);
        form.add(new BooleanOption("addReadme", getString("gb.initWithReadme"),
                getString("gb.initWithReadmeDescription"), addReadmeModel));

        // add .gitignore
        File gitignoreDir = app().runtime().getFileOrFolder(Keys.git.gitignoreFolder, "${baseFolder}/gitignore");
        File[] files = gitignoreDir.listFiles();
        if (files == null) {
            files = new File[0];
        }
        List<String> gitignores = new ArrayList<String>();
        for (File file : files) {
            if (file.isFile() && file.getName().endsWith(".gitignore")) {
                gitignores.add(StringUtils.stripFileExtension(file.getName()));
            }
        }
        Collections.sort(gitignores);

        gitignoreModel = Model.of("");
        addGitignoreModel = Model.of(false);
        form.add(new BooleanChoiceOption<String>("addGitIgnore", getString("gb.initWithGitignore"),
                getString("gb.initWithGitignoreDescription"), addGitignoreModel, gitignoreModel, gitignores)
                        .setVisible(gitignores.size() > 0));

        // TODO consider gitflow at creation (ticket-55)
        addGitflowModel = Model.of(false);
        form.add(new BooleanOption("addGitFlow", "Include a .gitflow file",
                "This will generate a config file which guides Git clients in setting up Gitflow branches.",
                addGitflowModel).setVisible(false));

        form.add(new Button("create"));

        add(form);
    }

    /**
     * Prepare the initial commit for the repository.
     *
     * @param repository
     * @param addReadme
     * @param gitignore
     * @param addGitFlow
     * @return true if an initial commit was created
     */
    protected boolean initialCommit(RepositoryModel repository, boolean addReadme, String gitignore,
            boolean addGitFlow) {
        boolean initialCommit = addReadme || !StringUtils.isEmpty(gitignore) || addGitFlow;
        if (!initialCommit) {
            return false;
        }

        // build an initial commit
        boolean success = false;
        Repository db = app().repositories().getRepository(repositoryModel.name);
        ObjectInserter odi = db.newObjectInserter();
        try {

            UserModel user = GitBlitWebSession.get().getUser();
            String email = Optional.fromNullable(user.emailAddress).or(user.username + "@" + "gitblit");
            PersonIdent author = new PersonIdent(user.getDisplayName(), email);

            DirCache newIndex = DirCache.newInCore();
            DirCacheBuilder indexBuilder = newIndex.builder();

            if (addReadme) {
                // insert a README
                String title = StringUtils.stripDotGit(StringUtils.getLastPathElement(repositoryModel.name));
                String description = repositoryModel.description == null ? "" : repositoryModel.description;
                String readme = String.format("## %s\n\n%s\n\n", title, description);
                byte[] bytes = readme.getBytes(Constants.ENCODING);

                DirCacheEntry entry = new DirCacheEntry("README.md");
                entry.setLength(bytes.length);
                entry.setLastModified(System.currentTimeMillis());
                entry.setFileMode(FileMode.REGULAR_FILE);
                entry.setObjectId(odi.insert(org.eclipse.jgit.lib.Constants.OBJ_BLOB, bytes));

                indexBuilder.add(entry);
            }

            if (!StringUtils.isEmpty(gitignore)) {
                // insert a .gitignore file
                File dir = app().runtime().getFileOrFolder(Keys.git.gitignoreFolder, "${baseFolder}/gitignore");
                File file = new File(dir, gitignore + ".gitignore");
                if (file.exists() && file.length() > 0) {
                    byte[] bytes = FileUtils.readContent(file);
                    if (!ArrayUtils.isEmpty(bytes)) {
                        DirCacheEntry entry = new DirCacheEntry(".gitignore");
                        entry.setLength(bytes.length);
                        entry.setLastModified(System.currentTimeMillis());
                        entry.setFileMode(FileMode.REGULAR_FILE);
                        entry.setObjectId(odi.insert(org.eclipse.jgit.lib.Constants.OBJ_BLOB, bytes));

                        indexBuilder.add(entry);
                    }
                }
            }

            if (addGitFlow) {
                // insert a .gitflow file
                Config config = new Config();
                config.setString("gitflow", null, "masterBranch", Constants.MASTER);
                config.setString("gitflow", null, "developBranch", Constants.DEVELOP);
                config.setString("gitflow", null, "featureBranchPrefix", "feature/");
                config.setString("gitflow", null, "releaseBranchPrefix", "release/");
                config.setString("gitflow", null, "hotfixBranchPrefix", "hotfix/");
                config.setString("gitflow", null, "supportBranchPrefix", "support/");
                config.setString("gitflow", null, "versionTagPrefix", "");

                byte[] bytes = config.toText().getBytes(Constants.ENCODING);

                DirCacheEntry entry = new DirCacheEntry(".gitflow");
                entry.setLength(bytes.length);
                entry.setLastModified(System.currentTimeMillis());
                entry.setFileMode(FileMode.REGULAR_FILE);
                entry.setObjectId(odi.insert(org.eclipse.jgit.lib.Constants.OBJ_BLOB, bytes));

                indexBuilder.add(entry);
            }

            indexBuilder.finish();

            if (newIndex.getEntryCount() == 0) {
                // nothing to commit
                return false;
            }

            ObjectId treeId = newIndex.writeTree(odi);

            // Create a commit object
            CommitBuilder commit = new CommitBuilder();
            commit.setAuthor(author);
            commit.setCommitter(author);
            commit.setEncoding(Constants.ENCODING);
            commit.setMessage("Initial commit");
            commit.setTreeId(treeId);

            // Insert the commit into the repository
            ObjectId commitId = odi.insert(commit);
            odi.flush();

            // set the branch refs
            RevWalk revWalk = new RevWalk(db);
            try {
                // set the master branch
                RevCommit revCommit = revWalk.parseCommit(commitId);
                RefUpdate masterRef = db.updateRef(Constants.R_MASTER);
                masterRef.setNewObjectId(commitId);
                masterRef.setRefLogMessage("commit: " + revCommit.getShortMessage(), false);
                Result masterRC = masterRef.update();
                switch (masterRC) {
                case NEW:
                    success = true;
                    break;
                default:
                    success = false;
                }

                if (addGitFlow) {
                    // set the develop branch for git-flow
                    RefUpdate developRef = db.updateRef(Constants.R_DEVELOP);
                    developRef.setNewObjectId(commitId);
                    developRef.setRefLogMessage("commit: " + revCommit.getShortMessage(), false);
                    Result developRC = developRef.update();
                    switch (developRC) {
                    case NEW:
                        success = true;
                        break;
                    default:
                        success = false;
                    }
                }
            } finally {
                revWalk.close();
            }
        } catch (UnsupportedEncodingException e) {
            logger().error(null, e);
        } catch (IOException e) {
            logger().error(null, e);
        } finally {
            odi.close();
            db.close();
        }
        return success;
    }
}