TW-58811 Support 'update-ref --stdin'
[teamcity/git-plugin.git] / git-agent / src / jetbrains / buildServer / buildTriggers / vcs / git / agent / NativeGitFacade.java
1 /*
2  * Copyright 2000-2018 JetBrains s.r.o.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 package jetbrains.buildServer.buildTriggers.vcs.git.agent;
18
19 import com.intellij.execution.configurations.GeneralCommandLine;
20 import com.intellij.openapi.util.SystemInfo;
21 import com.intellij.openapi.util.io.FileUtil;
22 import jetbrains.buildServer.ExecResult;
23 import jetbrains.buildServer.SimpleCommandLineProcessRunner;
24 import jetbrains.buildServer.buildTriggers.vcs.git.agent.command.*;
25 import jetbrains.buildServer.buildTriggers.vcs.git.agent.command.impl.*;
26 import jetbrains.buildServer.ssh.VcsRootSshKeyManager;
27 import jetbrains.buildServer.util.StringUtil;
28 import jetbrains.buildServer.vcs.VcsException;
29 import org.jetbrains.annotations.NotNull;
30 import org.jetbrains.annotations.Nullable;
31
32 import java.io.File;
33 import java.util.HashMap;
34 import java.util.Map;
35
36 import static com.intellij.openapi.util.text.StringUtil.isEmpty;
37
38 /**
39  * @author dmitry.neverov
40  */
41 public class NativeGitFacade implements GitFacade {
42
43   private final GitAgentSSHService mySsh;
44   private final ScriptGen myScriptGen;
45   private final String myGitPath;
46   private final GitVersion myGitVersion;
47   private final File myRepositoryDir;
48   private final File myTmpDir;
49   private final boolean myDeleteTempFiles;
50   private final GitProgressLogger myLogger;
51   private final GitExec myGitExec;
52   private final Map<String, String> myEnv;
53   private final Context myCtx;
54   private VcsRootSshKeyManager mySshKeyManager;
55   private boolean myUseGitSshCommand = true;
56
57   public NativeGitFacade(@NotNull GitAgentSSHService ssh,
58                          @NotNull String gitPath,
59                          @NotNull GitVersion gitVersion,
60                          @NotNull File repositoryDir,
61                          @NotNull File tmpDir,
62                          boolean deleteTempFiles,
63                          @NotNull GitProgressLogger logger,
64                          @NotNull GitExec gitExec,
65                          @NotNull Map<String, String> env,
66                          @NotNull Context ctx) {
67     mySsh = ssh;
68     myTmpDir = tmpDir;
69     myScriptGen = makeScriptGen();
70     myGitPath = gitPath;
71     myGitVersion = gitVersion;
72     myRepositoryDir = repositoryDir;
73     myDeleteTempFiles = deleteTempFiles;
74     myLogger = logger;
75     myGitExec = gitExec;
76     myEnv = env;
77     myCtx = ctx;
78   }
79
80   public NativeGitFacade(@NotNull String gitPath, @NotNull GitProgressLogger logger) {
81     this(gitPath, logger, new File("."));
82   }
83
84
85   public NativeGitFacade(@NotNull String gitPath,
86                          @NotNull GitProgressLogger logger,
87                          @NotNull File repositoryDir) {
88     mySsh = null;
89     myTmpDir = new File(FileUtil.getTempDirectory());
90     myScriptGen = makeScriptGen();
91     myGitPath = gitPath;
92     myGitVersion = GitVersion.MIN;
93     myRepositoryDir = repositoryDir;
94     myDeleteTempFiles = true;
95     myLogger = logger;
96     myGitExec = null;
97     myEnv = new HashMap<String, String>(0);
98     myCtx = new NoBuildContext();
99   }
100
101
102   @NotNull
103   public InitCommand init() {
104     return new InitCommandImpl(createCommandLine());
105   }
106
107   @NotNull
108   public CreateBranchCommand createBranch() {
109     return new CreateBranchCommandImpl(createCommandLine());
110   }
111
112   @NotNull
113   public DeleteBranchCommand deleteBranch() {
114     return new DeleteBranchCommandImpl(createCommandLine());
115   }
116
117   @NotNull
118   public DeleteTagCommand deleteTag() {
119     return new DeleteTagCommandImpl(createCommandLine());
120   }
121
122   @NotNull
123   public AddRemoteCommand addRemote() {
124     return new AddRemoteCommandImpl(createCommandLine());
125   }
126
127   @NotNull
128   public CleanCommand clean() {
129     return new CleanCommandImpl(createCommandLine());
130   }
131
132   @NotNull
133   public ResetCommand reset() {
134     return new ResetCommandImpl(createCommandLine());
135   }
136
137   @NotNull
138   public UpdateRefCommand updateRef() {
139     return new UpdateRefCommandImpl(createCommandLine());
140   }
141
142   @NotNull
143   public UpdateRefBatchCommand updateRefBatch() {
144     return new UpdateRefBatchCommandImpl(createCommandLine());
145   }
146
147   @NotNull
148   public CheckoutCommand checkout() {
149     return new CheckoutCommandImpl(createCommandLine());
150   }
151
152   @NotNull
153   public GetConfigCommand getConfig() {
154     return new GetConfigCommandImpl(createCommandLine());
155   }
156
157   @NotNull
158   public SetConfigCommand setConfig() {
159     return new SetConfigCommandImpl(createCommandLine());
160   }
161
162   @NotNull
163   public FetchCommand fetch() {
164     return new FetchCommandImpl(createCommandLine());
165   }
166
167   @NotNull
168   public LogCommand log() {
169     return new LogCommandImpl(createCommandLine());
170   }
171
172   @NotNull
173   public SubmoduleInitCommand submoduleInit() {
174     return new SubmoduleInitCommandImpl(createCommandLine());
175   }
176
177   @NotNull
178   public SubmoduleSyncCommand submoduleSync() {
179     return new SubmoduleSyncCommandImpl(createCommandLine());
180   }
181
182   @NotNull
183   public SubmoduleUpdateCommand submoduleUpdate() {
184     return new SubmoduleUpdateCommandImpl(createCommandLine());
185   }
186
187   @NotNull
188   public ShowRefCommand showRef() {
189     return new ShowRefCommandImpl(createCommandLine());
190   }
191
192   @NotNull
193   public VersionCommand version() {
194     return new VersionCommandImpl(createCommandLine());
195   }
196
197   @NotNull
198   public LsRemoteCommand lsRemote() {
199     return new LsRemoteCommandImpl(createCommandLine());
200   }
201
202   @NotNull
203   public PackRefs packRefs() {
204     return new PackRefsImpl(createCommandLine());
205   }
206
207   @NotNull
208   public GcCommand gc() {
209     return new GcCommandImpl(createCommandLine());
210   }
211
212   @NotNull
213   public RepackCommand repack() {
214     return new RepackCommandImpl(createCommandLine());
215   }
216
217   @NotNull
218   @Override
219   public UpdateIndexCommand updateIndex() {
220     return new UpdateIndexCommandImpl(createCommandLine());
221   }
222
223   @NotNull
224   @Override
225   public DiffCommand diff() {
226     return new DiffCommandImpl(createCommandLine());
227   }
228
229   @NotNull
230   public Branches listBranches() throws VcsException {
231     GitCommandLine cmd = createCommandLine();
232     cmd.addParameter("branch");
233     ExecResult r = CommandUtil.runCommand(cmd);
234     CommandUtil.failIfNotEmptyStdErr(cmd, r);
235     return parseBranches(r.getStdout());
236   }
237
238   @NotNull
239   public SetUpstreamCommand setUpstream(@NotNull String localBranch, @NotNull String upstreamBranch) throws VcsException {
240     return new SetUpstreamCommandImpl(createCommandLine(), localBranch, upstreamBranch);
241   }
242
243   @NotNull
244   public String resolvePath(@NotNull File f) throws VcsException {
245     try {
246       if (myGitExec.isCygwin()) {
247         String cygwinBin = myGitExec.getCygwinBinPath();
248         GeneralCommandLine cmd = new GeneralCommandLine();
249         cmd.setWorkDirectory(cygwinBin);
250         cmd.setExePath(new File(cygwinBin, "cygpath.exe").getCanonicalPath());
251         cmd.addParameter(f.getCanonicalPath());
252         ExecResult res = SimpleCommandLineProcessRunner.runCommandSecure(cmd, cmd.getCommandLineString(), null, new ProcessTimeoutCallback(30));
253         Throwable error = res.getException();
254         if (error != null)
255           throw error;
256         return res.getStdout().trim();
257       } else {
258         return f.getCanonicalPath();
259       }
260     } catch (Throwable e) {
261       throw new VcsException("Error while resolving path " + f.getAbsolutePath(), e);
262     }
263   }
264
265   @NotNull
266   private GitCommandLine createCommandLine() {
267     GitCommandLine cmd = new GitCommandLine(mySsh, myScriptGen, myTmpDir, myDeleteTempFiles, myLogger, myGitVersion, myEnv, myCtx);
268     cmd.setExePath(myGitPath);
269     cmd.setWorkingDirectory(myRepositoryDir);
270     cmd.setSshKeyManager(mySshKeyManager);
271     cmd.setUseGitSshCommand(myUseGitSshCommand);
272     return cmd;
273   }
274
275   public void setSshKeyManager(@Nullable VcsRootSshKeyManager sshKeyManager) {
276     mySshKeyManager = sshKeyManager;
277   }
278
279   public void setUseGitSshCommand(boolean useGitSshCommand) {
280     myUseGitSshCommand = useGitSshCommand;
281   }
282
283   @NotNull
284   private ScriptGen makeScriptGen() {
285     return SystemInfo.isUnix ? new UnixScriptGen(myTmpDir, new EscapeEchoArgumentUnix()) : new WinScriptGen(myTmpDir, new EscapeEchoArgumentWin());
286   }
287
288
289   @NotNull
290   private Branches parseBranches(String out) {
291     Branches branches = new Branches();
292     for (String l : StringUtil.splitByLines(out)) {
293       String line = l.trim();
294       if (isEmpty(line))
295         continue;
296       boolean currentBranch = line.startsWith("* ");
297       String branchName = currentBranch ? line.substring(2).trim() : line;
298       branches.addBranch(branchName, currentBranch);
299     }
300     return branches;
301   }
302
303
304   @NotNull
305   public ScriptGen getScriptGen() {
306     return myScriptGen;
307   }
308 }