View Javadoc

1   /*
2    * Copyright 2006-2012 smartics, Kronseder & Reiner GmbH
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 de.smartics.maven.plugin.buildmetadata.scm.maven;
17  
18  import java.util.Iterator;
19  import java.util.List;
20  
21  import org.apache.commons.lang.StringUtils;
22  import org.apache.commons.logging.Log;
23  import org.apache.commons.logging.LogFactory;
24  import org.apache.maven.scm.ChangeFile;
25  import org.apache.maven.scm.ChangeSet;
26  import org.apache.maven.scm.ScmFile;
27  import org.apache.maven.scm.ScmFileSet;
28  import org.apache.maven.scm.ScmVersion;
29  import org.apache.maven.scm.command.changelog.ChangeLogScmResult;
30  import org.apache.maven.scm.command.changelog.ChangeLogSet;
31  import org.apache.maven.scm.command.status.StatusScmResult;
32  import org.apache.maven.scm.manager.NoSuchScmProviderException;
33  import org.apache.maven.scm.manager.ScmManager;
34  import org.apache.maven.scm.provider.ScmProvider;
35  import org.apache.maven.scm.repository.ScmRepository;
36  
37  import de.smartics.maven.plugin.buildmetadata.scm.LocallyModifiedInfo;
38  import de.smartics.maven.plugin.buildmetadata.scm.Revision;
39  import de.smartics.maven.plugin.buildmetadata.scm.RevisionNumberFetcher;
40  import de.smartics.maven.plugin.buildmetadata.scm.ScmException;
41  
42  /**
43   * Implementation on the Maven SCM implementation to fetch the latest revision
44   * number.
45   *
46   * @author <a href="mailto:robert.reiner@smartics.de">Robert Reiner</a>
47   * @version $Revision:591 $
48   */
49  public final class MavenScmRevisionNumberFetcher implements RevisionNumberFetcher
50  {
51    // ********************************* Fields *********************************
52  
53    // --- constants ------------------------------------------------------------
54  
55    /**
56     * Reference to the logger for this class.
57     */
58    private static final Log LOG = LogFactory
59        .getLog(MavenScmRevisionNumberFetcher.class);
60  
61    // --- members --------------------------------------------------------------
62  
63    /**
64     * The SCM manager to access to SCM system.
65     */
66    private final ScmManager scmManager;
67  
68    /**
69     * The information to connect to the SCM system.
70     */
71    private final ScmConnectionInfo scmConnectionInfo;
72  
73    /**
74     * Information to retrieve the revision information from the SCM after the
75     * connection is established.
76     */
77    private final ScmAccessInfo scmAccessInfo;
78  
79    // ****************************** Initializer *******************************
80  
81    // ****************************** Constructors ******************************
82  
83    /**
84     * Default constructor.
85     *
86     * @param scmManager the SCM manager to access to SCM system.
87     * @param scmConnectionInfo the information to connect to the SCM system.
88     * @param scmAccessInfo the value for scmAccessInfo.
89     */
90    public MavenScmRevisionNumberFetcher(final ScmManager scmManager,
91        final ScmConnectionInfo scmConnectionInfo,
92        final ScmAccessInfo scmAccessInfo)
93    {
94      this.scmManager = scmManager;
95      this.scmConnectionInfo = scmConnectionInfo;
96      this.scmAccessInfo = scmAccessInfo;
97    }
98  
99    // ****************************** Inner Classes *****************************
100 
101   // ********************************* Methods ********************************
102 
103   // --- init -----------------------------------------------------------------
104 
105   // --- get&set --------------------------------------------------------------
106 
107   // --- business -------------------------------------------------------------
108 
109   /**
110    * {@inheritDoc}
111    *
112    * @see de.smartics.maven.plugin.buildmetadata.scm.RevisionNumberFetcher#fetchLatestRevisionNumber()
113    */
114   public Revision fetchLatestRevisionNumber() throws ScmException
115   {
116     if (LOG.isDebugEnabled())
117     {
118       LOG.debug("  Fetching latest revision number.\n    "
119                 + this.scmConnectionInfo + "\n    " + this.scmAccessInfo);
120     }
121 
122     final ScmRepository repository =
123         scmConnectionInfo.createRepository(scmManager);
124     final ScmProvider provider = createScmProvider(repository);
125     final ChangeLogScmResult result =
126         scmAccessInfo.fetchChangeLog(repository, provider);
127 
128     if (result != null)
129     {
130       final ChangeLogSet changeLogSet = result.getChangeLog();
131       final Revision revision = findEndVersion(changeLogSet);
132       if (LOG.isDebugEnabled())
133       {
134         LOG.debug("  Found revision '" + revision + "'.");
135       }
136       return revision;
137     }
138     else if (LOG.isDebugEnabled())
139     {
140       LOG.debug("  No revision information found.");
141     }
142     return null;
143   }
144 
145   /**
146    * {@inheritDoc}
147    *
148    * @see de.smartics.maven.plugin.buildmetadata.scm.RevisionNumberFetcher#containsModifications(org.apache.maven.scm.ScmFileSet)
149    */
150   public LocallyModifiedInfo containsModifications(final ScmFileSet fileSet)
151     throws ScmException
152   {
153     if (LOG.isDebugEnabled())
154     {
155       LOG.debug("  Fetching modification information.\n    "
156                 + this.scmConnectionInfo + "\n    " + this.scmAccessInfo);
157     }
158 
159     try
160     {
161       final ScmRepository repository =
162           scmConnectionInfo.createRepository(scmManager);
163       final ScmProvider provider = createScmProvider(repository);
164       final StatusScmResult result = provider.status(repository, fileSet);
165 
166       if (result.isSuccess())
167       {
168         return createLocallyModifiedInfo(result);
169       }
170       else
171       {
172         final String message =
173             result.getProviderMessage() + ": " + result.getCommandOutput();
174         if (LOG.isDebugEnabled())
175         {
176           LOG.debug(message);
177         }
178 
179         throw new ScmException(message);
180       }
181     }
182     catch (final org.apache.maven.scm.ScmException e)
183     {
184       throw new ScmException(e);
185     }
186   }
187 
188   @SuppressWarnings("unchecked")
189   private LocallyModifiedInfo createLocallyModifiedInfo(
190       final StatusScmResult result)
191   {
192     final List<ScmFile> changedFiles = filter(result.getChangedFiles());
193     final boolean locallyModified = !changedFiles.isEmpty();
194     if (LOG.isDebugEnabled())
195     {
196       LOG.debug("  Modifications have" + (locallyModified ? "" : " not")
197                 + " been found.");
198     }
199     return new LocallyModifiedInfo(locallyModified, locallyModified
200         ? toString(changedFiles) : null);
201   }
202 
203   private List<ScmFile> filter(final List<ScmFile> files)
204   {
205     if (this.scmAccessInfo.isIgnoreDotFilesInBaseDir())
206     {
207       filterDotFiles(files);
208     }
209     return files;
210   }
211 
212   private void filterDotFiles(final List<ScmFile> files)
213   {
214     for (final Iterator<ScmFile> i = files.iterator(); i.hasNext();)
215     {
216       final ScmFile file = i.next();
217       final String path = file.getPath();
218       if (path.length() > 0 && path.charAt(0) == '.')
219       {
220         i.remove();
221       }
222     }
223   }
224 
225   /**
226    * Renders the files to a blank separated list of file names.
227    *
228    * @param items the file items.
229    * @return the string representation of the files.
230    */
231   private String toString(final List<?> items)
232   {
233     final StringBuilder buffer = new StringBuilder(512);
234     for (Object item : items)
235     {
236       buffer.append(item).append(' ');
237     }
238     return StringUtils.chomp(buffer.toString());
239   }
240 
241   /**
242    * Finds the largest revision number.
243    *
244    * @impl Currently we assume the the largest revision is provided by the last
245    *       entry of the set.
246    * @param changeLogSet the set of change log entries to compare the revision
247    *          numbers to find the largest.
248    * @return the largest revision number from the set or <code>null</code> if no
249    *         end version can be found.
250    */
251   @SuppressWarnings("unchecked")
252   private Revision findEndVersion(final ChangeLogSet changeLogSet)
253   {
254     if (changeLogSet != null)
255     {
256       final ScmVersion endVersion = changeLogSet.getEndVersion();
257       if (endVersion != null)
258       {
259         if(LOG.isDebugEnabled())
260         {
261           LOG.debug("End version found.");
262         }
263         return new MavenRevision(endVersion, changeLogSet.getEndDate());
264       }
265 
266       final List<ChangeSet> changeSets = changeLogSet.getChangeSets();
267       if (!changeSets.isEmpty())
268       {
269         final int lastIndex = changeSets.size() - 1;
270         for (int index = lastIndex; index >= 0; index--)
271         {
272           final ChangeSet set = changeSets.get(lastIndex);
273           final List<ChangeFile> changeFiles = set.getFiles();
274           if (!changeFiles.isEmpty())
275           {
276             final ChangeFile file = changeFiles.get(0);
277             final String revision = file.getRevision();
278             if (revision != null)
279             {
280               return new StringRevision(revision, set.getDate());
281             }
282           }
283           else
284           {
285             if(LOG.isDebugEnabled())
286             {
287               LOG.debug("No change files found.");
288             }
289           }
290         }
291       }
292       else
293       {
294         if(LOG.isDebugEnabled())
295         {
296           LOG.debug("No change set found.");
297         }
298       }
299     }
300     else
301     {
302       if(LOG.isDebugEnabled())
303       {
304         LOG.debug("No change log set found.");
305       }
306     }
307 
308     return null;
309   }
310 
311   /**
312    * Creates the provider instance to access the given repository.
313    *
314    * @param repository the repository to access with the provider to be created.
315    * @return the provider to access the given repository.
316    * @throws ScmException if the provider cannot be created.
317    */
318   private ScmProvider createScmProvider(final ScmRepository repository)
319     throws ScmException
320   {
321     try
322     {
323       final ScmProvider provider =
324           scmManager.getProviderByRepository(repository);
325       return provider;
326     }
327     catch (final NoSuchScmProviderException e)
328     {
329       throw new ScmException("Cannot create SCM provider.", e);
330     }
331   }
332 
333   // --- object basics --------------------------------------------------------
334 
335 }