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