1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.kathrynhuxtable.maven.wagon.gitsite;
17
18 import java.io.File;
19 import java.io.IOException;
20
21 import java.text.DecimalFormat;
22
23 import java.util.ArrayList;
24 import java.util.List;
25 import java.util.Random;
26 import java.util.Stack;
27
28 import org.apache.maven.scm.CommandParameter;
29 import org.apache.maven.scm.CommandParameters;
30 import org.apache.maven.scm.ScmBranch;
31 import org.apache.maven.scm.ScmException;
32 import org.apache.maven.scm.ScmFile;
33 import org.apache.maven.scm.ScmFileSet;
34 import org.apache.maven.scm.ScmResult;
35 import org.apache.maven.scm.ScmVersion;
36 import org.apache.maven.scm.command.add.AddScmResult;
37 import org.apache.maven.scm.command.checkin.CheckInScmResult;
38 import org.apache.maven.scm.command.checkout.CheckOutScmResult;
39 import org.apache.maven.scm.command.list.ListScmResult;
40 import org.apache.maven.scm.manager.NoSuchScmProviderException;
41 import org.apache.maven.scm.manager.ScmManager;
42 import org.apache.maven.scm.provider.ScmProvider;
43 import org.apache.maven.scm.provider.ScmProviderRepository;
44 import org.apache.maven.scm.provider.ScmProviderRepositoryWithHost;
45 import org.apache.maven.scm.provider.git.command.GitCommand;
46 import org.apache.maven.scm.provider.git.gitexe.GitExeScmProvider;
47 import org.apache.maven.scm.repository.ScmRepository;
48 import org.apache.maven.scm.repository.ScmRepositoryException;
49 import org.apache.maven.wagon.AbstractWagon;
50 import org.apache.maven.wagon.ConnectionException;
51 import org.apache.maven.wagon.ResourceDoesNotExistException;
52 import org.apache.maven.wagon.TransferFailedException;
53 import org.apache.maven.wagon.authentication.AuthenticationException;
54 import org.apache.maven.wagon.authentication.AuthenticationInfo;
55 import org.apache.maven.wagon.authorization.AuthorizationException;
56 import org.apache.maven.wagon.events.TransferEvent;
57 import org.apache.maven.wagon.proxy.ProxyInfoProvider;
58 import org.apache.maven.wagon.repository.Repository;
59 import org.apache.maven.wagon.resource.Resource;
60
61 import org.codehaus.plexus.util.FileUtils;
62 import org.codehaus.plexus.util.StringUtils;
63
64 import org.kathrynhuxtable.maven.wagon.gitsite.git.GitSiteCheckInCommand;
65 import org.kathrynhuxtable.maven.wagon.gitsite.git.GitSiteCheckOutCommand;
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106 public class GitSiteWagon extends AbstractWagon {
107
108
109
110
111
112
113 private ScmManager scmManager;
114
115
116 private String siteBranch;
117
118
119 private File checkoutDirectory;
120
121
122
123
124
125
126 public ScmManager getScmManager() {
127 return scmManager;
128 }
129
130
131
132
133
134
135 public void setScmManager(ScmManager scmManager) {
136 this.scmManager = scmManager;
137 }
138
139
140
141
142
143
144 public String getSiteBranch() {
145 return siteBranch;
146 }
147
148
149
150
151
152
153 public void setSiteBranch(String siteBranch) {
154 this.siteBranch = siteBranch;
155 }
156
157
158
159
160
161
162
163 public File getCheckoutDirectory() {
164 return checkoutDirectory;
165 }
166
167
168
169
170
171
172
173 public void setCheckoutDirectory(File checkoutDirectory) {
174 this.checkoutDirectory = checkoutDirectory;
175 }
176
177
178
179
180
181
182
183
184
185
186
187
188 public ScmProvider getScmProvider(String scmType) throws NoSuchScmProviderException {
189 return getScmManager().getProviderByType(scmType);
190 }
191
192
193
194
195
196
197 public void openConnectionInternal() throws ConnectionException {
198 if (checkoutDirectory == null) {
199 checkoutDirectory = createCheckoutDirectory();
200 }
201
202 if (checkoutDirectory.exists()) {
203 removeCheckoutDirectory();
204 }
205
206 checkoutDirectory.mkdirs();
207 }
208
209
210
211
212
213
214 private File createCheckoutDirectory() {
215 File checkoutDirectory;
216
217 DecimalFormat fmt = new DecimalFormat("#####");
218
219 Random rand = new Random(System.currentTimeMillis() + Runtime.getRuntime().freeMemory());
220
221 do {
222 checkoutDirectory = new File(System.getProperty("java.io.tmpdir"),
223 "wagon-scm" + fmt.format(Math.abs(rand.nextInt())) + ".checkout");
224 } while (checkoutDirectory.exists());
225
226 return checkoutDirectory;
227 }
228
229
230
231
232
233
234 private void removeCheckoutDirectory() throws ConnectionException {
235 if (checkoutDirectory == null) {
236 return;
237 }
238
239 try {
240 FileUtils.deleteDirectory(checkoutDirectory);
241 } catch (IOException e) {
242 throw new ConnectionException("Unable to cleanup checkout directory", e);
243 }
244 }
245
246
247
248
249
250
251
252
253
254
255
256
257 private ScmRepository getScmRepository(String url) throws ScmRepositoryException, NoSuchScmProviderException {
258 String username = null;
259
260 String password = null;
261
262 String privateKey = null;
263
264 String passphrase = null;
265
266 if (authenticationInfo != null) {
267 username = authenticationInfo.getUserName();
268
269 password = authenticationInfo.getPassword();
270
271 privateKey = authenticationInfo.getPrivateKey();
272
273 passphrase = authenticationInfo.getPassphrase();
274 }
275
276 ScmRepository scmRepository = getScmManager().makeScmRepository(url);
277
278 ScmProviderRepository providerRepository = scmRepository.getProviderRepository();
279
280 if (StringUtils.isNotEmpty(username)) {
281 providerRepository.setUser(username);
282 }
283
284 if (StringUtils.isNotEmpty(password)) {
285 providerRepository.setPassword(password);
286 }
287
288 if (providerRepository instanceof ScmProviderRepositoryWithHost) {
289 ScmProviderRepositoryWithHost providerRepo = (ScmProviderRepositoryWithHost) providerRepository;
290
291 if (StringUtils.isNotEmpty(privateKey)) {
292 providerRepo.setPrivateKey(privateKey);
293 }
294
295 if (StringUtils.isNotEmpty(passphrase)) {
296 providerRepo.setPassphrase(passphrase);
297 }
298 }
299
300 return scmRepository;
301 }
302
303
304
305
306
307
308
309
310
311
312 private void checkIn(ScmProvider scmProvider, ScmRepository scmRepository, String msg) throws ScmException {
313 CommandParameters parameters = new CommandParameters();
314
315 parameters.setScmVersion(CommandParameter.SCM_VERSION, new ScmBranch(siteBranch));
316
317 parameters.setString(CommandParameter.MESSAGE, msg);
318
319 ScmResult result = (CheckInScmResult) executeCommand((GitExeScmProvider) scmProvider, new GitSiteCheckInCommand(),
320 scmRepository.getProviderRepository(),
321 new ScmFileSet(checkoutDirectory), parameters);
322
323 checkScmResult(result);
324 }
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341 private String checkOut(ScmProvider scmProvider, ScmRepository scmRepository, String targetName, Resource resource)
342 throws TransferFailedException {
343 checkoutDirectory = createCheckoutDirectory();
344
345 Stack<String> stack = new Stack<String>();
346
347 String target = targetName;
348
349
350
351
352
353
354 try {
355 while (target.length() > 0
356 && !scmProvider.list(scmRepository, new ScmFileSet(new File("."), new File(target)), false, (ScmVersion) null)
357 .isSuccess()) {
358 stack.push(getFilename(target));
359 target = getDirname(target);
360 }
361 } catch (ScmException e) {
362 fireTransferError(resource, e, TransferEvent.REQUEST_PUT);
363
364 throw new TransferFailedException("Error listing repository: " + e.getMessage(), e);
365 }
366
367
368
369
370
371
372
373 String url = getRepository().getUrl();
374 String relPath = "";
375 if (!url.endsWith(".git")) {
376 final int iGitSuffix = url.lastIndexOf(".git");
377 if (iGitSuffix > 0) {
378 relPath = url.substring(iGitSuffix + 5) + '/';
379 url = url.substring(0, iGitSuffix + 4);
380 }
381 }
382
383
384
385
386
387
388 try {
389 scmRepository = getScmRepository(url);
390
391 CommandParameters parameters = new CommandParameters();
392
393 parameters.setScmVersion(CommandParameter.SCM_VERSION, new ScmBranch(siteBranch));
394
395 parameters.setString(CommandParameter.RECURSIVE, "false");
396
397 CheckOutScmResult ret = (CheckOutScmResult) executeCommand((GitExeScmProvider) scmProvider, new GitSiteCheckOutCommand(),
398 scmRepository.getProviderRepository(),
399 new ScmFileSet(new File(checkoutDirectory, "")), parameters);
400
401 checkScmResult(ret);
402 } catch (ScmException e) {
403 fireTransferError(resource, e, TransferEvent.REQUEST_PUT);
404
405 throw new TransferFailedException("Error checking out: " + e.getMessage(), e);
406 }
407
408
409
410 while (!stack.isEmpty()) {
411 String p = (String) stack.pop();
412
413 relPath += p + '/';
414
415 File newDir = new File(checkoutDirectory, relPath);
416
417 if (!newDir.mkdirs()) {
418 throw new TransferFailedException("Failed to create directory " + newDir.getAbsolutePath() + "; parent should exist: "
419 + checkoutDirectory);
420 }
421
422 try {
423 addFiles(scmProvider, scmRepository, checkoutDirectory, relPath);
424 } catch (ScmException e) {
425 fireTransferError(resource, e, TransferEvent.REQUEST_PUT);
426
427 throw new TransferFailedException("Failed to add directory " + newDir + " to working copy", e);
428 }
429 }
430
431 return relPath;
432 }
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451 private int addFiles(ScmProvider scmProvider, ScmRepository scmRepository, File basedir, String scmFilePath) throws ScmException {
452 int addedFiles = 0;
453
454 File scmFile = new File(basedir, scmFilePath);
455
456 if (scmFilePath.length() != 0) {
457 AddScmResult result = scmProvider.add(scmRepository, new ScmFileSet(basedir, new File(scmFilePath)));
458
459
460
461
462
463
464 if (!result.isSuccess()) {
465 result = scmProvider.add(scmRepository, new ScmFileSet(basedir, new File(scmFilePath)));
466 }
467
468 addedFiles = result.getAddedFiles().size();
469 }
470
471 String reservedScmFile = scmProvider.getScmSpecificFilename();
472
473 if (scmFile.isDirectory()) {
474 File[] files = scmFile.listFiles();
475
476 for (int i = 0; i < files.length; i++) {
477 if (reservedScmFile != null && !reservedScmFile.equals(files[i].getName())) {
478 addedFiles += addFiles(scmProvider, scmRepository, basedir,
479 (scmFilePath.length() == 0 ? "" : scmFilePath + "/") + files[i].getName());
480 }
481 }
482 }
483
484 return addedFiles;
485 }
486
487
488
489
490
491
492
493
494 public boolean supportsDirectoryCopy() {
495 return true;
496 }
497
498
499
500
501
502
503 public void connect(Repository repository, AuthenticationInfo authenticationInfo, ProxyInfoProvider proxyInfoProvider)
504 throws ConnectionException, AuthenticationException {
505 String url = repository.getUrl();
506
507 if (url.startsWith("gitsite:")) {
508 url = url.substring(8);
509 int index = url.indexOf(':');
510
511 if (index > -1) {
512 siteBranch = url.substring(index + 1);
513 url = url.substring(0, index);
514 } else {
515 siteBranch = "gh-pages";
516 }
517
518 url = "scm:git:ssh://" + url;
519 repository.setUrl(url);
520 }
521
522 super.connect(repository, authenticationInfo, proxyInfoProvider);
523 }
524
525
526
527
528 public void put(File source, String destination) throws TransferFailedException {
529 throw new TransferFailedException("Not currently supported: put");
530 }
531
532
533
534
535 public void putDirectory(File sourceDirectory, String destinationDirectory) throws TransferFailedException,
536 ResourceDoesNotExistException, AuthorizationException {
537 if (!sourceDirectory.isDirectory()) {
538 throw new IllegalArgumentException("Source is not a directory: " + sourceDirectory);
539 }
540
541 Resource target = new Resource(destinationDirectory);
542
543 firePutInitiated(target, sourceDirectory);
544
545 try {
546 ScmRepository scmRepository = getScmRepository(getRepository().getUrl());
547
548 target.setContentLength(sourceDirectory.length());
549 target.setLastModified(sourceDirectory.lastModified());
550
551 firePutStarted(target, sourceDirectory);
552
553 String msg = "Wagon: Deploying " + sourceDirectory.getName() + " to repository";
554
555 ScmProvider scmProvider = getScmProvider(scmRepository.getProvider());
556
557 String checkoutTargetName = sourceDirectory.isDirectory() ? destinationDirectory : getDirname(destinationDirectory);
558 String relPath = checkOut(scmProvider, scmRepository, checkoutTargetName, target);
559
560 File newCheckoutDirectory = new File(checkoutDirectory, relPath);
561
562 File scmFile = new File(newCheckoutDirectory, sourceDirectory.isDirectory() ? "" : getFilename(destinationDirectory));
563
564 boolean fileAlreadyInScm = scmFile.exists();
565
566 if (!scmFile.equals(sourceDirectory)) {
567 if (sourceDirectory.isDirectory()) {
568 FileUtils.copyDirectoryStructure(sourceDirectory, scmFile);
569 } else {
570 FileUtils.copyFile(sourceDirectory, scmFile);
571 }
572 }
573
574 if (!fileAlreadyInScm || scmFile.isDirectory()) {
575 int addedFiles = addFiles(scmProvider, scmRepository, newCheckoutDirectory,
576 sourceDirectory.isDirectory() ? "" : scmFile.getName());
577
578 if (!fileAlreadyInScm && addedFiles == 0) {
579 throw new ScmException("Unable to add file to SCM: " + scmFile + "; see error messages above for more information");
580 }
581 }
582
583 checkIn(scmProvider, scmRepository, msg);
584 } catch (ScmException e) {
585 e.printStackTrace();
586 fireTransferError(target, e, TransferEvent.REQUEST_GET);
587
588 System.exit(1);
589 throw new TransferFailedException("Error interacting with SCM: " + e.getMessage(), e);
590 } catch (IOException e) {
591 fireTransferError(target, e, TransferEvent.REQUEST_GET);
592
593 throw new TransferFailedException("Error interacting with SCM: " + e.getMessage(), e);
594 }
595
596 if (sourceDirectory.isFile()) {
597 postProcessListeners(target, sourceDirectory, TransferEvent.REQUEST_PUT);
598 }
599
600 firePutCompleted(target, sourceDirectory);
601 }
602
603
604
605
606
607
608
609
610 private void checkScmResult(ScmResult result) throws ScmException {
611 if (!result.isSuccess()) {
612 throw new ScmException("Unable to commit file. " + result.getProviderMessage() + " "
613 + (result.getCommandOutput() == null ? "" : result.getCommandOutput()));
614 }
615 }
616
617
618
619
620 public void closeConnection() throws ConnectionException {
621 removeCheckoutDirectory();
622 }
623
624
625
626
627
628 public boolean getIfNewer(String resourceName, File destination, long timestamp) throws TransferFailedException,
629 ResourceDoesNotExistException, AuthorizationException {
630 throw new UnsupportedOperationException("Not currently supported: getIfNewer");
631 }
632
633
634
635
636 public void get(String resourceName, File destination) throws TransferFailedException, ResourceDoesNotExistException,
637 AuthorizationException {
638 throw new UnsupportedOperationException("Not currently supported: get");
639 }
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655 public List<String> getFileList(String resourcePath) throws TransferFailedException, ResourceDoesNotExistException,
656 AuthorizationException {
657 try {
658 ScmRepository repository = getScmRepository(getRepository().getUrl());
659 ScmProvider provider = getScmProvider(repository.getProvider());
660 ListScmResult result = provider.list(repository,
661 new ScmFileSet(new File("."), new File(resourcePath)), false, (ScmVersion) null);
662
663 if (!result.isSuccess()) {
664 throw new ResourceDoesNotExistException(result.getProviderMessage());
665 }
666
667 List<String> files = new ArrayList<String>();
668
669 for (ScmFile f : getListScmResultFiles(result)) {
670 files.add(f.getPath());
671 System.out.println("LIST FILE: " + f + " (path=" + f.getPath() + ")");
672 }
673
674 return files;
675 } catch (ScmException e) {
676 throw new TransferFailedException("Error getting filelist from SCM", e);
677 }
678 }
679
680
681
682
683
684
685
686
687
688 @SuppressWarnings("unchecked")
689 private List<ScmFile> getListScmResultFiles(ListScmResult result) {
690 return (List<ScmFile>) result.getFiles();
691 }
692
693
694
695
696 public boolean resourceExists(String resourceName) throws TransferFailedException, AuthorizationException {
697 try {
698 getFileList(resourceName);
699 return true;
700 } catch (ResourceDoesNotExistException e) {
701 return false;
702 }
703 }
704
705
706
707
708
709
710
711
712 private String getFilename(String filename) {
713 String fname = StringUtils.replace(filename, "/", File.separator);
714
715 return FileUtils.filename(fname);
716 }
717
718
719
720
721
722
723
724
725 private String getDirname(String filename) {
726 String fname = StringUtils.replace(filename, "/", File.separator);
727
728 return FileUtils.dirname(fname);
729 }
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744 protected ScmResult executeCommand(GitExeScmProvider scmProvider, GitCommand command, ScmProviderRepository repository,
745 ScmFileSet fileSet, CommandParameters parameters) throws ScmException {
746 command.setLogger(scmProvider.getLogger());
747
748 return command.execute(repository, fileSet, parameters);
749 }
750 }