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  
58      @Override
59      public ScmResult executeCommand(ScmProviderRepository repository, ScmFileSet fileSet, CommandParameters parameters)
60              throws ScmException {
61          return executeChangeLogCommand(
62                  repository,
63                  fileSet,
64                  parameters.getDate(CommandParameter.START_DATE, null),
65                  parameters.getDate(CommandParameter.END_DATE, null),
66                  (ScmBranch) parameters.getScmVersion(CommandParameter.BRANCH, null),
67                  parameters.getString(CommandParameter.CHANGELOG_DATE_PATTERN, null),
68                  parameters.getScmVersion(CommandParameter.START_SCM_VERSION, null),
69                  parameters.getScmVersion(CommandParameter.END_SCM_VERSION, null),
70                  parameters.getInt(CommandParameter.LIMIT, -1));
71      }
72  
73      /** {@inheritDoc} */
74      @Deprecated
75      @Override
76      protected ChangeLogScmResult executeChangeLogCommand(
77              ScmProviderRepository repo,
78              ScmFileSet fileSet,
79              ScmVersion startVersion,
80              ScmVersion endVersion,
81              String datePattern)
82              throws ScmException {
83          return executeChangeLogCommand(repo, fileSet, null, null, null, datePattern, startVersion, endVersion, null);
84      }
85  
86      /** {@inheritDoc} */
87      @Deprecated
88      @Override
89      protected ChangeLogScmResult executeChangeLogCommand(
90              ScmProviderRepository repo,
91              ScmFileSet fileSet,
92              Date startDate,
93              Date endDate,
94              ScmBranch branch,
95              String datePattern)
96              throws ScmException {
97          return executeChangeLogCommand(repo, fileSet, startDate, endDate, branch, datePattern, null, null, null);
98      }
99  
100     @Override
101     protected ChangeLogScmResult executeChangeLogCommand(ChangeLogScmRequest request) throws ScmException {
102         final ScmVersion startVersion = request.getStartRevision();
103         final ScmVersion endVersion = request.getEndRevision();
104         final ScmFileSet fileSet = request.getScmFileSet();
105         final String datePattern = request.getDatePattern();
106         return executeChangeLogCommand(
107                 request.getScmRepository().getProviderRepository(),
108                 fileSet,
109                 request.getStartDate(),
110                 request.getEndDate(),
111                 request.getScmBranch(),
112                 datePattern,
113                 startVersion,
114                 endVersion,
115                 request.getLimit());
116     }
117 
118     private ChangeLogScmResult executeChangeLogCommand(
119             ScmProviderRepository repo,
120             ScmFileSet fileSet,
121             Date startDate,
122             Date endDate,
123             ScmBranch branch,
124             String datePattern,
125             ScmVersion startVersion,
126             ScmVersion endVersion,
127             Integer limit)
128             throws ScmException {
129         Commandline cl = createCommandLine(
130                 (SvnScmProviderRepository) repo,
131                 fileSet.getBasedir(),
132                 branch,
133                 startDate,
134                 endDate,
135                 startVersion,
136                 endVersion,
137                 limit);
138 
139         SvnChangeLogConsumer consumer = new SvnChangeLogConsumer(datePattern);
140 
141         CommandLineUtils.StringStreamConsumer stderr = new CommandLineUtils.StringStreamConsumer();
142 
143         if (logger.isInfoEnabled()) {
144             logger.info("Executing: " + SvnCommandLineUtils.cryptPassword(cl));
145 
146             if (Os.isFamily(Os.FAMILY_WINDOWS)) {
147                 logger.info("Working directory: " + cl.getWorkingDirectory().getAbsolutePath());
148             }
149         }
150 
151         int exitCode;
152 
153         try {
154             exitCode = SvnCommandLineUtils.execute(cl, consumer, stderr);
155         } catch (CommandLineException ex) {
156             throw new ScmException("Error while executing svn command.", ex);
157         }
158 
159         if (exitCode != 0) {
160             return new ChangeLogScmResult(cl.toString(), "The svn command failed.", stderr.getOutput(), false);
161         }
162         ChangeLogSet changeLogSet = new ChangeLogSet(consumer.getModifications(), startDate, endDate);
163         changeLogSet.setStartVersion(startVersion);
164         changeLogSet.setEndVersion(endVersion);
165 
166         return new ChangeLogScmResult(cl.toString(), changeLogSet);
167     }
168 
169     // ----------------------------------------------------------------------
170     //
171     // ----------------------------------------------------------------------
172 
173     public static Commandline createCommandLine(
174             SvnScmProviderRepository repository,
175             File workingDirectory,
176             ScmBranch branch,
177             Date startDate,
178             Date endDate,
179             ScmVersion startVersion,
180             ScmVersion endVersion) {
181         return createCommandLine(
182                 repository, workingDirectory, branch, startDate, endDate, startVersion, endVersion, null);
183     }
184 
185     public static Commandline createCommandLine(
186             SvnScmProviderRepository repository,
187             File workingDirectory,
188             ScmBranch branch,
189             Date startDate,
190             Date endDate,
191             ScmVersion startVersion,
192             ScmVersion endVersion,
193             Integer limit) {
194         SimpleDateFormat dateFormat = new SimpleDateFormat(DATE_FORMAT);
195 
196         dateFormat.setTimeZone(TimeZone.getTimeZone("GMT"));
197 
198         Commandline cl = SvnCommandLineUtils.getBaseSvnCommandLine(workingDirectory, repository);
199 
200         cl.createArg().setValue("log");
201 
202         cl.createArg().setValue("-v");
203 
204         // TODO: May want to add some kind of support for --stop-on-copy and --limit NUM
205 
206         if (limit != null && limit > 0) {
207             cl.createArg().setValue("--limit");
208             cl.createArg().setValue(Integer.toString(limit));
209         }
210 
211         if (startDate != null) {
212             cl.createArg().setValue("-r");
213 
214             if (endDate != null) {
215                 cl.createArg()
216                         .setValue("{" + dateFormat.format(startDate) + "}" + ":" + "{" + dateFormat.format(endDate)
217                                 + "}");
218             } else {
219                 cl.createArg().setValue("{" + dateFormat.format(startDate) + "}:HEAD");
220             }
221         }
222 
223         if (startVersion != null) {
224             cl.createArg().setValue("-r");
225 
226             if (endVersion != null) {
227                 if (startVersion.getName().equals(endVersion.getName())) {
228                     cl.createArg().setValue(startVersion.getName());
229                 } else {
230                     cl.createArg().setValue(startVersion.getName() + ":" + endVersion.getName());
231                 }
232             } else {
233                 cl.createArg().setValue(startVersion.getName() + ":HEAD");
234             }
235         }
236 
237         if (branch != null && StringUtils.isNotEmpty(branch.getName())) {
238             // By specifying a branch and this repository url below, subversion should show
239             // the changelog of that branch, but limit it to paths that also occur in this repository.
240             if (branch instanceof ScmTag) {
241                 String tagUrl = SvnTagBranchUtils.resolveTagUrl(repository, (ScmTag) branch);
242                 cl.createArg().setValue(tagUrl + "@");
243             } else {
244                 String branchUrl = SvnTagBranchUtils.resolveBranchUrl(repository, branch);
245                 cl.createArg().setValue(branchUrl + "@");
246             }
247         }
248 
249         if (endVersion == null || !Objects.equals("BASE", endVersion.getName())) {
250             cl.createArg().setValue(repository.getUrl() + "@");
251         }
252 
253         return cl;
254     }
255 }