1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 package com.github.maven.plugins.site;
23
24 import static java.lang.Integer.MAX_VALUE;
25 import static org.eclipse.egit.github.core.Blob.ENCODING_BASE64;
26 import static org.eclipse.egit.github.core.TreeEntry.MODE_BLOB;
27 import static org.eclipse.egit.github.core.TreeEntry.TYPE_BLOB;
28 import static org.eclipse.egit.github.core.TypedResource.TYPE_COMMIT;
29
30 import com.github.maven.plugins.core.GitHubProjectMojo;
31 import com.github.maven.plugins.core.PathUtils;
32 import com.github.maven.plugins.core.StringUtils;
33
34 import java.io.ByteArrayOutputStream;
35 import java.io.File;
36 import java.io.FileInputStream;
37 import java.io.IOException;
38 import java.text.MessageFormat;
39 import java.util.ArrayList;
40 import java.util.Arrays;
41 import java.util.Collections;
42 import java.util.List;
43
44 import org.apache.maven.execution.MavenSession;
45 import org.apache.maven.plugin.MojoExecutionException;
46 import org.apache.maven.project.MavenProject;
47 import org.apache.maven.settings.Settings;
48 import org.eclipse.egit.github.core.Blob;
49 import org.eclipse.egit.github.core.Commit;
50 import org.eclipse.egit.github.core.Reference;
51 import org.eclipse.egit.github.core.RepositoryId;
52 import org.eclipse.egit.github.core.Tree;
53 import org.eclipse.egit.github.core.TreeEntry;
54 import org.eclipse.egit.github.core.TypedResource;
55 import org.eclipse.egit.github.core.client.RequestException;
56 import org.eclipse.egit.github.core.service.DataService;
57 import org.eclipse.egit.github.core.util.EncodingUtils;
58
59
60
61
62
63
64
65
66
67 public class SiteMojo extends GitHubProjectMojo {
68
69
70
71
72 public static final String BRANCH_DEFAULT = "refs/heads/gh-pages";
73
74
75
76
77 public static final String NO_JEKYLL_FILE = ".nojekyll";
78
79
80
81
82
83
84 private String branch = BRANCH_DEFAULT;
85
86
87
88
89
90
91 private String path;
92
93
94
95
96
97
98
99 private String message;
100
101
102
103
104
105
106 private String repositoryName;
107
108
109
110
111
112
113 private String repositoryOwner;
114
115
116
117
118
119
120
121 private String userName;
122
123
124
125
126
127
128
129 private String password;
130
131
132
133
134
135
136
137 private String oauth2Token;
138
139
140
141
142
143
144
145 private String host;
146
147
148
149
150
151
152
153
154 private String server;
155
156
157
158
159
160
161 private String[] includes;
162
163
164
165
166
167
168 private String[] excludes;
169
170
171
172
173
174
175
176
177 private File outputDirectory;
178
179
180
181
182
183
184
185 private MavenProject project;
186
187
188
189
190
191
192 private MavenSession session;
193
194
195
196
197
198
199 private Settings settings;
200
201
202
203
204
205
206 private boolean force;
207
208
209
210
211
212
213
214 private boolean noJekyll;
215
216
217
218
219
220
221
222 private boolean merge;
223
224
225
226
227
228
229
230
231 private boolean dryRun;
232
233
234
235
236
237
238
239
240 private boolean skip;
241
242
243
244
245
246
247
248
249
250
251 protected String createBlob(DataService service, RepositoryId repository,
252 String path) throws MojoExecutionException {
253 File file = new File(outputDirectory, path);
254 final long length = file.length();
255 final int size = length > MAX_VALUE ? MAX_VALUE : (int) length;
256 ByteArrayOutputStream output = new ByteArrayOutputStream(size);
257 FileInputStream stream = null;
258 try {
259 stream = new FileInputStream(file);
260 final byte[] buffer = new byte[8192];
261 int read;
262 while ((read = stream.read(buffer)) != -1)
263 output.write(buffer, 0, read);
264 } catch (IOException e) {
265 throw new MojoExecutionException("Error reading file: "
266 + getExceptionMessage(e), e);
267 } finally {
268 if (stream != null)
269 try {
270 stream.close();
271 } catch (IOException e) {
272 debug("Exception closing stream", e);
273 }
274 }
275
276 Blob blob = new Blob().setEncoding(ENCODING_BASE64);
277 String encoded = EncodingUtils.toBase64(output.toByteArray());
278 blob.setContent(encoded);
279
280 try {
281 if (isDebug())
282 debug(MessageFormat.format("Creating blob from {0}",
283 file.getAbsolutePath()));
284 if (!dryRun)
285 return service.createBlob(repository, blob);
286 else
287 return null;
288 } catch (IOException e) {
289 throw new MojoExecutionException("Error creating blob: "
290 + getExceptionMessage(e), e);
291 }
292 }
293
294 public void execute() throws MojoExecutionException {
295 if (skip) {
296 info("Github Site Plugin execution skipped");
297 return;
298 }
299
300 RepositoryId repository = getRepository(project, repositoryOwner,
301 repositoryName);
302
303 if (dryRun)
304 info("Dry run mode, repository will not be modified");
305
306
307 String baseDir = outputDirectory.getAbsolutePath();
308 String[] includePaths = StringUtils.removeEmpties(includes);
309 String[] excludePaths = StringUtils.removeEmpties(excludes);
310 if (isDebug())
311 debug(MessageFormat.format(
312 "Scanning {0} and including {1} and exluding {2}", baseDir,
313 Arrays.toString(includePaths),
314 Arrays.toString(excludePaths)));
315 String[] paths = PathUtils.getMatchingPaths(includePaths, excludePaths,
316 baseDir);
317
318 if (paths.length != 1)
319 info(MessageFormat.format("Creating {0} blobs", paths.length));
320 else
321 info("Creating 1 blob");
322 if (isDebug())
323 debug(MessageFormat.format("Scanned files to include: {0}",
324 Arrays.toString(paths)));
325
326 DataService service = new DataService(createClient(host, userName,
327 password, oauth2Token, server, settings, session));
328
329
330 List<TreeEntry> entries = new ArrayList<TreeEntry>(paths.length);
331 String prefix = path;
332 if (prefix == null)
333 prefix = "";
334 if (prefix.length() > 0 && !prefix.endsWith("/"))
335 prefix += "/";
336
337
338 if ('\\' == File.separatorChar)
339 for (int i = 0; i < paths.length; i++)
340 paths[i] = paths[i].replace('\\', '/');
341
342 boolean createNoJekyll = noJekyll;
343
344 for (String path : paths) {
345 TreeEntry entry = new TreeEntry();
346 entry.setPath(prefix + path);
347
348 if (createNoJekyll && NO_JEKYLL_FILE.equals(entry.getPath()))
349 createNoJekyll = false;
350 entry.setType(TYPE_BLOB);
351 entry.setMode(MODE_BLOB);
352 entry.setSha(createBlob(service, repository, path));
353 entries.add(entry);
354 }
355
356 if (createNoJekyll) {
357 TreeEntry entry = new TreeEntry();
358 entry.setPath(NO_JEKYLL_FILE);
359 entry.setType(TYPE_BLOB);
360 entry.setMode(MODE_BLOB);
361
362 if (isDebug())
363 debug("Creating empty .nojekyll blob at root of tree");
364 if (!dryRun)
365 try {
366 entry.setSha(service.createBlob(repository, new Blob()
367 .setEncoding(ENCODING_BASE64).setContent("")));
368 } catch (IOException e) {
369 throw new MojoExecutionException(
370 "Error creating .nojekyll empty blob: "
371 + getExceptionMessage(e), e);
372 }
373 entries.add(entry);
374 }
375
376 Reference ref = null;
377 try {
378 ref = service.getReference(repository, branch);
379 } catch (RequestException e) {
380 if (404 != e.getStatus())
381 throw new MojoExecutionException("Error getting reference: "
382 + getExceptionMessage(e), e);
383 } catch (IOException e) {
384 throw new MojoExecutionException("Error getting reference: "
385 + getExceptionMessage(e), e);
386 }
387
388 if (ref != null && !TYPE_COMMIT.equals(ref.getObject().getType()))
389 throw new MojoExecutionException(
390 MessageFormat
391 .format("Existing ref {0} points to a {1} ({2}) instead of a commmit",
392 ref.getRef(), ref.getObject().getType(),
393 ref.getObject().getSha()));
394
395
396 Tree tree;
397 try {
398 int size = entries.size();
399 if (size != 1)
400 info(MessageFormat.format(
401 "Creating tree with {0} blob entries", size));
402 else
403 info("Creating tree with 1 blob entry");
404 String baseTree = null;
405 if (merge && ref != null) {
406 Tree currentTree = service.getCommit(repository,
407 ref.getObject().getSha()).getTree();
408 if (currentTree != null)
409 baseTree = currentTree.getSha();
410 info(MessageFormat.format("Merging with tree {0}", baseTree));
411 }
412 if (!dryRun)
413 tree = service.createTree(repository, entries, baseTree);
414 else
415 tree = new Tree();
416 } catch (IOException e) {
417 throw new MojoExecutionException("Error creating tree: "
418 + getExceptionMessage(e), e);
419 }
420
421
422 Commit commit = new Commit();
423 commit.setMessage(message);
424 commit.setTree(tree);
425
426
427 if (ref != null)
428 commit.setParents(Collections.singletonList(new Commit().setSha(ref
429 .getObject().getSha())));
430
431 Commit created;
432 try {
433 if (!dryRun)
434 created = service.createCommit(repository, commit);
435 else
436 created = new Commit();
437 info(MessageFormat.format("Creating commit with SHA-1: {0}",
438 created.getSha()));
439 } catch (IOException e) {
440 throw new MojoExecutionException("Error creating commit: "
441 + getExceptionMessage(e), e);
442 }
443
444 TypedResource object = new TypedResource();
445 object.setType(TYPE_COMMIT).setSha(created.getSha());
446 if (ref != null) {
447
448 ref.setObject(object);
449 try {
450 info(MessageFormat.format(
451 "Updating reference {0} from {1} to {2}", branch,
452 commit.getParents().get(0).getSha(), created.getSha()));
453 if (!dryRun)
454 service.editReference(repository, ref, force);
455 } catch (IOException e) {
456 throw new MojoExecutionException("Error editing reference: "
457 + getExceptionMessage(e), e);
458 }
459 } else {
460
461 ref = new Reference().setObject(object).setRef(branch);
462 try {
463 info(MessageFormat.format(
464 "Creating reference {0} starting at commit {1}",
465 branch, created.getSha()));
466 if (!dryRun)
467 service.createReference(repository, ref);
468 } catch (IOException e) {
469 throw new MojoExecutionException("Error creating reference: "
470 + getExceptionMessage(e), e);
471 }
472 }
473 }
474 }