mercurialeclipse / file revision
summary |
shortlog |
changelog |
tags | edit |
manifest |
changeset |
file |
revisions |
annotate |
diff |
raw
src/com/vectrace/MercurialEclipse/commands/HgCommand.java
| author | Jerome Negre <jerome+hg@jnegre.org> |
| Sun Apr 06 20:37:11 2008 +0200 (15 months ago) | |
| changeset 253 | c890f1558210 |
| parent 231 | 95b3bb68de86 |
| permissions | -rw-r--r-- |
30s default timeout
1 package com.vectrace.MercurialEclipse.commands;
2
3 import java.io.BufferedInputStream;
4 import java.io.ByteArrayOutputStream;
5 import java.io.File;
6 import java.io.IOException;
7 import java.io.InputStream;
8 import java.io.PrintStream;
9 import java.util.ArrayList;
10 import java.util.HashMap;
11 import java.util.List;
12 import java.util.Map;
13
14 import org.eclipse.core.resources.IContainer;
15 import org.eclipse.core.resources.IProject;
16 import org.eclipse.core.resources.IResource;
17
18 import com.vectrace.MercurialEclipse.MercurialEclipsePlugin;
19 import com.vectrace.MercurialEclipse.exception.HgException;
20 import com.vectrace.MercurialEclipse.preferences.MercurialPreferenceConstants;
21 import com.vectrace.MercurialEclipse.team.MercurialUtilities;
22
23 /**
24 *
25 * @author Jerome Negre <jerome+hg@jnegre.org>
26 */
27 public class HgCommand {
28
29 //some OSes (windows...) are limited, use a hard-coded value
30 //to degrade gracefully
31 //TODO have an OS-dependent value
32 public static final int MAX_PARAMS = 120;
33
34 private static PrintStream console = new PrintStream(MercurialUtilities.getMercurialConsole().newOutputStream());
35
36 protected static class InputStreamConsumer extends Thread {
37 private final InputStream stream;
38 private byte[] output;
39
40 public InputStreamConsumer(InputStream stream) {
41 this.stream = new BufferedInputStream(stream);
42 }
43
44 @Override
45 public void run() {
46 try {
47 int length;
48 byte[] buffer = new byte[1024];
49 ByteArrayOutputStream output = new ByteArrayOutputStream();
50 while((length = stream.read(buffer)) != -1) {
51 output.write(buffer, 0, length);
52 }
53 stream.close();
54 this.output = output.toByteArray();
55 } catch (IOException e) {
56 // TODO report the error to the caller thread
57 MercurialEclipsePlugin.logError(e);
58 }
59 }
60
61 public byte[] getBytes() {
62 return output;
63 }
64
65 }
66
67 private final String command;
68 private final File workingDir;
69 private final boolean escapeFiles;
70 private final List<String> options = new ArrayList<String>();
71 private final List<String> files = new ArrayList<String>();
72
73 protected HgCommand(String command, File workingDir, boolean escapeFiles) {
74 this.command = command;
75 this.workingDir = workingDir;
76 this.escapeFiles = escapeFiles;
77 }
78
79 protected HgCommand(String command, IContainer container, boolean escapeFiles) {
80 this(
81 command,
82 container.getLocation().toFile(),
83 escapeFiles);
84 }
85
86 protected HgCommand(String command, boolean escapeFiles) {
87 this(command, (File)null, escapeFiles);
88 }
89
90 protected String getHgExecutable() {
91 return MercurialEclipsePlugin.getDefault()
92 .getPreferenceStore()
93 .getString(MercurialPreferenceConstants.MERCURIAL_EXECUTABLE);
94 }
95
96 protected String getDefaultUserName() {
97 return MercurialEclipsePlugin.getDefault()
98 .getPreferenceStore()
99 .getString(MercurialPreferenceConstants.MERCURIAL_USERNAME);
100 }
101
102 protected List<String> getCommands() {
103 ArrayList<String> result = new ArrayList<String>();
104 result.add(getHgExecutable());
105 result.add(command);
106 result.addAll(options);
107 if(escapeFiles && !files.isEmpty()) {
108 result.add("--");
109 }
110 result.addAll(files);
111 console.println("Command: ("+result.size()+") "+result);
112 //TODO check that length <= MAX_PARAMS
113 return result;
114 }
115
116 protected void addOptions(String... options) {
117 for(String option: options) {
118 this.options.add(option);
119 }
120 }
121
122 protected void addUserName(String user) {
123 this.options.add("-u");
124 this.options.add(user!=null?user:getDefaultUserName());
125 }
126
127 protected void addFiles(String... files) {
128 for(String file: files) {
129 this.files.add(file);
130 }
131 }
132
133 protected void addFiles(IResource... resources) {
134 for(IResource resource: resources) {
135 this.files.add(resource.getLocation().toOSString());
136 }
137 }
138
139 protected void addFiles(List<? extends IResource> resources) {
140 for(IResource resource: resources) {
141 this.files.add(resource.getLocation().toOSString());
142 }
143 }
144
145 /* TODO the timeout should be configurable, for instance a remote
146 * pull will likely exceed the 10 seconds limit
147 */
148 protected byte[] executeToBytes() throws HgException {
149 try {
150 long start = System.currentTimeMillis();
151 ProcessBuilder builder = new ProcessBuilder(getCommands());
152 builder.redirectErrorStream(true); // makes my life easier
153 if(workingDir != null) {
154 builder.directory(workingDir);
155 }
156 Process process = builder.start();
157 InputStreamConsumer consumer = new InputStreamConsumer(process.getInputStream());
158 consumer.start();
159 consumer.join(30000); // 30 seconds timeout
160 if(!consumer.isAlive()) {
161 if(process.waitFor() == 0) {
162 console.println("Done in "+(System.currentTimeMillis()-start)+" ms");
163 return consumer.getBytes();
164 }
165 throw new HgException("Process error, return code: "+process.exitValue()+", message: "+new String(consumer.getBytes()));
166 }
167 process.destroy();
168 throw new HgException("Process timeout");
169 } catch (IOException e) {
170 throw new HgException(e.getMessage(), e);
171 } catch (InterruptedException e) {
172 throw new HgException(e.getMessage(), e);
173 }
174 }
175
176 protected String executeToString() throws HgException {
177 return new String(executeToBytes());
178 }
179
180 protected static Map<IProject, List<IResource>> groupByProject(List<IResource> resources) {
181 Map<IProject, List<IResource>> result = new HashMap<IProject, List<IResource>>();
182 for(IResource resource : resources) {
183 List<IResource> list = result.get(resource.getProject());
184 if(list == null) {
185 list = new ArrayList<IResource>();
186 result.put(resource.getProject(), list);
187 }
188 list.add(resource);
189 }
190 return result;
191 }
192 }
