f2cd73dff9bc5a13a789397dfd89d7a98621258c
[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 CheckoutCommand checkout() {
144     return new CheckoutCommandImpl(createCommandLine());
145   }
146
147   @NotNull
148   public GetConfigCommand getConfig() {
149     return new GetConfigCommandImpl(createCommandLine());
150   }
151
152   @NotNull
153   public SetConfigCommand setConfig() {
154     return new SetConfigCommandImpl(createCommandLine());
155   }
156
157   @NotNull
158   public FetchCommand fetch() {
159     return new FetchCommandImpl(createCommandLine());
160   }
161
162   @NotNull
163   public LogCommand log() {
164     return new LogCommandImpl(createCommandLine());
165   }
166
167   @NotNull
168   public SubmoduleInitCommand submoduleInit() {
169     return new SubmoduleInitCommandImpl(createCommandLine());
170   }
171
172   @NotNull
173   public SubmoduleSyncCommand submoduleSync() {
174     return new SubmoduleSyncCommandImpl(createCommandLine());
175   }
176
177   @NotNull
178   public SubmoduleUpdateCommand submoduleUpdate() {
179     return new SubmoduleUpdateCommandImpl(createCommandLine());
180   }
181
182   @NotNull
183   public ShowRefCommand showRef() {
184     return new ShowRefCommandImpl(createCommandLine());
185   }
186
187   @NotNull
188   public VersionCommand version() {
189     return new VersionCommandImpl(createCommandLine());
190   }
191
192   @NotNull
193   public LsRemoteCommand lsRemote() {
194     return new LsRemoteCommandImpl(createCommandLine());
195   }
196
197   @NotNull
198   public PackRefs packRefs() {
199     return new PackRefsImpl(createCommandLine());
200   }
201
202   @NotNull
203   public GcCommand gc() {
204     return new GcCommandImpl(createCommandLine());
205   }
206
207   @NotNull
208   public RepackCommand repack() {
209     return new RepackCommandImpl(createCommandLine());
210   }
211
212   @NotNull
213   @Override
214   public UpdateIndexCommand updateIndex() {
215     return new UpdateIndexCommandImpl(createCommandLine());
216   }
217
218   @NotNull
219   @Override
220   public DiffCommand diff() {
221     return new DiffCommandImpl(createCommandLine());
222   }
223
224   @NotNull
225   public Branches listBranches() throws VcsException {
226     GitCommandLine cmd = createCommandLine();
227     cmd.addParameter("branch");
228     ExecResult r = CommandUtil.runCommand(cmd);
229     CommandUtil.failIfNotEmptyStdErr(cmd, r);
230     return parseBranches(r.getStdout());
231   }
232
233   @NotNull
234   public SetUpstreamCommand setUpstream(@NotNull String localBranch, @NotNull String upstreamBranch) throws VcsException {
235     return new SetUpstreamCommandImpl(createCommandLine(), localBranch, upstreamBranch);
236   }
237
238   @NotNull
239   public String resolvePath(@NotNull File f) throws VcsException {
240     try {
241       if (myGitExec.isCygwin()) {
242         String cygwinBin = myGitExec.getCygwinBinPath();
243         GeneralCommandLine cmd = new GeneralCommandLine();
244         cmd.setWorkDirectory(cygwinBin);
245         cmd.setExePath(new File(cygwinBin, "cygpath.exe").getCanonicalPath());
246         cmd.addParameter(f.getCanonicalPath());
247         ExecResult res = SimpleCommandLineProcessRunner.runCommandSecure(cmd, cmd.getCommandLineString(), null, new ProcessTimeoutCallback(30));
248         Throwable error = res.getException();
249         if (error != null)
250           throw error;
251         return res.getStdout().trim();
252       } else {
253         return f.getCanonicalPath();
254       }
255     } catch (Throwable e) {
256       throw new VcsException("Error while resolving path " + f.getAbsolutePath(), e);
257     }
258   }
259
260   @NotNull
261   private GitCommandLine createCommandLine() {
262     GitCommandLine cmd = new GitCommandLine(mySsh, myScriptGen, myTmpDir, myDeleteTempFiles, myLogger, myGitVersion, myEnv, myCtx);
263     cmd.setExePath(myGitPath);
264     cmd.setWorkingDirectory(myRepositoryDir);
265     cmd.setSshKeyManager(mySshKeyManager);
266     cmd.setUseGitSshCommand(myUseGitSshCommand);
267     return cmd;
268   }
269
270   public void setSshKeyManager(@Nullable VcsRootSshKeyManager sshKeyManager) {
271     mySshKeyManager = sshKeyManager;
272   }
273
274   public void setUseGitSshCommand(boolean useGitSshCommand) {
275     myUseGitSshCommand = useGitSshCommand;
276   }
277
278   @NotNull
279   private ScriptGen makeScriptGen() {
280     return SystemInfo.isUnix ? new UnixScriptGen(myTmpDir, new EscapeEchoArgumentUnix()) : new WinScriptGen(myTmpDir, new EscapeEchoArgumentWin());
281   }
282
283
284   @NotNull
285   private Branches parseBranches(String out) {
286     Branches branches = new Branches();
287     for (String l : StringUtil.splitByLines(out)) {
288       String line = l.trim();
289       if (isEmpty(line))
290         continue;
291       boolean currentBranch = line.startsWith("* ");
292       String branchName = currentBranch ? line.substring(2).trim() : line;
293       branches.addBranch(branchName, currentBranch);
294     }
295     return branches;
296   }
297
298
299   @NotNull
300   public ScriptGen getScriptGen() {
301     return myScriptGen;
302   }
303 }