View Javadoc

1   /*
2    * #%L
3    * JavaHg
4    * %%
5    * Copyright (C) 2011 aragost Trifork ag
6    * %%
7    * Permission is hereby granted, free of charge, to any person obtaining a copy
8    * of this software and associated documentation files (the "Software"), to deal
9    * in the Software without restriction, including without limitation the rights
10   * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11   * copies of the Software, and to permit persons to whom the Software is
12   * furnished to do so, subject to the following conditions:
13   * 
14   * The above copyright notice and this permission notice shall be included in
15   * all copies or substantial portions of the Software.
16   * 
17   * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18   * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19   * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20   * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21   * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22   * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23   * THE SOFTWARE.
24   * #L%
25   */
26  package com.aragost.javahg.commands;
27  
28  import java.io.IOException;
29  
30  import com.aragost.javahg.Changeset;
31  import com.aragost.javahg.Repository;
32  import com.aragost.javahg.commands.flags.GraftCommandFlags;
33  import com.aragost.javahg.internals.HgInputStream;
34  import com.aragost.javahg.internals.RuntimeIOException;
35  import com.aragost.javahg.merge.GraftContext;
36  
37  /**
38   * Command class for executing <tt>hg graft</tt>. Set flags from
39   * {@link GraftCommandFlags} and call the {@link #execute} method.
40   */
41  public class GraftCommand extends GraftCommandFlags {
42  
43      private boolean hasConflicts = false;
44      private boolean somethingSkipped = false;
45  
46      /**
47       * @param repository
48       *            the repository associated with this command.
49       */
50      public GraftCommand(Repository repository) {
51          super(repository);
52          cmdAppend("-y");
53          cmdAppend("--tool", "internal:fail");
54      }
55  
56      @Override
57      public boolean isSuccessful() {
58          return super.isSuccessful() || this.hasConflicts || this.somethingSkipped;
59      }
60  
61      /**
62       * Run <tt>hg graft</tt> with the specified revisions.
63       * <p>
64       * If the grafting is succesful null is return. Otherwise a
65       * MergeContext is return where the conflicts can be inspected and
66       * resolved.
67       * 
68       * @param changeset
69       *            the changeset to graft
70       */
71      public GraftContext execute(Changeset changeset) {
72          Repository repo = getRepository();
73          repo.lock();
74          HgInputStream stream = launchStream(changeset.getNode());
75          try {
76              if (stream.match("grafting revision ".getBytes())) {
77                  int rev = stream.revisionUpTo('\n');
78                  GraftContext ctx = new GraftContext(this, rev);
79                  if (!stream.isEof()) {
80                      ctx.processStream(stream, true);
81                  }
82                  stream.consumeAll();
83                  boolean flagOrKeepDeleteConflicts = !ctx.getFlagConflicts().isEmpty()
84                          || !ctx.getKeepDeleteConflicts().isEmpty();
85                  if (getReturnCode() == -1 && this.hasConflicts || flagOrKeepDeleteConflicts) {
86                      if (flagOrKeepDeleteConflicts && ctx.getMergeConflicts().isEmpty()) {
87                          // graft has actually made a new changeset,
88                          // but
89                          // there is actually flag conflict or
90                          // keep/delete
91                          // conflict. So rollback the changeset.
92                          Changeset rollbackChangeset = repo.tip();
93                          if (!changeset.getNode().equals(rollbackChangeset.getExtra().getString("source"))) {
94                              throw new IllegalStateException("Current tip is not grafted from expected changeset");
95                          }
96                          RollbackCommand.on(repo).execute();
97                          ctx.setRollbackChangeset(rollbackChangeset);
98                      }
99                      return ctx;
100                 } else {
101                     return null;
102                 }
103             } else {
104                 return null;
105             }
106         } catch (IOException e) {
107             throw new RuntimeIOException(e);
108         } finally {
109             repo.unlock();
110         }
111     }
112 
113     /**
114      * Execute the graft command with the continue flag.
115      * 
116      * @return true if a new changeset was created, false if for some
117      *         reason graft did not succeed
118      */
119     public boolean executeContinue() {
120         launchString("--continue");
121         return getReturnCode() == 0;
122     }
123 
124     @Override
125     protected void doneHook() {
126         String errorString = getErrorString();
127         this.hasConflicts = errorString.indexOf("abort: unresolved conflicts, can't continue") >= 0
128                 || errorString.indexOf("abort: unresolved merge conflicts (see hg help resolve)") >= 0;
129         this.somethingSkipped = errorString.indexOf("skipping ancestor revision ") >= 0;
130     }
131 
132     @Override
133     protected void clear() {
134         super.clear();
135         this.hasConflicts = false;
136         this.somethingSkipped = false;
137     }
138 
139 }