View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.maven.scm.provider.svn.svnexe.command.changelog;
20  
21  import java.io.File;
22  import java.text.SimpleDateFormat;
23  import java.util.Date;
24  import java.util.Objects;
25  import java.util.TimeZone;
26  
27  import org.apache.commons.lang3.StringUtils;
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.ScmFileSet;
33  import org.apache.maven.scm.ScmResult;
34  import org.apache.maven.scm.ScmTag;
35  import org.apache.maven.scm.ScmVersion;
36  import org.apache.maven.scm.command.changelog.AbstractChangeLogCommand;
37  import org.apache.maven.scm.command.changelog.ChangeLogScmRequest;
38  import org.apache.maven.scm.command.changelog.ChangeLogScmResult;
39  import org.apache.maven.scm.command.changelog.ChangeLogSet;
40  import org.apache.maven.scm.provider.ScmProviderRepository;
41  import org.apache.maven.scm.provider.svn.SvnTagBranchUtils;
42  import org.apache.maven.scm.provider.svn.command.SvnCommand;
43  import org.apache.maven.scm.provider.svn.repository.SvnScmProviderRepository;
44  import org.apache.maven.scm.provider.svn.svnexe.command.SvnCommandLineUtils;
45  import org.codehaus.plexus.util.Os;
46  import org.codehaus.plexus.util.cli.CommandLineException;
47  import org.codehaus.plexus.util.cli.CommandLineUtils;
48  import org.codehaus.plexus.util.cli.Commandline;
49  
50  /**
51   * @author <a href="mailto:evenisse@apache.org">Emmanuel Venisse</a>
52   * @author Olivier Lamy
53   *
54   */
55  public class SvnChangeLogCommand extends AbstractChangeLogCommand implements SvnCommand {
56      private static final String DATE_FORMAT = "yyyy-MM-dd HH:mm:ss Z";
57      private final boolean interactive;
58  
59      public SvnChangeLogCommand(boolean interactive) {
60          this.interactive = interactive;
61      }
62  
63      @Override
64      public ScmResult executeCommand(ScmProviderRepository repository, ScmFileSet fileSet, CommandParameters parameters)
65              throws ScmException {
66          return executeChangeLogCommand(
67                  repository,
68                  fileSet,
69                  parameters.getDate(CommandParameter.START_DATE, null),
70                  parameters.getDate(CommandParameter.END_DATE, null),
71                  (ScmBranch) parameters.getScmVersion(CommandParameter.BRANCH, null),
72                  parameters.getString(CommandParameter.CHANGELOG_DATE_PATTERN, null),
73                  parameters.getScmVersion(CommandParameter.START_SCM_VERSION, null),
74                  parameters.getScmVersion(CommandParameter.END_SCM_VERSION, null),
75                  parameters.getInt(CommandParameter.LIMIT, -1));
76      }
77  
78      /** {@inheritDoc} */
79      @Deprecated
80      @Override
81      protected ChangeLogScmResult executeChangeLogCommand(
82              ScmProviderRepository repo,
83              ScmFileSet fileSet,
84              ScmVersion startVersion,
85              ScmVersion endVersion,
86              String datePattern)
87              throws ScmException {
88          return executeChangeLogCommand(repo, fileSet, null, null, null, datePattern, startVersion, endVersion, null);
89      }
90  
91      /** {@inheritDoc} */
92      @Deprecated
93      @Override
94      protected ChangeLogScmResult executeChangeLogCommand(
95              ScmProviderRepository repo,
96              ScmFileSet fileSet,
97              Date startDate,
98              Date endDate,
99              ScmBranch branch,
100             String datePattern)
101             throws ScmException {
102         return executeChangeLogCommand(repo, fileSet, startDate, endDate, branch, datePattern, null, null, null);
103     }
104 
105     @Override
106     protected ChangeLogScmResult executeChangeLogCommand(ChangeLogScmRequest request) throws ScmException {
107         final ScmVersion startVersion = request.getStartRevision();
108         final ScmVersion endVersion = request.getEndRevision();
109         final ScmFileSet fileSet = request.getScmFileSet();
110         final String datePattern = request.getDatePattern();
111         return executeChangeLogCommand(
112                 request.getScmRepository().getProviderRepository(),
113                 fileSet,
114                 request.getStartDate(),
115                 request.getEndDate(),
116                 request.getScmBranch(),
117                 datePattern,
118                 startVersion,
119                 endVersion,
120                 request.getLimit());
121     }
122 
123     private ChangeLogScmResult executeChangeLogCommand(
124             ScmProviderRepository repo,
125             ScmFileSet fileSet,
126             Date startDate,
127             Date endDate,
128             ScmBranch branch,
129             String datePattern,
130             ScmVersion startVersion,
131             ScmVersion endVersion,
132             Integer limit)
133             throws ScmException {
134         Commandline cl = createCommandLine(
135                 (SvnScmProviderRepository) repo,
136                 fileSet.getBasedir(),
137                 branch,
138                 startDate,
139                 endDate,
140                 startVersion,
141                 endVersion,
142                 limit);
143 
144         SvnChangeLogConsumer consumer = new SvnChangeLogConsumer(datePattern);
145 
146         CommandLineUtils.StringStreamConsumer stderr = new CommandLineUtils.StringStreamConsumer();
147 
148         if (logger.isInfoEnabled()) {
149             logger.info("Executing: " + SvnCommandLineUtils.cryptPassword(cl));
150 
151             if (Os.isFamily(Os.FAMILY_WINDOWS)) {
152                 logger.info("Working directory: " + cl.getWorkingDirectory().getAbsolutePath());
153             }
154         }
155 
156         int exitCode;
157 
158         try {
159             exitCode = SvnCommandLineUtils.execute(cl, consumer, stderr);
160         } catch (CommandLineException ex) {
161             throw new ScmException("Error while executing svn command.", ex);
162         }
163 
164         if (exitCode != 0) {
165             return new ChangeLogScmResult(cl.toString(), "The svn command failed.", stderr.getOutput(), false);
166         }
167         ChangeLogSet changeLogSet = new ChangeLogSet(consumer.getModifications(), startDate, endDate);
168         changeLogSet.setStartVersion(startVersion);
169         changeLogSet.setEndVersion(endVersion);
170 
171         return new ChangeLogScmResult(cl.toString(), changeLogSet);
172     }
173 
174     // ----------------------------------------------------------------------
175     //
176     // ----------------------------------------------------------------------
177 
178     public Commandline createCommandLine(
179             SvnScmProviderRepository repository,
180             File workingDirectory,
181             ScmBranch branch,
182             Date startDate,
183             Date endDate,
184             ScmVersion startVersion,
185             ScmVersion endVersion) {
186         return createCommandLine(
187                 repository, workingDirectory, branch, startDate, endDate, startVersion, endVersion, null);
188     }
189 
190     public Commandline createCommandLine(
191             SvnScmProviderRepository repository,
192             File workingDirectory,
193             ScmBranch branch,
194             Date startDate,
195             Date endDate,
196             ScmVersion startVersion,
197             ScmVersion endVersion,
198             Integer limit) {
199         SimpleDateFormat dateFormat = new SimpleDateFormat(DATE_FORMAT);
200 
201         dateFormat.setTimeZone(TimeZone.getTimeZone("GMT"));
202 
203         Commandline cl = SvnCommandLineUtils.getBaseSvnCommandLine(workingDirectory, repository, interactive);
204 
205         cl.createArg().setValue("log");
206 
207         cl.createArg().setValue("-v");
208 
209         // TODO: May want to add some kind of support for --stop-on-copy and --limit NUM
210 
211         if (limit != null && limit > 0) {
212             cl.createArg().setValue("--limit");
213             cl.createArg().setValue(Integer.toString(limit));
214         }
215 
216         if (startDate != null) {
217             cl.createArg().setValue("-r");
218 
219             if (endDate != null) {
220                 cl.createArg()
221                         .setValue("{" + dateFormat.format(startDate) + "}" + ":" + "{" + dateFormat.format(endDate)
222                                 + "}");
223             } else {
224                 cl.createArg().setValue("{" + dateFormat.format(startDate) + "}:HEAD");
225             }
226         }
227 
228         if (startVersion != null) {
229             cl.createArg().setValue("-r");
230 
231             if (endVersion != null) {
232                 if (startVersion.getName().equals(endVersion.getName())) {
233                     cl.createArg().setValue(startVersion.getName());
234                 } else {
235                     cl.createArg().setValue(startVersion.getName() + ":" + endVersion.getName());
236                 }
237             } else {
238                 cl.createArg().setValue(startVersion.getName() + ":HEAD");
239             }
240         }
241 
242         if (branch != null && StringUtils.isNotEmpty(branch.getName())) {
243             // By specifying a branch and this repository url below, subversion should show
244             // the changelog of that branch, but limit it to paths that also occur in this repository.
245             if (branch instanceof ScmTag) {
246                 String tagUrl = SvnTagBranchUtils.resolveTagUrl(repository, (ScmTag) branch);
247                 cl.createArg().setValue(tagUrl + "@");
248             } else {
249                 String branchUrl = SvnTagBranchUtils.resolveBranchUrl(repository, branch);
250                 cl.createArg().setValue(branchUrl + "@");
251             }
252         }
253 
254         if (endVersion == null || !Objects.equals("BASE", endVersion.getName())) {
255             cl.createArg().setValue(repository.getUrl() + "@");
256         }
257 
258         return cl;
259     }
260 }