001 package org.apache.maven.scm.provider.accurev;
002
003 /*
004 * Licensed to the Apache Software Foundation (ASF) under one
005 * or more contributor license agreements. See the NOTICE file
006 * distributed with this work for additional information
007 * regarding copyright ownership. The ASF licenses this file
008 * to you under the Apache License, Version 2.0 (the
009 * "License"); you may not use this file except in compliance
010 * with the License. You may obtain a copy of the License at
011 *
012 * http://www.apache.org/licenses/LICENSE-2.0
013 *
014 * Unless required by applicable law or agreed to in writing,
015 * software distributed under the License is distributed on an
016 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
017 * KIND, either express or implied. See the License for the
018 * specific language governing permissions and limitations
019 * under the License.
020 */
021
022 import java.io.File;
023 import java.util.ArrayList;
024 import java.util.Collections;
025 import java.util.Date;
026 import java.util.HashMap;
027 import java.util.List;
028 import java.util.Map;
029 import java.util.Set;
030
031 import org.apache.maven.scm.ChangeFile;
032 import org.apache.maven.scm.ChangeSet;
033 import org.apache.maven.scm.CommandParameter;
034 import org.apache.maven.scm.CommandParameters;
035 import org.apache.maven.scm.ScmException;
036 import org.apache.maven.scm.ScmFile;
037 import org.apache.maven.scm.ScmFileSet;
038 import org.apache.maven.scm.ScmRevision;
039 import org.apache.maven.scm.command.add.AddScmResult;
040 import org.apache.maven.scm.command.blame.BlameScmResult;
041 import org.apache.maven.scm.command.changelog.ChangeLogScmResult;
042 import org.apache.maven.scm.command.checkin.CheckInScmResult;
043 import org.apache.maven.scm.command.checkout.CheckOutScmResult;
044 import org.apache.maven.scm.command.export.ExportScmResult;
045 import org.apache.maven.scm.command.login.LoginScmResult;
046 import org.apache.maven.scm.command.remove.RemoveScmResult;
047 import org.apache.maven.scm.command.status.StatusScmResult;
048 import org.apache.maven.scm.command.tag.TagScmResult;
049 import org.apache.maven.scm.command.update.UpdateScmResult;
050 import org.apache.maven.scm.provider.AbstractScmProvider;
051 import org.apache.maven.scm.provider.ScmProviderRepository;
052 import org.apache.maven.scm.provider.accurev.cli.AccuRevCommandLine;
053 import org.apache.maven.scm.provider.accurev.command.add.AccuRevAddCommand;
054 import org.apache.maven.scm.provider.accurev.command.blame.AccuRevBlameCommand;
055 import org.apache.maven.scm.provider.accurev.command.changelog.AccuRevChangeLogCommand;
056 import org.apache.maven.scm.provider.accurev.command.checkin.AccuRevCheckInCommand;
057 import org.apache.maven.scm.provider.accurev.command.checkout.AccuRevCheckOutCommand;
058 import org.apache.maven.scm.provider.accurev.command.export.AccuRevExportCommand;
059 import org.apache.maven.scm.provider.accurev.command.login.AccuRevLoginCommand;
060 import org.apache.maven.scm.provider.accurev.command.remove.AccuRevRemoveCommand;
061 import org.apache.maven.scm.provider.accurev.command.status.AccuRevStatusCommand;
062 import org.apache.maven.scm.provider.accurev.command.tag.AccuRevTagCommand;
063 import org.apache.maven.scm.provider.accurev.command.update.AccuRevUpdateCommand;
064 import org.apache.maven.scm.provider.accurev.command.update.AccuRevUpdateScmResult;
065 import org.apache.maven.scm.provider.accurev.util.QuotedPropertyParser;
066 import org.apache.maven.scm.repository.ScmRepositoryException;
067 import org.apache.maven.scm.repository.UnknownRepositoryStructure;
068 import org.codehaus.plexus.util.StringUtils;
069
070 /**
071 * AccuRev integration with Maven SCM
072 *
073 * @plexus.component role="org.apache.maven.scm.provider.ScmProvider" role-hint="accurev"
074 */
075 public class AccuRevScmProvider
076 extends AbstractScmProvider
077 {
078
079 public static final String ACCUREV_EXECUTABLE_PROPERTY = "accurevExe";
080
081 public static final String TAG_FORMAT_PROPERTY = "tagFormat";
082
083 public static final String SYSTEM_PROPERTY_PREFIX = "maven.scm.accurev.";
084
085 public String getScmType()
086 {
087
088 return "accurev";
089 }
090
091 /**
092 * The basic url parsing approach is to be as loose as possible. If you specify as per the docs you'll get what you
093 * expect. If you do something else the result is undefined. Don't use "/" "\" or "@" as the delimiter,
094 */
095 public ScmProviderRepository makeProviderScmRepository( String scmSpecificUrl, char delimiter )
096 throws ScmRepositoryException
097 {
098
099 List<String> validationMessages = new ArrayList<String>();
100
101 String[] tokens = StringUtils.split( scmSpecificUrl, Character.toString( delimiter ) );
102
103 // [[user][/pass]@host[:port]][:stream][:\project\dir]
104
105 String basisStream = null;
106 String projectPath = null;
107 int port = AccuRev.DEFAULT_PORT;
108 String host = null;
109 String user = null;
110 String password = null;
111 Map<String, String> properties = new HashMap<String, String>();
112 properties.put( TAG_FORMAT_PROPERTY, AccuRevScmProviderRepository.DEFAULT_TAG_FORMAT );
113 properties.put( ACCUREV_EXECUTABLE_PROPERTY, AccuRev.DEFAULT_ACCUREV_EXECUTABLE );
114
115 fillSystemProperties( properties );
116
117 int i = 0;
118 while ( i < tokens.length )
119 {
120 int at = tokens[i].indexOf( '@' );
121 // prefer "/", better not have a "/" or a "\\" in your password.
122 int slash = tokens[i].indexOf( '/' );
123 slash = slash < 0 ? tokens[i].indexOf( '\\' ) : slash;
124
125 int qMark = tokens[i].indexOf( '?' );
126
127 if ( qMark == 0 )
128 {
129 QuotedPropertyParser.parse( tokens[i].substring( 1 ), properties );
130 }
131 else if ( slash == 0 )
132 {
133 // this is the project path
134 projectPath = tokens[i].substring( 1 );
135 break;
136 }
137 else if ( ( slash > 0 || ( at >= 0 ) ) && host == null && user == null )
138 {
139 // user/pass@host
140 int len = tokens[i].length();
141 if ( at >= 0 && len > at )
142 {
143 // everything after the "@"
144 host = tokens[i].substring( at + 1 );
145 }
146
147 if ( slash > 0 )
148 {
149 // user up to /
150 user = tokens[i].substring( 0, slash );
151 // pass between / and @
152 password = tokens[i].substring( slash + 1, at < 0 ? len : at );
153 }
154 else
155 {
156 // no /, user from beginning to @
157 user = tokens[i].substring( 0, at < 0 ? len : at );
158 }
159
160 }
161 else if ( host != null && tokens[i].matches( "^[0-9]+$" ) )
162 {
163 // only valid entry with all digits is the port specification.
164 port = Integer.parseInt( tokens[i] );
165 }
166 else
167 {
168 basisStream = tokens[i];
169 }
170
171 i++;
172 }
173
174 if ( i < tokens.length )
175 {
176 validationMessages.add( "Unknown tokens in URL " + scmSpecificUrl );
177 }
178
179 AccuRevScmProviderRepository repo = new AccuRevScmProviderRepository();
180 repo.setLogger( getLogger() );
181 if ( !StringUtils.isEmpty( user ) )
182 {
183 repo.setUser( user );
184 }
185 if ( !StringUtils.isEmpty( password ) )
186 {
187 repo.setPassword( password );
188 }
189 if ( !StringUtils.isEmpty( basisStream ) )
190 {
191 repo.setStreamName( basisStream );
192 }
193 if ( !StringUtils.isEmpty( projectPath ) )
194 {
195 repo.setProjectPath( projectPath );
196 }
197 if ( !StringUtils.isEmpty( host ) )
198 {
199 repo.setHost( host );
200 }
201 repo.setPort( port );
202 repo.setTagFormat( properties.get( TAG_FORMAT_PROPERTY ) );
203
204 AccuRevCommandLine accuRev = new AccuRevCommandLine( host, port );
205 accuRev.setLogger( getLogger() );
206 accuRev.setExecutable( properties.get( ACCUREV_EXECUTABLE_PROPERTY ) );
207 repo.setAccuRev( accuRev );
208
209 return repo;
210
211 }
212
213 private void fillSystemProperties( Map<String, String> properties )
214 {
215
216 Set<String> propertyKeys = properties.keySet();
217 for ( String key : propertyKeys )
218 {
219 String systemPropertyKey = SYSTEM_PROPERTY_PREFIX + key;
220 String systemProperty = System.getProperty( systemPropertyKey );
221 if ( systemProperty != null )
222 {
223 properties.put( key, systemProperty );
224 }
225 }
226
227 }
228
229 @Override
230 protected LoginScmResult login( ScmProviderRepository repository, ScmFileSet fileSet, CommandParameters parameters )
231 throws ScmException
232 {
233
234 if ( getLogger().isDebugEnabled() )
235 {
236 getLogger().debug( repository.toString() );
237 }
238
239 AccuRevLoginCommand command = new AccuRevLoginCommand( getLogger() );
240 return command.login( repository, fileSet, parameters );
241 }
242
243 @Override
244 protected CheckOutScmResult checkout( ScmProviderRepository repository, ScmFileSet fileSet,
245 CommandParameters parameters )
246 throws ScmException
247 {
248
249 // workaround deprecated behaviour
250 // TODO pull up to AbstractScmProvider
251 AccuRevScmProviderRepository accuRevRepo = (AccuRevScmProviderRepository) repository;
252 if ( !repository.isPersistCheckout() && accuRevRepo.shouldUseExportForNonPersistentCheckout() )
253 {
254
255 ExportScmResult result = export( repository, fileSet, parameters );
256 if ( result.isSuccess() )
257 {
258 return new CheckOutScmResult( result.getCommandLine(), result.getExportedFiles(),
259 accuRevRepo.getExportRelativePath() );
260 }
261 else
262 {
263 return new CheckOutScmResult( result.getCommandLine(), result.getProviderMessage(),
264 result.getCommandOutput(), false );
265 }
266 }
267
268 AccuRevCheckOutCommand command = new AccuRevCheckOutCommand( getLogger() );
269
270 return command.checkout( repository, fileSet, parameters );
271
272 }
273
274 @Override
275 protected CheckInScmResult checkin( ScmProviderRepository repository, ScmFileSet fileSet,
276 CommandParameters parameters )
277 throws ScmException
278 {
279
280 AccuRevCheckInCommand command = new AccuRevCheckInCommand( getLogger() );
281
282 return command.checkIn( repository, fileSet, parameters );
283 }
284
285 @Override
286 public ScmProviderRepository makeProviderScmRepository( File path )
287 throws ScmRepositoryException, UnknownRepositoryStructure
288 {
289
290 // TODO: accurev info with current dir = "path", find workspace. Find use-case for this.
291 return super.makeProviderScmRepository( path );
292 }
293
294 @Override
295 public AddScmResult add( ScmProviderRepository repository, ScmFileSet fileSet, CommandParameters parameters )
296 throws ScmException
297 {
298 AccuRevAddCommand command = new AccuRevAddCommand( getLogger() );
299 return command.add( repository, fileSet, parameters );
300 }
301
302 @Override
303 protected TagScmResult tag( ScmProviderRepository repository, ScmFileSet fileSet, CommandParameters parameters )
304 throws ScmException
305 {
306
307 AccuRevTagCommand command = new AccuRevTagCommand( getLogger() );
308 return command.tag( repository, fileSet, parameters );
309
310 }
311
312 @Override
313 protected StatusScmResult status( ScmProviderRepository repository, ScmFileSet fileSet, CommandParameters parameters )
314 throws ScmException
315 {
316
317 AccuRevStatusCommand command = new AccuRevStatusCommand( getLogger() );
318 return command.status( repository, fileSet, parameters );
319
320 }
321
322 @Override
323 protected UpdateScmResult update( ScmProviderRepository repository, ScmFileSet fileSet, CommandParameters parameters )
324 throws ScmException
325 {
326
327 AccuRevScmProviderRepository accurevRepo = (AccuRevScmProviderRepository) repository;
328
329 AccuRevUpdateCommand command = new AccuRevUpdateCommand( getLogger() );
330
331 UpdateScmResult result = command.update( repository, fileSet, parameters );
332
333 if ( result.isSuccess() && parameters.getBoolean( CommandParameter.RUN_CHANGELOG_WITH_UPDATE ) )
334 {
335 AccuRevUpdateScmResult accuRevResult = (AccuRevUpdateScmResult) result;
336
337 ScmRevision fromRevision = new ScmRevision( accuRevResult.getFromRevision() );
338 ScmRevision toRevision = new ScmRevision( accuRevResult.getToRevision() );
339
340 parameters.setScmVersion( CommandParameter.START_SCM_VERSION, fromRevision );
341 parameters.setScmVersion( CommandParameter.END_SCM_VERSION, toRevision );
342
343 AccuRevVersion startVersion = accurevRepo.getAccuRevVersion( fromRevision );
344 AccuRevVersion endVersion = accurevRepo.getAccuRevVersion( toRevision );
345 if ( startVersion.getBasisStream().equals( endVersion.getBasisStream() ) )
346 {
347 ChangeLogScmResult changeLogResult = changelog( repository, fileSet, parameters );
348
349 if ( changeLogResult.isSuccess() )
350 {
351 result.setChanges( changeLogResult.getChangeLog().getChangeSets() );
352 }
353 else
354 {
355 getLogger().warn( "Changelog from " + fromRevision + " to " + toRevision + " failed" );
356 }
357 }
358 else
359 {
360 String comment = "Cross stream update result from " + startVersion + " to " + endVersion;
361 String author = "";
362 List<ScmFile> files = result.getUpdatedFiles();
363 List<ChangeFile> changeFiles = new ArrayList<ChangeFile>( files.size() );
364 for (ScmFile scmFile : files)
365 {
366 changeFiles.add(new ChangeFile( scmFile.getPath() ));
367 }
368 ChangeSet dummyChangeSet = new ChangeSet( new Date(), comment, author, changeFiles );
369 // different streams invalidates the change log, insert a dummy change instead.
370 List<ChangeSet> changeSets = Collections.singletonList( dummyChangeSet );
371 result.setChanges( changeSets );
372 }
373
374 }
375 return result;
376 }
377
378 @Override
379 protected ExportScmResult export( ScmProviderRepository repository, ScmFileSet fileSet, CommandParameters parameters )
380 throws ScmException
381 {
382
383 AccuRevExportCommand command = new AccuRevExportCommand( getLogger() );
384 return command.export( repository, fileSet, parameters );
385 }
386
387 @Override
388 protected ChangeLogScmResult changelog( ScmProviderRepository repository, ScmFileSet fileSet,
389 CommandParameters parameters )
390 throws ScmException
391 {
392
393 AccuRevChangeLogCommand command = new AccuRevChangeLogCommand( getLogger() );
394 return command.changelog( repository, fileSet, parameters );
395 }
396
397 @Override
398 protected RemoveScmResult remove( ScmProviderRepository repository, ScmFileSet fileSet, CommandParameters parameters )
399 throws ScmException
400 {
401
402 AccuRevRemoveCommand command = new AccuRevRemoveCommand( getLogger() );
403 return command.remove( repository, fileSet, parameters );
404 }
405
406 /** {@inheritDoc} */
407 @Override
408 protected BlameScmResult blame( ScmProviderRepository repository, ScmFileSet fileSet, CommandParameters parameters )
409 throws ScmException
410 {
411
412 AccuRevBlameCommand blameCommand = new AccuRevBlameCommand( getLogger() );
413 return blameCommand.blame( repository, fileSet, parameters );
414 }
415 }