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