summaryrefslogtreecommitdiff
path: root/plugins/git4idea/src/git4idea/commands/GitCommand.java
blob: 27beb50100c1ad51d2f7fc603f5911179e35de98 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
/*
 * Copyright 2000-2009 JetBrains s.r.o.
 *
 * 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 git4idea.commands;

import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;

/**
 * <p>
 *   The descriptor of git command.
 * </p>
 * <p>
 *   It contains policy information about locking which is handled in {@link GitHandler#runInCurrentThread(java.lang.Runnable)} to prevent
 *   simultaneous Git commands conflict on the index.lock file.
 *   write-commands can't be executed simultaneously, but a write-command doesn't prevent read-commands to execute.
 * </p>
 * <p>
 *   A lock-policy can be different for a single command, for example, {@code git stash} may change the index (and thus should hold the
 *   write lock), which {@code git stash list} doesn't (and therefore no lock is needed).
 * </p>
 */
public class GitCommand {

  public static final GitCommand ADD = write("add");
  public static final GitCommand BLAME = read("blame");
  public static final GitCommand BRANCH = read("branch");
  public static final GitCommand CHECKOUT = write("checkout");
  public static final GitCommand CHECK_ATTR = read("check-attr");
  public static final GitCommand COMMIT = write("commit");
  public static final GitCommand CONFIG = read("config");
  public static final GitCommand CHERRY = read("cherry");
  public static final GitCommand CHERRY_PICK = write("cherry-pick");
  public static final GitCommand CLONE = write("clone");
  public static final GitCommand DIFF = read("diff");
  public static final GitCommand FETCH = read("fetch");  // fetch is a read-command, because it doesn't modify the index
  public static final GitCommand INIT = write("init");
  public static final GitCommand LOG = read("log");
  public static final GitCommand LS_FILES = read("ls-files");
  public static final GitCommand LS_REMOTE = read("ls-remote");
  public static final GitCommand MERGE = write("merge");
  public static final GitCommand MERGE_BASE = read("merge-base");
  public static final GitCommand PULL = write("pull");
  public static final GitCommand PUSH = write("push");
  public static final GitCommand REBASE = writeSuspendable("rebase");
  public static final GitCommand REMOTE = read("remote");
  public static final GitCommand RESET = write("reset");
  public static final GitCommand REV_LIST = read("rev-list");
  public static final GitCommand REV_PARSE = read("rev-parse");
  public static final GitCommand RM = write("rm");
  public static final GitCommand SHOW = read("show");
  public static final GitCommand STASH = write("stash");
  public static final GitCommand STATUS = read("status");
  public static final GitCommand TAG = read("tag");
  public static final GitCommand UPDATE_INDEX = write("update-index");

  /**
   * Name of environment variable that specifies editor for the git
   */
  public static final String GIT_EDITOR_ENV = "GIT_EDITOR";

  enum LockingPolicy {
    READ,
    WRITE,
    WRITE_SUSPENDABLE,
  }

  @NotNull @NonNls private final String myName; // command name passed to git
  @NotNull private final LockingPolicy myLocking; // Locking policy for the command

  private GitCommand(@NotNull String name, @NotNull LockingPolicy lockingPolicy) {
    myLocking = lockingPolicy;
    myName = name;
  }

  /**
   * Copy constructor with other locking policy.
   */
  private GitCommand(@NotNull GitCommand command, @NotNull LockingPolicy lockingPolicy) {
    myName = command.name();
    myLocking = lockingPolicy;
  }

  /**
   * <p>Creates the clone of this git command, but with LockingPolicy different from the default one.</p>
   * <p>This can be used for commands, which are considered to be "write" commands in general, but can be "read" commands when a certain
   *    set of arguments is given ({@code git stash list}, for instance).</p>
   * <p>Use this constructor with care: specifying read-policy on a write operation may result in a conflict during simultaneous
   *    modification of index.</p>
   */
  @NotNull
  public GitCommand readLockingCommand() {
    return new GitCommand(this, LockingPolicy.READ);
  }

  @NotNull
  private static GitCommand read(@NotNull String name) {
    return new GitCommand(name, LockingPolicy.READ);
  }

  @NotNull
  private static GitCommand write(@NotNull String name) {
    return new GitCommand(name, LockingPolicy.WRITE);
  }

  @NotNull
  private static GitCommand writeSuspendable(@NotNull String name) {
    return new GitCommand(name, LockingPolicy.WRITE_SUSPENDABLE);
  }

  @NotNull
  public String name() {
    return myName;
  }

  @NotNull
  public LockingPolicy lockingPolicy() {
    return myLocking;
  }

  @Override
  public String toString() {
    return myName;
  }
}