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 * 054 */ 055public class SvnChangeLogCommand extends AbstractChangeLogCommand implements SvnCommand { 056 private static final String DATE_FORMAT = "yyyy-MM-dd HH:mm:ss Z"; 057 058 @Override 059 public ScmResult executeCommand(ScmProviderRepository repository, ScmFileSet fileSet, CommandParameters parameters) 060 throws ScmException { 061 return executeChangeLogCommand( 062 repository, 063 fileSet, 064 parameters.getDate(CommandParameter.START_DATE, null), 065 parameters.getDate(CommandParameter.END_DATE, null), 066 (ScmBranch) parameters.getScmVersion(CommandParameter.BRANCH, null), 067 parameters.getString(CommandParameter.CHANGELOG_DATE_PATTERN, null), 068 parameters.getScmVersion(CommandParameter.START_SCM_VERSION, null), 069 parameters.getScmVersion(CommandParameter.END_SCM_VERSION, null), 070 parameters.getInt(CommandParameter.LIMIT, -1)); 071 } 072 073 /** {@inheritDoc} */ 074 @Deprecated 075 @Override 076 protected ChangeLogScmResult executeChangeLogCommand( 077 ScmProviderRepository repo, 078 ScmFileSet fileSet, 079 ScmVersion startVersion, 080 ScmVersion endVersion, 081 String datePattern) 082 throws ScmException { 083 return executeChangeLogCommand(repo, fileSet, null, null, null, datePattern, startVersion, endVersion, null); 084 } 085 086 /** {@inheritDoc} */ 087 @Deprecated 088 @Override 089 protected ChangeLogScmResult executeChangeLogCommand( 090 ScmProviderRepository repo, 091 ScmFileSet fileSet, 092 Date startDate, 093 Date endDate, 094 ScmBranch branch, 095 String datePattern) 096 throws ScmException { 097 return executeChangeLogCommand(repo, fileSet, startDate, endDate, branch, datePattern, null, null, null); 098 } 099 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}