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