001/* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, 013 * software distributed under the License is distributed on an 014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 015 * KIND, either express or implied. See the License for the 016 * specific language governing permissions and limitations 017 * under the License. 018 */ 019package org.apache.maven.scm.provider.svn.svnexe.command.changelog; 020 021import java.io.File; 022import java.text.SimpleDateFormat; 023import java.util.Date; 024import java.util.Objects; 025import java.util.TimeZone; 026 027import org.apache.commons.lang3.StringUtils; 028import org.apache.maven.scm.CommandParameter; 029import org.apache.maven.scm.CommandParameters; 030import org.apache.maven.scm.ScmBranch; 031import org.apache.maven.scm.ScmException; 032import org.apache.maven.scm.ScmFileSet; 033import org.apache.maven.scm.ScmResult; 034import org.apache.maven.scm.ScmTag; 035import org.apache.maven.scm.ScmVersion; 036import org.apache.maven.scm.command.changelog.AbstractChangeLogCommand; 037import org.apache.maven.scm.command.changelog.ChangeLogScmRequest; 038import org.apache.maven.scm.command.changelog.ChangeLogScmResult; 039import org.apache.maven.scm.command.changelog.ChangeLogSet; 040import org.apache.maven.scm.provider.ScmProviderRepository; 041import org.apache.maven.scm.provider.svn.SvnTagBranchUtils; 042import org.apache.maven.scm.provider.svn.command.SvnCommand; 043import org.apache.maven.scm.provider.svn.repository.SvnScmProviderRepository; 044import org.apache.maven.scm.provider.svn.svnexe.command.SvnCommandLineUtils; 045import org.codehaus.plexus.util.Os; 046import org.codehaus.plexus.util.cli.CommandLineException; 047import org.codehaus.plexus.util.cli.CommandLineUtils; 048import org.codehaus.plexus.util.cli.Commandline; 049 050/** 051 * @author <a href="mailto:evenisse@apache.org">Emmanuel Venisse</a> 052 * @author Olivier Lamy 053 */ 054public class SvnChangeLogCommand extends AbstractChangeLogCommand implements SvnCommand { 055 private static final String DATE_FORMAT = "yyyy-MM-dd HH:mm:ss Z"; 056 private final boolean interactive; 057 058 public SvnChangeLogCommand(boolean interactive) { 059 this.interactive = interactive; 060 } 061 062 @Override 063 public ScmResult executeCommand(ScmProviderRepository repository, ScmFileSet fileSet, CommandParameters parameters) 064 throws ScmException { 065 return executeChangeLogCommand( 066 repository, 067 fileSet, 068 parameters.getDate(CommandParameter.START_DATE, null), 069 parameters.getDate(CommandParameter.END_DATE, null), 070 (ScmBranch) parameters.getScmVersion(CommandParameter.BRANCH, null), 071 parameters.getString(CommandParameter.CHANGELOG_DATE_PATTERN, null), 072 parameters.getScmVersion(CommandParameter.START_SCM_VERSION, null), 073 parameters.getScmVersion(CommandParameter.END_SCM_VERSION, null), 074 parameters.getInt(CommandParameter.LIMIT, -1)); 075 } 076 077 /** 078 * {@inheritDoc} 079 */ 080 @Deprecated 081 @Override 082 protected ChangeLogScmResult executeChangeLogCommand( 083 ScmProviderRepository repo, 084 ScmFileSet fileSet, 085 ScmVersion startVersion, 086 ScmVersion endVersion, 087 String datePattern) 088 throws ScmException { 089 return executeChangeLogCommand(repo, fileSet, null, null, null, datePattern, startVersion, endVersion, null); 090 } 091 092 /** 093 * {@inheritDoc} 094 */ 095 @Deprecated 096 @Override 097 protected ChangeLogScmResult executeChangeLogCommand( 098 ScmProviderRepository repo, 099 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}