Line data Source code
1 : // Copyright (C) 2011 The Android Open Source Project 2 : // 3 : // Licensed under the Apache License, Version 2.0 (the "License"); 4 : // you may not use this file except in compliance with the License. 5 : // You may obtain a copy of the License at 6 : // 7 : // http://www.apache.org/licenses/LICENSE-2.0 8 : // 9 : // Unless required by applicable law or agreed to in writing, software 10 : // distributed under the License is distributed on an "AS IS" BASIS, 11 : // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 : // See the License for the specific language governing permissions and 13 : // limitations under the License. 14 : 15 : package com.google.gerrit.server.submit; 16 : 17 : import com.google.common.collect.ImmutableList; 18 : import com.google.common.collect.ImmutableSet; 19 : import com.google.gerrit.entities.BranchNameKey; 20 : import com.google.gerrit.entities.Project; 21 : import com.google.gerrit.exceptions.StorageException; 22 : import com.google.gerrit.extensions.restapi.RestApiException; 23 : import com.google.gerrit.server.git.CodeReviewCommit; 24 : import com.google.gerrit.server.project.NoSuchProjectException; 25 : import com.google.gerrit.server.submit.MergeOpRepoManager.OpenRepo; 26 : import com.google.gerrit.server.update.BatchUpdate; 27 : import com.google.gerrit.server.update.UpdateException; 28 : import com.google.inject.Inject; 29 : import com.google.inject.Singleton; 30 : import java.io.IOException; 31 : import java.util.LinkedHashSet; 32 : import java.util.Map; 33 : import org.eclipse.jgit.transport.ReceiveCommand; 34 : 35 : public class SubmoduleOp { 36 : 37 : @Singleton 38 : public static class Factory { 39 : private final SubscriptionGraph.Factory subscriptionGraphFactory; 40 : private final SubmoduleCommits.Factory submoduleCommitsFactory; 41 : 42 : @Inject 43 : Factory( 44 : SubscriptionGraph.Factory subscriptionGraphFactory, 45 142 : SubmoduleCommits.Factory submoduleCommitsFactory) { 46 142 : this.subscriptionGraphFactory = subscriptionGraphFactory; 47 142 : this.submoduleCommitsFactory = submoduleCommitsFactory; 48 142 : } 49 : 50 : public SubmoduleOp create( 51 : Map<BranchNameKey, ReceiveCommand> updatedBranches, MergeOpRepoManager orm) 52 : throws SubmoduleConflictException { 53 68 : return new SubmoduleOp( 54 : updatedBranches, 55 : orm, 56 68 : subscriptionGraphFactory.compute(updatedBranches.keySet(), orm), 57 68 : submoduleCommitsFactory.create(orm)); 58 : } 59 : } 60 : 61 : private final Map<BranchNameKey, ReceiveCommand> updatedBranches; 62 : private final MergeOpRepoManager orm; 63 : private final SubscriptionGraph subscriptionGraph; 64 : private final SubmoduleCommits submoduleCommits; 65 : private final UpdateOrderCalculator updateOrderCalculator; 66 : 67 : private SubmoduleOp( 68 : Map<BranchNameKey, ReceiveCommand> updatedBranches, 69 : MergeOpRepoManager orm, 70 : SubscriptionGraph subscriptionGraph, 71 68 : SubmoduleCommits submoduleCommits) { 72 68 : this.updatedBranches = updatedBranches; 73 68 : this.orm = orm; 74 68 : this.subscriptionGraph = subscriptionGraph; 75 68 : this.submoduleCommits = submoduleCommits; 76 68 : this.updateOrderCalculator = new UpdateOrderCalculator(subscriptionGraph); 77 68 : } 78 : 79 : public void updateSuperProjects(boolean dryrun) throws RestApiException { 80 68 : ImmutableSet<Project.NameKey> projects = updateOrderCalculator.getProjectsInOrder(); 81 68 : if (projects == null) { 82 0 : return; 83 : } 84 : 85 68 : if (dryrun) { 86 : // On dryrun, the refs hasn't been updated. 87 : // force the new tips on submoduleCommits 88 0 : forceRefTips(updatedBranches, submoduleCommits); 89 : } 90 : 91 68 : LinkedHashSet<Project.NameKey> superProjects = new LinkedHashSet<>(); 92 : try { 93 68 : GitlinkOp.Factory gitlinkOpFactory = 94 : new GitlinkOp.Factory(submoduleCommits, subscriptionGraph); 95 68 : for (Project.NameKey project : projects) { 96 : // only need superprojects 97 68 : if (subscriptionGraph.isAffectedSuperProject(project)) { 98 2 : superProjects.add(project); 99 : // get a new BatchUpdate for the super project 100 2 : OpenRepo or = orm.getRepo(project); 101 2 : for (BranchNameKey branch : subscriptionGraph.getAffectedSuperBranches(project)) { 102 2 : or.getUpdate().addRepoOnlyOp(gitlinkOpFactory.create(branch)); 103 2 : } 104 : } 105 68 : } 106 68 : BatchUpdate.execute( 107 68 : orm.batchUpdates(superProjects, /* refLogMessage= */ "merged"), 108 68 : ImmutableList.of(), 109 : dryrun); 110 0 : } catch (UpdateException | IOException | NoSuchProjectException e) { 111 0 : throw new StorageException("Cannot update gitlinks", e); 112 68 : } 113 68 : } 114 : 115 : private void forceRefTips( 116 : Map<BranchNameKey, ReceiveCommand> updatedBranches, SubmoduleCommits submoduleCommits) { 117 : // This is dryrun, all commands succeeded (no need to filter success). 118 0 : for (Map.Entry<BranchNameKey, ReceiveCommand> updateBranch : updatedBranches.entrySet()) { 119 : try { 120 0 : ReceiveCommand command = updateBranch.getValue(); 121 0 : if (command.getType() == ReceiveCommand.Type.DELETE) { 122 0 : continue; 123 : } 124 : 125 0 : BranchNameKey branchNameKey = updateBranch.getKey(); 126 0 : OpenRepo openRepo = orm.getRepo(branchNameKey.project()); 127 0 : CodeReviewCommit fakeTip = openRepo.rw.parseCommit(command.getNewId()); 128 0 : submoduleCommits.addBranchTip(branchNameKey, fakeTip); 129 0 : } catch (NoSuchProjectException | IOException e) { 130 0 : throw new StorageException("Cannot find branch tip target in dryrun", e); 131 0 : } 132 0 : } 133 0 : } 134 : }