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