1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package com.meltmedia.cadmium.cli;
17
18 import java.io.IOException;
19 import java.net.URI;
20 import java.net.URISyntaxException;
21 import java.util.List;
22 import java.util.regex.Matcher;
23 import java.util.regex.Pattern;
24
25 import org.apache.http.HttpEntity;
26 import org.apache.http.HttpResponse;
27 import org.apache.http.HttpStatus;
28 import org.apache.http.client.ClientProtocolException;
29 import org.apache.http.client.HttpClient;
30 import org.apache.http.client.methods.HttpGet;
31 import org.apache.http.client.utils.URIBuilder;
32 import org.apache.http.impl.client.DefaultHttpClient;
33 import org.apache.http.util.EntityUtils;
34
35 import com.beust.jcommander.Parameter;
36 import com.beust.jcommander.Parameters;
37 import com.google.gson.Gson;
38 import com.google.gson.reflect.TypeToken;
39 import com.meltmedia.cadmium.core.history.HistoryEntry;
40
41
42
43
44
45
46
47 @Parameters(commandDescription = "Lists history for a given site in human readable form.", separators="=")
48 public class HistoryCommand extends AbstractAuthorizedOnly implements CliCommand {
49 private static final Pattern URI_PATTERN = Pattern.compile("^(http[s]{0,1}://.*)$");
50
51 @Parameter(names="-n", description="Limits number of history items returned.", required=false)
52 private Integer limit = -1;
53
54 @Parameter(names="-r", description="Filters out non revertible history items from list.", required=false)
55 private boolean filter = false;
56
57 @Parameter(description="Site", required=true)
58 private List<String> site;
59
60 public void execute() throws Exception {
61 String siteUri = getSecureBaseUrl(site.get(0));
62 Matcher siteMatcher = URI_PATTERN.matcher(siteUri);
63 if(siteMatcher.matches()) {
64 siteUri = siteMatcher.group(1);
65
66 System.out.println("Showing history for "+siteUri+":");
67
68 List<HistoryEntry> history = getHistory(siteUri, limit, filter, token);
69
70 displayHistory(history, false, null);
71 } else {
72 System.err.println("Invalid value for site parameter!");
73 System.exit(1);
74 }
75 }
76
77
78
79
80
81
82
83 public static void displayHistory(List<HistoryEntry> history, boolean filter, Integer limitHistory) {
84 if(history != null && history.size() > 0) {
85 System.console().format("%7s|%7s|%12s|%7s|%14s|%52s|%18s|%42s|%24s|%6s|%6s|%6s|%6s\n", "Index", "Type", "Date", "Time", "User", "Repository", "Branch", "Revision", "Time Live", "Maint", "Revert", "Done", "Fail");
86 for(int i=0; i<218; i++) {
87 System.out.print("-");
88 }
89 System.out.println();
90 boolean showing = false;
91 for(HistoryEntry entry : history) {
92 if(!filter || entry.isRevertible()) {
93 if(limitHistory == null || limitHistory-- > 0) {
94 showing = true;
95 System.console().format("%7d|%7s|%4tm/%<2td/%<4tY|%<4tH:%<2tM|%14s|%52s|%18s|%42s|%24s|%6b|%6b|%6s|%6s\n",
96 entry.getIndex(),
97 entry.getType(),
98 entry.getTimestamp(),
99 entry.getOpenId(),
100 entry.getRepoUrl(),
101 entry.getBranch(),
102 entry.getRevision(),
103 formatTimeLive(entry.getTimeLive() == 0 ? System.currentTimeMillis() - entry.getTimestamp().getTime() : entry.getTimeLive()),
104 entry.isMaintenance(),
105 entry.isRevertible(),
106 entry.isFinished(),
107 entry.isFailed());
108 printComments(entry.getComment());
109 }
110 }
111 }
112 if(!showing) {
113 System.out.println("No history to show");
114 }
115 } else {
116 System.out.println("No history to show");
117 }
118 }
119
120
121
122
123
124
125
126
127
128
129 public static void waitForToken(String siteUri, String token, Long since, Long timeout) throws Exception {
130
131 if(!siteUri.endsWith("/system/history")) {
132 siteUri += "/system/history";
133 }
134 siteUri += "/" + token;
135 if(since != null) {
136 siteUri += "/" + since;
137 }
138
139 HttpClient httpClient = setTrustAllSSLCerts(new DefaultHttpClient());
140 HttpGet get = new HttpGet(siteUri);
141 Long currentTime = System.currentTimeMillis();
142 Long timeoutTime = currentTime + timeout;
143 do {
144 currentTime = System.currentTimeMillis();
145
146 HttpResponse resp = httpClient.execute(get);
147 if(resp.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
148 String response = EntityUtils.toString(resp.getEntity());
149 if(response != null && response.trim().equalsIgnoreCase("true")) {
150 return;
151 } else {
152 Thread.sleep(1000l);
153 }
154 } else {
155 String errorResponse = EntityUtils.toString(resp.getEntity());
156 if(errorResponse != null) {
157 throw new Exception(errorResponse.trim());
158 } else {
159 throw new Exception("Command failed!");
160 }
161 }
162 } while(currentTime < timeoutTime);
163 if(currentTime >= timeoutTime) {
164 throw new Exception("Timed out waiting for command to complete!");
165 }
166 }
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183 public static List<HistoryEntry> getHistory(String siteUri, int limit, boolean filter, String token)
184 throws URISyntaxException, IOException, ClientProtocolException, Exception {
185
186 if(!siteUri.endsWith("/system/history")) {
187 siteUri += "/system/history";
188 }
189
190 List<HistoryEntry> history = null;
191
192 HttpClient httpClient = setTrustAllSSLCerts(new DefaultHttpClient());
193 HttpGet get = null;
194 try {
195 URIBuilder uriBuilder = new URIBuilder(siteUri);
196 if(limit > 0) {
197 uriBuilder.addParameter("limit", limit+"");
198 }
199 if(filter) {
200 uriBuilder.addParameter("filter", filter+"");
201 }
202 URI uri = uriBuilder.build();
203 get = new HttpGet(uri);
204 addAuthHeader(token, get);
205
206 HttpResponse resp = httpClient.execute(get);
207 if(resp.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
208 HttpEntity entity = resp.getEntity();
209 if(entity.getContentType().getValue().equals("application/json")) {
210 String responseContent = EntityUtils.toString(entity);
211
212 history = new Gson().fromJson(responseContent, new TypeToken<List<HistoryEntry>>() {}.getType());
213 } else {
214 System.err.println("Invalid response content type ["+entity.getContentType().getValue()+"]");
215 System.exit(1);
216 }
217 } else {
218 System.err.println("Request failed due to a ["+resp.getStatusLine().getStatusCode()+":"+resp.getStatusLine().getReasonPhrase()+"] response from the remote server.");
219 System.exit(1);
220 }
221 } finally {
222 if(get != null) {
223 get.releaseConnection();
224 }
225 }
226 return history;
227 }
228
229
230
231
232
233
234 private static void printComments(String comment) {
235 int index = 0;
236 int nextIndex = 154;
237 while(index < comment.length()) {
238 nextIndex = nextIndex <= comment.length() ? nextIndex : comment.length();
239 String commentSegment = comment.substring(index, nextIndex);
240 int lastSpace = commentSegment.lastIndexOf(' ');
241 int lastNewLine = commentSegment.indexOf('\n');
242 char lastChar = ' ';
243 if(nextIndex < comment.length() ) {
244 lastChar = comment.charAt(nextIndex);
245 }
246 if(lastNewLine > 0) {
247 nextIndex = index + lastNewLine;
248 commentSegment = comment.substring(index, nextIndex);
249 } else
250 if(Character.isWhitespace(lastChar)) {
251
252 } else
253 if(lastSpace > 0) {
254 nextIndex = index + lastSpace;
255 commentSegment = comment.substring(index, nextIndex);
256 }
257 System.out.println(" " + commentSegment);
258 index = nextIndex;
259 if(lastNewLine > 0 || lastSpace > 0) {
260 index++;
261 }
262 nextIndex = index + 154;
263 }
264 }
265
266
267
268
269
270
271
272 private static String formatTimeLive(long timeLive) {
273 String timeString = "ms";
274 timeString = (timeLive % 1000) + timeString;
275 timeLive = timeLive / 1000;
276 if(timeLive > 0) {
277 timeString = (timeLive % 60) + "s" + timeString;
278 timeLive = timeLive / 60;
279 if(timeLive > 0) {
280 timeString = (timeLive % 60) + "m" + timeString;
281 timeLive = timeLive / 60;
282 if(timeLive > 0) {
283 timeString = (timeLive % 24) + "h" + timeString;
284 timeLive = timeLive / 24;
285 if(timeLive > 0) {
286 timeString = (timeLive) + "d" + timeString;
287 }
288 }
289 }
290 }
291 return timeString;
292 }
293
294 @Override
295 public String getCommandName() {
296 return "history";
297 }
298
299 }