View Javadoc
1   /*
2    * Copyright (c) 2010 Kathryn Huxtable
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  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.log.ScmLogger;
41  import org.apache.maven.scm.manager.NoSuchScmProviderException;
42  import org.apache.maven.scm.manager.ScmManager;
43  import org.apache.maven.scm.provider.ScmProvider;
44  import org.apache.maven.scm.provider.ScmProviderRepository;
45  import org.apache.maven.scm.provider.ScmProviderRepositoryWithHost;
46  import org.apache.maven.scm.provider.git.command.GitCommand;
47  import org.apache.maven.scm.provider.git.gitexe.GitExeScmProvider;
48  import org.apache.maven.scm.repository.ScmRepository;
49  import org.apache.maven.scm.repository.ScmRepositoryException;
50  import org.apache.maven.wagon.AbstractWagon;
51  import org.apache.maven.wagon.ConnectionException;
52  import org.apache.maven.wagon.ResourceDoesNotExistException;
53  import org.apache.maven.wagon.TransferFailedException;
54  import org.apache.maven.wagon.authentication.AuthenticationException;
55  import org.apache.maven.wagon.authentication.AuthenticationInfo;
56  import org.apache.maven.wagon.authorization.AuthorizationException;
57  import org.apache.maven.wagon.events.TransferEvent;
58  import org.apache.maven.wagon.proxy.ProxyInfoProvider;
59  import org.apache.maven.wagon.repository.Repository;
60  import org.apache.maven.wagon.resource.Resource;
61  
62  import org.codehaus.plexus.util.FileUtils;
63  import org.codehaus.plexus.util.StringUtils;
64  
65  import org.kathrynhuxtable.maven.wagon.gitsite.git.GitSiteCheckInCommand;
66  import org.kathrynhuxtable.maven.wagon.gitsite.git.GitSiteCheckOutCommand;
67  
68  /**
69   * Wagon provider to deploy site documentation to GitHub's pages system.
70   *
71   * <p>This should do more or less the following, but doesn't because it doesn't
72   * actually delete old files.</p>
73   *
74   * <pre>
75   * mkdir ${checkoutDirectory}
76   * cd ${checkoutDirectory}
77   * git init
78   * git remote add origin ${gitRepoUrl}
79   * git pull origin refs/heads/${siteBranch}
80   * <replace the contents of the checkout directory, except for the .git subdirectory, with the site docs>
81   * git add .
82   * git commit -a -m "Wagon: Deploying site to repository"
83   * git push origin master:${siteBranch}
84   * rm -Rf ${checkoutDirectory}
85   * </pre>
86   * 
87   * We <em>need</em> to create the gh-pages branch if it doesn't already exist:
88   * 
89   * <pre>
90   * cd ${checkoutDirectory}
91   * git symbolic-ref HEAD refs/heads/gh-pages
92   * rm .git/index
93   * git clean -fdx
94   * git add .
95   * git commit -a -m "First pages commit"
96   * git push origin gh-pages
97   * </pre>
98   *
99   * @plexus.component role="org.apache.maven.wagon.Wagon" role-hint="gitsite"
100  *                   instantiation-strategy="per-lookup"
101  * @author           <a href="kathryn@kathrynhuxtable.org">Kathryn Huxtable</a>
102  * @author           <a href="brett@apache.org">Brett Porter</a>
103  * @author           <a href="evenisse@apache.org">Emmanuel Venisse</a>
104  * @author           <a href="carlos@apache.org">Carlos Sanchez</a>
105  * @author           Jason van Zyl
106  */
107 public class GitSiteWagon extends AbstractWagon {
108 
109     /**
110      * The SCM Manager.
111      *
112      * @plexus.requirement
113      */
114     private ScmManager scmManager;
115 
116     /** The site branch. Set in connect. */
117     private String siteBranch;
118 
119     /** The check-out directory. */
120     private File checkoutDirectory;
121 
122     /**
123      * Get the {@link ScmManager} used in this Wagon.
124      *
125      * @return the {@link ScmManager}.
126      */
127     public ScmManager getScmManager() {
128         return scmManager;
129     }
130 
131     /**
132      * Set the {@link ScmManager} used in this Wagon.
133      *
134      * @param scmManager the scmManager to set.
135      */
136     public void setScmManager(ScmManager scmManager) {
137         this.scmManager = scmManager;
138     }
139 
140     /**
141      * Get the {@link #siteBranch} used in this Wagon.
142      *
143      * @return the {@link #siteBranch}.
144      */
145     public String getSiteBranch() {
146         return siteBranch;
147     }
148 
149     /**
150      * Set the {@link #siteBranch} used in this Wagon.
151      *
152      * @param siteBranch the siteBranch to set.
153      */
154     public void setSiteBranch(String siteBranch) {
155         this.siteBranch = siteBranch;
156     }
157 
158     /**
159      * Get the directory where Wagon will checkout files from SCM. This
160      * directory will be deleted!
161      *
162      * @return the {@link #checkoutDirectory}.
163      */
164     public File getCheckoutDirectory() {
165         return checkoutDirectory;
166     }
167 
168     /**
169      * Set the directory where Wagon will checkout files from SCM. This
170      * directory will be deleted!
171      *
172      * @param checkoutDirectory the check-out directory to set.
173      */
174     public void setCheckoutDirectory(File checkoutDirectory) {
175         this.checkoutDirectory = checkoutDirectory;
176     }
177 
178     /**
179      * Convenience method to get the {@link ScmProvider} implementation to
180      * handle the provided SCM type.
181      *
182      * @param  scmType type of SCM, eg. <code>svn</code>, <code>cvs</code>
183      *
184      * @return the {@link ScmProvider} that will handle provided SCM type.
185      *
186      * @throws NoSuchScmProviderException if there is no {@link ScmProvider}
187      *                                    able to handle that SCM type.
188      */
189     public ScmProvider getScmProvider(String scmType) throws NoSuchScmProviderException {
190         return getScmManager().getProviderByType(scmType);
191     }
192 
193     /**
194      * This will clean up the checkout directory.
195      *
196      * @throws ConnectionException
197      */
198     public void openConnectionInternal() throws ConnectionException {
199         if (checkoutDirectory == null) {
200             checkoutDirectory = createCheckoutDirectory();
201         }
202 
203         if (checkoutDirectory.exists()) {
204             removeCheckoutDirectory();
205         }
206 
207         checkoutDirectory.mkdirs();
208     }
209 
210     /**
211      * Create the checkout directory.
212      *
213      * @return the File representing the checkout directory.
214      */
215     private File createCheckoutDirectory() {
216         File checkoutDirectory;
217 
218         DecimalFormat fmt = new DecimalFormat("#####");
219 
220         Random rand = new Random(System.currentTimeMillis() + Runtime.getRuntime().freeMemory());
221 
222         do {
223             checkoutDirectory = new File(System.getProperty("java.io.tmpdir"),
224                                          "wagon-scm" + fmt.format(Math.abs(rand.nextInt())) + ".checkout");
225         } while (checkoutDirectory.exists());
226 
227         return checkoutDirectory;
228     }
229 
230     /**
231      * Remove (delete) the checkout directory.
232      *
233      * @throws ConnectionException if unable to clean up the checkout directory.
234      */
235     private void removeCheckoutDirectory() throws ConnectionException {
236         if (checkoutDirectory == null) {
237             return; // Silently return.
238         }
239 
240         try {
241             FileUtils.deleteDirectory(checkoutDirectory);
242         } catch (IOException e) {
243             throw new ConnectionException("Unable to cleanup checkout directory", e);
244         }
245     }
246 
247     /**
248      * Get the SCM repository from the URL.
249      *
250      * @param  url the URL.
251      *
252      * @return the SCM repository.
253      *
254      * @throws ScmRepositoryException     if an SCM error occurs.
255      * @throws NoSuchScmProviderException if there is no matching provider for
256      *                                    the URL.
257      */
258     private ScmRepository getScmRepository(String url) throws ScmRepositoryException, NoSuchScmProviderException {
259         String username = null;
260 
261         String password = null;
262 
263         String privateKey = null;
264 
265         String passphrase = null;
266 
267         if (authenticationInfo != null) {
268             username = authenticationInfo.getUserName();
269 
270             password = authenticationInfo.getPassword();
271 
272             privateKey = authenticationInfo.getPrivateKey();
273 
274             passphrase = authenticationInfo.getPassphrase();
275         }
276 
277         ScmRepository scmRepository = getScmManager().makeScmRepository(url);
278 
279         ScmProviderRepository providerRepository = scmRepository.getProviderRepository();
280 
281         if (StringUtils.isNotEmpty(username)) {
282             providerRepository.setUser(username);
283         }
284 
285         if (StringUtils.isNotEmpty(password)) {
286             providerRepository.setPassword(password);
287         }
288 
289         if (providerRepository instanceof ScmProviderRepositoryWithHost) {
290             ScmProviderRepositoryWithHost providerRepo = (ScmProviderRepositoryWithHost) providerRepository;
291 
292             if (StringUtils.isNotEmpty(privateKey)) {
293                 providerRepo.setPrivateKey(privateKey);
294             }
295 
296             if (StringUtils.isNotEmpty(passphrase)) {
297                 providerRepo.setPassphrase(passphrase);
298             }
299         }
300 
301         return scmRepository;
302     }
303 
304     /**
305      * Configure and perform the check-in process.
306      *
307      * @param  scmProvider   the SCM provider.
308      * @param  scmRepository the SCM repository.
309      * @param  msg           the commit message.
310      *
311      * @throws ScmException
312      */
313     private void checkIn(ScmProvider scmProvider, ScmRepository scmRepository, String msg) throws ScmException {
314         CommandParameters parameters = new CommandParameters();
315 
316         parameters.setScmVersion(CommandParameter.SCM_VERSION, new ScmBranch(siteBranch));
317 
318         parameters.setString(CommandParameter.MESSAGE, msg);
319 
320         ScmResult result = (CheckInScmResult) executeCommand((GitExeScmProvider) scmProvider, new GitSiteCheckInCommand(),
321                                                              scmRepository.getProviderRepository(),
322                                                              new ScmFileSet(checkoutDirectory), parameters);
323 
324         checkScmResult(result);
325     }
326 
327     /**
328      * Configure and perform the check-out process.
329      *
330      * <p>Returns the relative path to targetName in the checkout dir. If the
331      * targetName already exists in the scm, this will be the empty string.</p>
332      *
333      * @param  scmProvider   the SCM provider.
334      * @param  scmRepository the SCM repository.
335      * @param  targetName    the check-out directory.
336      * @param  resource      the resource.
337      *
338      * @return the relative path to targetName in the check-out directory.
339      *
340      * @throws TransferFailedException
341      */
342     private String checkOut(ScmProvider scmProvider, ScmRepository scmRepository, String targetName, Resource resource)
343         throws TransferFailedException {
344         checkoutDirectory = createCheckoutDirectory();
345 
346         Stack<String> stack = new Stack<String>();
347 
348         String target = targetName;
349 
350         // Totally ignore scmRepository parent stuff since that is not supported by all SCMs.
351         // Instead, assume that that url exists. If not, then that's an error.
352         // Check whether targetName, which is a relative path into the scm, exists.
353         // If it doesn't, check the parent, etc.
354 
355         try {
356             while (target.length() > 0
357                     && !scmProvider.list(scmRepository, new ScmFileSet(new File("."), new File(target)), false, (ScmVersion) null)
358                     .isSuccess()) {
359                 stack.push(getFilename(target));
360                 target = getDirname(target);
361             }
362         } catch (ScmException e) {
363             fireTransferError(resource, e, TransferEvent.REQUEST_PUT);
364 
365             throw new TransferFailedException("Error listing repository: " + e.getMessage(), e);
366         }
367 
368         /* A URL for a module will look like: 
369          *   scm:git:ssh://github.com/auser/project.git/module
370          * so we strip the module to get just:
371          *   scm:git:ssh://github.com/auser/project.git
372          * to ensure a successful checkout, then adjust the relative path.
373          */
374         String url = getRepository().getUrl() + targetName;
375         String relPath = "";
376         
377         if (!url.endsWith(".git")) {
378             final int iGitSuffix = url.lastIndexOf(".git");
379             if (iGitSuffix > 0) {
380                 relPath = url.substring(iGitSuffix + 5) + '/';
381                 url = url.substring(0, iGitSuffix + 4);
382             }
383         }
384         final ScmLogger logger = ((GitExeScmProvider)scmProvider).getLogger();
385         logger.debug("checkOut url: " + url);
386         logger.debug("checkOut relPath: " + relPath);
387 
388         // ok, we've established that target exists, or is empty.
389         // Check the resource out; if it doesn't exist, that means we're in the svn repo url root,
390         // and the configuration is incorrect. We will not try repo.getParent since most scm's don't
391         // implement that.
392 
393         try {
394             scmRepository = getScmRepository(url);
395 
396             CommandParameters parameters = new CommandParameters();
397 
398             parameters.setScmVersion(CommandParameter.SCM_VERSION, new ScmBranch(siteBranch));
399 
400             parameters.setString(CommandParameter.RECURSIVE, "false");
401 
402             CheckOutScmResult ret = (CheckOutScmResult) executeCommand((GitExeScmProvider) scmProvider, new GitSiteCheckOutCommand(),
403                                                                        scmRepository.getProviderRepository(),
404                                                                        new ScmFileSet(new File(checkoutDirectory, "")), parameters);
405 
406             checkScmResult(ret);
407         } catch (ScmException e) {
408             fireTransferError(resource, e, TransferEvent.REQUEST_PUT);
409 
410             throw new TransferFailedException("Error checking out: " + e.getMessage(), e);
411         }
412 
413         // now create the subdirs in target, if it's a parent of targetName
414 
415         while (!stack.isEmpty()) {
416             String p = (String) stack.pop();
417 
418             relPath += p + '/';
419             logger.debug(" * checkOut relPath: " + relPath);
420 
421             File newDir = new File(checkoutDirectory, relPath);
422 
423             if (!newDir.mkdirs()) {
424                 throw new TransferFailedException("Failed to create directory " + newDir.getAbsolutePath() + "; parent should exist: "
425                                                   + checkoutDirectory);
426             }
427 
428             try {
429                 addFiles(scmProvider, scmRepository, checkoutDirectory, relPath);
430             } catch (ScmException e) {
431                 fireTransferError(resource, e, TransferEvent.REQUEST_PUT);
432 
433                 throw new TransferFailedException("Failed to add directory " + newDir + " to working copy", e);
434             }
435         }
436 
437         return relPath;
438     }
439 
440     private List<File> buildFiles(ScmProvider scmProvider, File basedir, String scmFilePath) {
441         List<File> result = new ArrayList<File>();
442         if (scmFilePath.length() != 0) {
443             result.add(new File(scmFilePath));
444         }
445         String reservedScmFile = scmProvider.getScmSpecificFilename();
446         File scmFile = new File(basedir, scmFilePath);
447         if (scmFile.isDirectory()) {
448             File[] f = scmFile.listFiles();
449 
450             for (int i = 0; i < f.length; i++) {
451                 if (reservedScmFile != null && !reservedScmFile.equals(f[i].getName())) {
452                     result.addAll(buildFiles(scmProvider, basedir, (scmFilePath.length() == 0 ? "" : scmFilePath + "/") + f[i].getName()));
453                 }
454             }
455         }
456         return result;
457     }
458 
459     /**
460      * Add a file or directory to a SCM repository. If it's a directory all its
461      * contents are added recursively.
462      *
463      * @param  scmProvider   SCM provider
464      * @param  scmRepository SCM repository
465      * @param  basedir       local directory corresponding to scmRepository
466      * @param  scmFilePath   path of the file or directory to add, relative to
467      *                       basedir
468      *
469      * @return the number of files added.
470      *
471      * @throws ScmException
472      */
473     private int addFiles(ScmProvider scmProvider, ScmRepository scmRepository, File basedir, String scmFilePath) throws ScmException {
474         AddScmResult result = scmProvider.add(scmRepository, new ScmFileSet(basedir, buildFiles(scmProvider, basedir, scmFilePath)));
475         /*
476          * TODO dirty fix to work around files with property svn:eol-style=native if a file has that property, first
477          * time file is added it fails, second time it succeeds the solution is check if the scm provider is svn and
478          * unset that property when the SCM API allows it
479          */
480         if (!result.isSuccess()) {
481             result = scmProvider.add(scmRepository, new ScmFileSet(basedir, new File(scmFilePath)));
482         }
483 
484         return result.getAddedFiles().size();
485     }
486 
487     /**
488      * Return whether or not this wagon supports directory copy.
489      *
490      * @return {@code true}
491      *
492      * @see    org.apache.maven.wagon.AbstractWagon#supportsDirectoryCopy()
493      */
494     public boolean supportsDirectoryCopy() {
495         return true;
496     }
497 
498     /**
499      * @see org.apache.maven.wagon.AbstractWagon#connect(org.apache.maven.wagon.repository.Repository,
500      *      org.apache.maven.wagon.authentication.AuthenticationInfo,
501      *      org.apache.maven.wagon.proxy.ProxyInfoProvider)
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 if (url.indexOf(".github.com.git") != -1) {
515                 // it's a master page
516                 siteBranch = "master";
517             }else {
518                 siteBranch = "gh-pages";
519             }
520 
521             if (url.startsWith("file:///"))
522                 url = "scm:git:" + url;
523             else
524                 url = "scm:git:ssh://" + url;
525             repository.setUrl(url);
526         }
527 
528         super.connect(repository, authenticationInfo, proxyInfoProvider);
529     }
530 
531     /**
532      * @see org.apache.maven.wagon.Wagon#put(java.io.File, java.lang.String)
533      */
534     public void put(File source, String destination) throws TransferFailedException {
535     	putResource(source, destination);
536     }
537 
538     /**
539      * @see org.apache.maven.wagon.AbstractWagon#putDirectory(java.io.File, java.lang.String)
540      */
541     public void putDirectory(File sourceDirectory, String destinationDirectory) throws TransferFailedException,
542         ResourceDoesNotExistException, AuthorizationException {
543         if (!sourceDirectory.isDirectory()) {
544             throw new IllegalArgumentException("Source is not a directory: " + sourceDirectory);
545         }
546 
547         putResource(sourceDirectory, destinationDirectory);
548     }
549 
550 	private void putResource(File sourceDirectory, String destinationDirectory) throws TransferFailedException {
551 		Resource target = new Resource(destinationDirectory);
552 
553         firePutInitiated(target, sourceDirectory);
554 
555         try {
556             ScmRepository scmRepository = getScmRepository(getRepository().getUrl());
557 
558             target.setContentLength(sourceDirectory.length());
559             target.setLastModified(sourceDirectory.lastModified());
560 
561             firePutStarted(target, sourceDirectory);
562 
563             String msg = "Wagon: Deploying " + sourceDirectory.getName() + " to repository";
564 
565             ScmProvider scmProvider = getScmProvider(scmRepository.getProvider());
566 
567             String checkoutTargetName = sourceDirectory.isDirectory() ? destinationDirectory : getDirname(destinationDirectory);
568             String relPath            = checkOut(scmProvider, scmRepository, checkoutTargetName, target);
569 
570             File newCheckoutDirectory = new File(checkoutDirectory, relPath);
571 
572             File scmFile = new File(newCheckoutDirectory, sourceDirectory.isDirectory() ? "" : getFilename(destinationDirectory));
573 
574             boolean fileAlreadyInScm = scmFile.exists();
575 
576             if (!scmFile.equals(sourceDirectory)) {
577                 if (sourceDirectory.isDirectory()) {
578                     FileUtils.copyDirectoryStructure(sourceDirectory, scmFile);
579                 } else {
580                     FileUtils.copyFile(sourceDirectory, scmFile);
581                 }
582             }
583 
584             if (!fileAlreadyInScm || scmFile.isDirectory()) {
585                 int addedFiles = addFiles(scmProvider, scmRepository, newCheckoutDirectory,
586                                           sourceDirectory.isDirectory() ? "" : scmFile.getName());
587 
588                 if (!fileAlreadyInScm && addedFiles == 0) {
589                     throw new ScmException("Unable to add file to SCM: " + scmFile + "; see error messages above for more information");
590                 }
591             }
592 
593             checkIn(scmProvider, scmRepository, msg);
594         } catch (ScmException e) {
595             e.printStackTrace();
596             fireTransferError(target, e, TransferEvent.REQUEST_GET);
597 
598             System.exit(1);
599             throw new TransferFailedException("Error interacting with SCM: " + e.getMessage(), e);
600         } catch (IOException e) {
601             fireTransferError(target, e, TransferEvent.REQUEST_GET);
602 
603             throw new TransferFailedException("Error interacting with SCM: " + e.getMessage(), e);
604         }
605 
606         if (sourceDirectory.isFile()) {
607             postProcessListeners(target, sourceDirectory, TransferEvent.REQUEST_PUT);
608         }
609 
610         firePutCompleted(target, sourceDirectory);
611 	}
612 
613     /**
614      * Check that the ScmResult was a successful operation
615      *
616      * @param  result the SCM result.
617      *
618      * @throws ScmException
619      */
620     private void checkScmResult(ScmResult result) throws ScmException {
621         if (!result.isSuccess()) {
622             throw new ScmException("Unable to commit file. " + result.getProviderMessage() + " "
623                                    + (result.getCommandOutput() == null ? "" : result.getCommandOutput()));
624         }
625     }
626 
627     /**
628      * @see org.apache.maven.wagon.AbstractWagon#closeConnection()
629      */
630     public void closeConnection() throws ConnectionException {
631         removeCheckoutDirectory();
632     }
633 
634     /**
635      * @see org.apache.maven.wagon.Wagon#getIfNewer(java.lang.String,java.io.File,
636      *      long)
637      */
638     public boolean getIfNewer(String resourceName, File destination, long timestamp) throws TransferFailedException,
639         ResourceDoesNotExistException, AuthorizationException {
640         throw new UnsupportedOperationException("Not currently supported: getIfNewer");
641     }
642 
643     /**
644      * @see org.apache.maven.wagon.Wagon#get(java.lang.String, java.io.File)
645      */
646     public void get(String resourceName, File destination) throws TransferFailedException, ResourceDoesNotExistException,
647         AuthorizationException {
648         throw new UnsupportedOperationException("Not currently supported: get");
649     }
650 
651     /**
652      * Get the file list for the resource.
653      *
654      * @param  resourcePath the resource path.
655      *
656      * @return a List&lt;String&gt; with filenames/directories at the
657      *         resourcepath.
658      *
659      * @throws TransferFailedException
660      * @throws ResourceDoesNotExistException
661      * @throws AuthorizationException
662      *
663      * @see    org.apache.maven.wagon.AbstractWagon#getFileList(java.lang.String)
664      */
665     public List<String> getFileList(String resourcePath) throws TransferFailedException, ResourceDoesNotExistException,
666         AuthorizationException {
667         try {
668             ScmRepository repository = getScmRepository(getRepository().getUrl());
669             ScmProvider   provider   = getScmProvider(repository.getProvider());
670             ListScmResult result     = provider.list(repository,
671                                                      new ScmFileSet(new File("."), new File(resourcePath)), false, (ScmVersion) null);
672 
673             if (!result.isSuccess()) {
674                 throw new ResourceDoesNotExistException(result.getProviderMessage());
675             }
676 
677             List<String> files = new ArrayList<String>();
678 
679             for (ScmFile f : getListScmResultFiles(result)) {
680                 files.add(f.getPath());
681                 System.out.println("LIST FILE: " + f + " (path=" + f.getPath() + ")");
682             }
683 
684             return files;
685         } catch (ScmException e) {
686             throw new TransferFailedException("Error getting filelist from SCM", e);
687         }
688     }
689 
690     /**
691      * Wrapper around listScmResult.getFiles() to avoid having a larger method
692      * needing the suppressWarnings attribute.
693      *
694      * @param  result the ListScmResult.
695      *
696      * @return the files.
697      */
698     @SuppressWarnings("unchecked")
699     private List<ScmFile> getListScmResultFiles(ListScmResult result) {
700         return (List<ScmFile>) result.getFiles();
701     }
702 
703     /**
704      * @see org.apache.maven.wagon.AbstractWagon#resourceExists(java.lang.String)
705      */
706     public boolean resourceExists(String resourceName) throws TransferFailedException, AuthorizationException {
707         try {
708             getFileList(resourceName);
709             return true;
710         } catch (ResourceDoesNotExistException e) {
711             return false;
712         }
713     }
714 
715     /**
716      * Get the filename format for a file.
717      *
718      * @param  filename the file name.
719      *
720      * @return the file name.
721      */
722     private String getFilename(String filename) {
723         String fname = StringUtils.replace(filename, "/", File.separator);
724 
725         return FileUtils.filename(fname);
726     }
727 
728     /**
729      * Get the directory format for a file.
730      *
731      * @param  filename the file name.
732      *
733      * @return the directory name.
734      */
735     private String getDirname(String filename) {
736         String fname = StringUtils.replace(filename, "/", File.separator);
737 
738         return FileUtils.dirname(fname);
739     }
740 
741     /**
742      * Wrapper around gitCommand.execute to handle setting the logger.
743      *
744      * @param  scmProvider the SCM provider.
745      * @param  command     the command.
746      * @param  repository  the SCM repository.
747      * @param  fileSet     the file set.
748      * @param  parameters  any parameters to the command.
749      *
750      * @return the SCM result.
751      *
752      * @throws ScmException
753      */
754     protected ScmResult executeCommand(GitExeScmProvider scmProvider, GitCommand command, ScmProviderRepository repository,
755             ScmFileSet fileSet, CommandParameters parameters) throws ScmException {
756         command.setLogger(scmProvider.getLogger());
757 
758         return command.execute(repository, fileSet, parameters);
759     }
760 }