1 package org.apache.maven.scm.provider.perforce;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23 import java.io.BufferedReader;
24 import java.io.File;
25 import java.io.IOException;
26 import java.io.InputStreamReader;
27 import java.net.InetAddress;
28 import java.net.UnknownHostException;
29 import java.util.Arrays;
30 import java.util.HashSet;
31
32 import org.apache.maven.scm.CommandParameters;
33 import org.apache.maven.scm.ScmException;
34 import org.apache.maven.scm.ScmFileSet;
35 import org.apache.maven.scm.command.add.AddScmResult;
36 import org.apache.maven.scm.command.blame.BlameScmResult;
37 import org.apache.maven.scm.command.changelog.ChangeLogScmResult;
38 import org.apache.maven.scm.command.checkin.CheckInScmResult;
39 import org.apache.maven.scm.command.checkout.CheckOutScmResult;
40 import org.apache.maven.scm.command.diff.DiffScmResult;
41 import org.apache.maven.scm.command.edit.EditScmResult;
42 import org.apache.maven.scm.command.login.LoginScmResult;
43 import org.apache.maven.scm.command.remove.RemoveScmResult;
44 import org.apache.maven.scm.command.status.StatusScmResult;
45 import org.apache.maven.scm.command.tag.TagScmResult;
46 import org.apache.maven.scm.command.unedit.UnEditScmResult;
47 import org.apache.maven.scm.command.update.UpdateScmResult;
48 import org.apache.maven.scm.log.ScmLogger;
49 import org.apache.maven.scm.provider.AbstractScmProvider;
50 import org.apache.maven.scm.provider.ScmProviderRepository;
51 import org.apache.maven.scm.provider.perforce.command.PerforceInfoCommand;
52 import org.apache.maven.scm.provider.perforce.command.PerforceWhereCommand;
53 import org.apache.maven.scm.provider.perforce.command.add.PerforceAddCommand;
54 import org.apache.maven.scm.provider.perforce.command.blame.PerforceBlameCommand;
55 import org.apache.maven.scm.provider.perforce.command.changelog.PerforceChangeLogCommand;
56 import org.apache.maven.scm.provider.perforce.command.checkin.PerforceCheckInCommand;
57 import org.apache.maven.scm.provider.perforce.command.checkout.PerforceCheckOutCommand;
58 import org.apache.maven.scm.provider.perforce.command.diff.PerforceDiffCommand;
59 import org.apache.maven.scm.provider.perforce.command.edit.PerforceEditCommand;
60 import org.apache.maven.scm.provider.perforce.command.login.PerforceLoginCommand;
61 import org.apache.maven.scm.provider.perforce.command.remove.PerforceRemoveCommand;
62 import org.apache.maven.scm.provider.perforce.command.status.PerforceStatusCommand;
63 import org.apache.maven.scm.provider.perforce.command.tag.PerforceTagCommand;
64 import org.apache.maven.scm.provider.perforce.command.unedit.PerforceUnEditCommand;
65 import org.apache.maven.scm.provider.perforce.command.update.PerforceUpdateCommand;
66 import org.apache.maven.scm.provider.perforce.repository.PerforceScmProviderRepository;
67 import org.apache.maven.scm.repository.ScmRepositoryException;
68 import org.codehaus.plexus.util.StringUtils;
69 import org.codehaus.plexus.util.cli.Commandline;
70
71
72
73
74
75
76
77 public class PerforceScmProvider
78 extends AbstractScmProvider
79 {
80 private static final String[] PROTOCOLS = { "tcp", "tcp4", "tcp6", "tcp46", "tcp64", "ssl", "ssl4", "ssl6",
81 "ssl46", "ssl64" };
82
83
84
85
86
87 public boolean requiresEditMode()
88 {
89 return true;
90 }
91
92 public ScmProviderRepository makeProviderScmRepository( String scmSpecificUrl, char delimiter )
93 throws ScmRepositoryException
94 {
95 String protocol = null;
96 String path;
97 int port = 0;
98 String host = null;
99
100
101 int i0 = scmSpecificUrl.indexOf( delimiter );
102 if ( i0 > 0 )
103 {
104 protocol = scmSpecificUrl.substring( 0, i0 );
105 HashSet<String> protocols = new HashSet<String>( Arrays.asList( PROTOCOLS ) );
106 if ( protocols.contains( protocol ) )
107 {
108 scmSpecificUrl = scmSpecificUrl.substring( i0 + 1 );
109 }
110 else
111 {
112 protocol = null;
113 }
114 }
115
116 int i1 = scmSpecificUrl.indexOf( delimiter );
117 int i2 = scmSpecificUrl.indexOf( delimiter, i1 + 1 );
118
119 if ( i1 > 0 )
120 {
121 int lastDelimiter = scmSpecificUrl.lastIndexOf( delimiter );
122 path = scmSpecificUrl.substring( lastDelimiter + 1 );
123 host = scmSpecificUrl.substring( 0, i1 );
124
125
126 if ( i2 >= 0 )
127 {
128 try
129 {
130 String tmp = scmSpecificUrl.substring( i1 + 1, lastDelimiter );
131 port = Integer.parseInt( tmp );
132 }
133 catch ( NumberFormatException ex )
134 {
135 throw new ScmRepositoryException( "The port has to be a number." );
136 }
137 }
138 }
139 else
140 {
141 path = scmSpecificUrl;
142 }
143
144 String user = null;
145 String password = null;
146 if ( host != null && host.indexOf( '@' ) > 1 )
147 {
148 user = host.substring( 0, host.indexOf( '@' ) );
149 host = host.substring( host.indexOf( '@' ) + 1 );
150 }
151
152 if ( path.indexOf( '@' ) > 1 )
153 {
154 if ( host != null )
155 {
156 if ( getLogger().isWarnEnabled() )
157 {
158 getLogger().warn(
159 "Username as part of path is deprecated, the new format is "
160 + "scm:perforce:[username@]host:port:path_to_repository" );
161 }
162 }
163
164 user = path.substring( 0, path.indexOf( '@' ) );
165 path = path.substring( path.indexOf( '@' ) + 1 );
166 }
167
168 return new PerforceScmProviderRepository( protocol, host, port, path, user, password );
169 }
170
171 public String getScmType()
172 {
173 return "perforce";
174 }
175
176
177 protected ChangeLogScmResult changelog( ScmProviderRepository repository, ScmFileSet fileSet,
178 CommandParameters parameters )
179 throws ScmException
180 {
181 PerforceChangeLogCommand command = new PerforceChangeLogCommand();
182 command.setLogger( getLogger() );
183 return (ChangeLogScmResult) command.execute( repository, fileSet, parameters );
184 }
185
186 public AddScmResult add( ScmProviderRepository repository, ScmFileSet fileSet, CommandParameters params )
187 throws ScmException
188 {
189 PerforceAddCommand command = new PerforceAddCommand();
190 command.setLogger( getLogger() );
191 return (AddScmResult) command.execute( repository, fileSet, params );
192 }
193
194 protected RemoveScmResult remove( ScmProviderRepository repository, ScmFileSet fileSet, CommandParameters params )
195 throws ScmException
196 {
197 PerforceRemoveCommand command = new PerforceRemoveCommand();
198 command.setLogger( getLogger() );
199 return (RemoveScmResult) command.execute( repository, fileSet, params );
200 }
201
202 protected CheckInScmResult checkin( ScmProviderRepository repository, ScmFileSet fileSet, CommandParameters params )
203 throws ScmException
204 {
205 PerforceCheckInCommand command = new PerforceCheckInCommand();
206 command.setLogger( getLogger() );
207 return (CheckInScmResult) command.execute( repository, fileSet, params );
208 }
209
210 protected CheckOutScmResult checkout( ScmProviderRepository repository, ScmFileSet fileSet,
211 CommandParameters params )
212 throws ScmException
213 {
214 PerforceCheckOutCommand command = new PerforceCheckOutCommand();
215 command.setLogger( getLogger() );
216 return (CheckOutScmResult) command.execute( repository, fileSet, params );
217 }
218
219 protected DiffScmResult diff( ScmProviderRepository repository, ScmFileSet fileSet, CommandParameters params )
220 throws ScmException
221 {
222 PerforceDiffCommand command = new PerforceDiffCommand();
223 command.setLogger( getLogger() );
224 return (DiffScmResult) command.execute( repository, fileSet, params );
225 }
226
227 protected EditScmResult edit( ScmProviderRepository repository, ScmFileSet fileSet, CommandParameters params )
228 throws ScmException
229 {
230 PerforceEditCommand command = new PerforceEditCommand();
231 command.setLogger( getLogger() );
232 return (EditScmResult) command.execute( repository, fileSet, params );
233 }
234
235 protected LoginScmResult login( ScmProviderRepository repository, ScmFileSet fileSet, CommandParameters params )
236 throws ScmException
237 {
238 PerforceLoginCommand command = new PerforceLoginCommand();
239 command.setLogger( getLogger() );
240 return (LoginScmResult) command.execute( repository, fileSet, params );
241 }
242
243 protected StatusScmResult status( ScmProviderRepository repository, ScmFileSet fileSet, CommandParameters params )
244 throws ScmException
245 {
246 PerforceStatusCommand command = new PerforceStatusCommand();
247 command.setLogger( getLogger() );
248 return (StatusScmResult) command.execute( repository, fileSet, params );
249 }
250
251 protected TagScmResult tag( ScmProviderRepository repository, ScmFileSet fileSet, CommandParameters params )
252 throws ScmException
253 {
254 PerforceTagCommand command = new PerforceTagCommand();
255 command.setLogger( getLogger() );
256 return (TagScmResult) command.execute( repository, fileSet, params );
257 }
258
259 protected UnEditScmResult unedit( ScmProviderRepository repository, ScmFileSet fileSet, CommandParameters params )
260 throws ScmException
261 {
262 PerforceUnEditCommand command = new PerforceUnEditCommand();
263 command.setLogger( getLogger() );
264 return (UnEditScmResult) command.execute( repository, fileSet, params );
265 }
266
267 protected UpdateScmResult update( ScmProviderRepository repository, ScmFileSet fileSet, CommandParameters params )
268 throws ScmException
269 {
270 PerforceUpdateCommand command = new PerforceUpdateCommand();
271 command.setLogger( getLogger() );
272 return (UpdateScmResult) command.execute( repository, fileSet, params );
273 }
274
275 protected BlameScmResult blame( ScmProviderRepository repository, ScmFileSet fileSet, CommandParameters params )
276 throws ScmException
277 {
278 PerforceBlameCommand command = new PerforceBlameCommand();
279 command.setLogger( getLogger() );
280 return (BlameScmResult) command.execute( repository, fileSet, params );
281 }
282
283 public static Commandline createP4Command( PerforceScmProviderRepository repo, File workingDir )
284 {
285 Commandline command = new Commandline();
286 command.setExecutable( "p4" );
287 if ( workingDir != null )
288 {
289
290 command.createArg().setValue( "-d" );
291 command.createArg().setValue( workingDir.getAbsolutePath() );
292 }
293
294
295 if ( repo.getHost() != null )
296 {
297 command.createArg().setValue( "-p" );
298 String value = "";
299 if ( ! StringUtils.isBlank( repo.getProtocol() ) )
300 {
301 value += repo.getProtocol() + ":";
302 }
303 value += repo.getHost();
304 if ( repo.getPort() != 0 )
305 {
306 value += ":" + Integer.toString( repo.getPort() );
307 }
308 command.createArg().setValue( value );
309 }
310
311 if ( StringUtils.isNotEmpty( repo.getUser() ) )
312 {
313 command.createArg().setValue( "-u" );
314 command.createArg().setValue( repo.getUser() );
315 }
316
317 if ( StringUtils.isNotEmpty( repo.getPassword() ) )
318 {
319 command.createArg().setValue( "-P" );
320 command.createArg().setValue( repo.getPassword() );
321 }
322 return command;
323 }
324
325 public static String clean( String string )
326 {
327 if ( string.indexOf( " -P " ) == -1 )
328 {
329 return string;
330 }
331 int idx = string.indexOf( " -P " ) + 4;
332 int end = string.indexOf( ' ', idx );
333 return string.substring( 0, idx ) + StringUtils.repeat( "*", end - idx ) + string.substring( end );
334 }
335
336
337
338
339
340
341
342
343
344
345
346
347 public static String getCanonicalRepoPath( String repoPath )
348 {
349 if ( repoPath.endsWith( "/..." ) )
350 {
351 return repoPath;
352 }
353 else if ( repoPath.endsWith( "/" ) )
354 {
355 return repoPath + "...";
356 }
357 else
358 {
359 return repoPath + "/...";
360 }
361 }
362
363 private static final String NEWLINE = "\r\n";
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381 public static String createClientspec( ScmLogger logger, PerforceScmProviderRepository repo, File workDir,
382 String repoPath )
383 {
384 String clientspecName = getClientspecName( logger, repo, workDir );
385 String userName = getUsername( logger, repo );
386
387 String rootDir;
388 try
389 {
390
391 rootDir = workDir.getCanonicalPath();
392 }
393 catch ( IOException ex )
394 {
395
396 rootDir = workDir.getAbsolutePath();
397 }
398
399 StringBuilder buf = new StringBuilder();
400 buf.append( "Client: " ).append( clientspecName ).append( NEWLINE );
401 buf.append( "Root: " ).append( rootDir ).append( NEWLINE );
402 buf.append( "Owner: " ).append( userName ).append( NEWLINE );
403 buf.append( "View:" ).append( NEWLINE );
404 buf.append( "\t" ).append( PerforceScmProvider.getCanonicalRepoPath( repoPath ) );
405 buf.append( " //" ).append( clientspecName ).append( "/..." ).append( NEWLINE );
406 buf.append( "Description:" ).append( NEWLINE );
407 buf.append( "\t" ).append( "Created by maven-scm-provider-perforce" ).append( NEWLINE );
408 return buf.toString();
409 }
410
411 public static final String DEFAULT_CLIENTSPEC_PROPERTY = "maven.scm.perforce.clientspec.name";
412
413 public static String getClientspecName( ScmLogger logger, PerforceScmProviderRepository repo, File workDir )
414 {
415 String def = generateDefaultClientspecName( logger, repo, workDir );
416
417 String l = System.getProperty( DEFAULT_CLIENTSPEC_PROPERTY, def );
418 if ( l == null || "".equals( l.trim() ) )
419 {
420 return def;
421 }
422 return l;
423 }
424
425 private static String generateDefaultClientspecName( ScmLogger logger, PerforceScmProviderRepository repo,
426 File workDir )
427 {
428 String username = getUsername( logger, repo );
429 String hostname;
430 String path;
431 try
432 {
433 hostname = InetAddress.getLocalHost().getHostName();
434
435 path = workDir.getCanonicalPath().replaceAll( "[/ ~]", "-" );
436 }
437 catch ( UnknownHostException e )
438 {
439
440 throw new RuntimeException( e );
441 }
442 catch ( IOException e )
443 {
444 throw new RuntimeException( e );
445 }
446 return username + "-" + hostname + "-MavenSCM-" + path;
447 }
448
449 private static String getUsername( ScmLogger logger, PerforceScmProviderRepository repo )
450 {
451 String username = PerforceInfoCommand.getInfo( logger, repo ).getEntry( "User name" );
452 if ( username == null )
453 {
454
455 username = repo.getUser();
456 if ( username == null )
457 {
458 username = System.getProperty( "user.name", "nouser" );
459 }
460 }
461 return username;
462 }
463
464
465
466
467
468
469
470
471
472
473
474
475 public static String getRepoPath( ScmLogger log, PerforceScmProviderRepository repo, File basedir )
476 {
477 PerforceWhereCommand where = new PerforceWhereCommand( log, repo );
478
479
480
481
482
483 if ( basedir.toString().replace( '\\', '/' ).endsWith( "/target/checkout" ) )
484 {
485 String dir = basedir.toString();
486 basedir = new File( dir.substring( 0, dir.length() - "/target/checkout".length() ) );
487 log.debug( "Fixing checkout URL: " + basedir );
488 }
489 File pom = new File( basedir, "pom.xml" );
490 String loc = repo.getPath();
491 log.debug( "SCM path in pom: " + loc );
492 if ( pom.exists() )
493 {
494 loc = where.getDepotLocation( pom );
495 if ( loc == null )
496 {
497 loc = repo.getPath();
498 log.debug( "cannot find depot => using " + loc );
499 }
500 else if ( loc.endsWith( "/pom.xml" ) )
501 {
502 loc = loc.substring( 0, loc.length() - "/pom.xml".length() );
503 log.debug( "Actual POM location: " + loc );
504 if ( !repo.getPath().equals( loc ) )
505 {
506 log.info( "The SCM location in your pom.xml (" + repo.getPath()
507 + ") is not equal to the depot location (" + loc
508 + "). This happens frequently with branches. " + "Ignoring the SCM location." );
509 }
510 }
511 }
512 return loc;
513 }
514
515
516 private static Boolean live = null;
517
518 public static boolean isLive()
519 {
520 if ( live == null )
521 {
522 if ( !Boolean.getBoolean( "maven.scm.testing" ) )
523 {
524
525 live = Boolean.TRUE;
526 }
527 else
528 {
529
530
531
532
533 try
534 {
535 Commandline command = new Commandline();
536 command.setExecutable( "p4" );
537 Process proc = command.execute();
538 BufferedReader br = new BufferedReader( new InputStreamReader( proc.getInputStream() ) );
539 @SuppressWarnings( "unused" )
540 String line;
541 while ( ( line = br.readLine() ) != null )
542 {
543
544 }
545 int rc = proc.exitValue();
546 live = ( rc == 0 ? Boolean.TRUE : Boolean.FALSE );
547 }
548 catch ( Exception e )
549 {
550 e.printStackTrace();
551 live = Boolean.FALSE;
552 }
553 }
554 }
555
556 return live.booleanValue();
557 }
558 }