package com.perforce.maven.scm.provider.p4.util; import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.HashSet; import java.util.List; import org.apache.maven.scm.ScmException; import org.apache.maven.scm.ScmFileSet; import org.apache.maven.scm.ScmTag; import org.apache.maven.scm.ScmVersion; import org.codehaus.plexus.util.ReaderFactory; import org.codehaus.plexus.util.StringUtils; import org.codehaus.plexus.util.xml.pull.XmlPullParserException; import com.perforce.maven.scm.provider.p4.repository.P4ScmProviderRepository; import com.perforce.maven.scm.provider.p4.settings.Settings; import com.perforce.maven.scm.provider.p4.settings.io.xpp3.P4MavenXpp3Reader; import com.perforce.p4java.client.IClient; import com.perforce.p4java.core.file.FileSpecBuilder; import com.perforce.p4java.core.file.FileSpecOpStatus; import com.perforce.p4java.core.file.IFileSpec; import com.perforce.p4java.exception.P4JavaException; public class P4Utils { private P4Utils() { } /** * Gets the canonical repo path. * * @param repoPath the repo path * @return the canonical repo path */ public static String getCanonicalRepoPath( String repoPath ) { if ( repoPath == null ) { return null; } if ( repoPath.endsWith( "/" ) ) { repoPath += "..."; } else if ( !repoPath.endsWith( "/..." ) ) { repoPath += "/..."; } if ( repoPath.contains( " " ) ) { repoPath = "\"" + repoPath + "\""; } return repoPath; } /** * Perforce wildcards expansion. * * @param filePath the file path * @return the string */ public static String encodeWildcards( String filePath ) { String path = new String(); if ( filePath != null ) { path = filePath.replaceAll( "%", "%25" ).replaceAll( "\\*", "%2A" ).replaceAll( "#", "%23" ).replaceAll( "@", "%40" ); } return path; } /** * Checks if is empty. * * @param value the value * @return true, if is empty */ public static boolean isEmpty( String value ) { if ( value == null || value.trim().length() == 0 ) { return true; } return false; } /** * Gets the repo location. * * @param path the path * @return the repo location */ public static String getRepoLocation( IClient client, File localFile ) throws ScmException { try { List<IFileSpec> fileSpecs = client.where( FileSpecBuilder.makeFileSpecList( encodeWildcards( localFile.getAbsolutePath() ) ) ); for ( IFileSpec fileSpec : fileSpecs ) { if ( !P4Utils.isEmpty( fileSpec.getDepotPathString() ) ) { return fileSpec.getDepotPathString(); } } } catch ( Exception e ) { throw new ScmException( e.getLocalizedMessage(), e ); } return null; } public static boolean isRepoPathValid( IClient client, String repoPath ) throws ScmException { try { List<IFileSpec> fileSpecs = client.where( FileSpecBuilder.makeFileSpecList( getCanonicalRepoPath( repoPath ) ) ); if ( fileSpecs.size() != 0 ) { // check for error IFileSpec fileSpec = fileSpecs.get( 0 ); if ( fileSpec.getOpStatus() == FileSpecOpStatus.VALID ) { return true; } } } catch ( P4JavaException e ) { throw new ScmException( e.getLocalizedMessage(), e ); } return false; } public static String scmVersion2SuffixString( ScmVersion version ) { String versionSuffix = ""; if ( version != null && !P4Utils.isEmpty( version.getName() ) ) { versionSuffix = "@" + version.getName(); } return versionSuffix; } /** * Convert ScmFileSet to List<IFileSpec> for * * @param fileSet * @return * @throws ScmException */ public static List<IFileSpec> scmFileSet2P4FileSpecsWithNop4WildCard( ScmFileSet fileSet, ScmVersion version ) throws ScmException { String versionSuffix = scmVersion2SuffixString( version ); List<IFileSpec> fileSpecs = new ArrayList<IFileSpec>(); try { List<File> fileList = fileSet.getFileList(); if ( fileList != null ) { HashSet<String> filePaths = new HashSet<String>(); for ( File file : fileList ) { if ( ".".equals( file.getPath() ) ) { // ignore child path "." since it is the same as parent dir // this happens when issue mvn scm:command from command line continue; } if ( !file.isAbsolute() ) { // It is assumed that ScmFileSet does validate its fileList which must be relative to its // basedir file = new File( fileSet.getBasedir(), file.getPath() ); } filePaths.add( P4Utils.encodeWildcards( file.getCanonicalPath() + versionSuffix ) ); } if ( !filePaths.isEmpty() ) { fileSpecs = FileSpecBuilder.makeFileSpecList( filePaths.toArray( new String[filePaths.size()] ) ); } } } catch ( IOException e ) { throw new ScmException( e.getLocalizedMessage(), e ); } return fileSpecs; } public static List<IFileSpec> scmFileSet2P4FileSpecsWithNoP4WildCard( ScmFileSet fileSet ) throws ScmException { return scmFileSet2P4FileSpecsWithNop4WildCard( fileSet, null ); } public static List<IFileSpec> scmFileSet2P4FileSpecs( ScmFileSet fileSet, ScmVersion version ) throws ScmException { List<IFileSpec> fileSpecs = scmFileSet2P4FileSpecsWithNop4WildCard( fileSet, version ); if ( fileSpecs.isEmpty() ) { if ( P4Utils.isEmpty( fileSet.getIncludes() ) && P4Utils.isEmpty( fileSet.getExcludes() ) ) { String versionSuffix = scmVersion2SuffixString( version ); if ( isEmpty( versionSuffix ) ) { versionSuffix = "/..."; } String filePath = fileSet.getBasedir().getAbsolutePath() + versionSuffix; // very hacky if ( version instanceof ScmTag ) { filePath = "@" + version.getName(); } fileSpecs = FileSpecBuilder.makeFileSpecList( new String[] { filePath } ); } } return fileSpecs; } public static List<IFileSpec> scmFileSet2P4FileSpecs( ScmFileSet fileSet ) throws ScmException { return scmFileSet2P4FileSpecs( fileSet, null ); } // ////////////////////////////////////////////////////////////////////////////////////////////////////////// private static final String P4MAVEN_SETTINGS_FILENAME = "p4maven-settings.xml"; private static final File DEFAULT_SETTINGS_DIRECTORY = new File( System.getProperty( "user.home" ), ".scm" ); private static File settingsDirectory = DEFAULT_SETTINGS_DIRECTORY; private static Settings settings; public static synchronized Settings getSettings() { if ( settings == null ) { settings = readSettings(); } return settings; } private static Settings readSettings() { File settingsFile = getSettingsFile(); Settings settings = new Settings(); if ( settingsFile.exists() ) { P4MavenXpp3Reader reader = new P4MavenXpp3Reader(); try { settings = reader.read( ReaderFactory.newXmlReader( settingsFile ) ); } catch ( FileNotFoundException e ) { // nop } catch ( IOException e ) { // nop } catch ( XmlPullParserException e ) { String message = settingsFile.getAbsolutePath() + " isn't well formed. SKIPPED." + e.getMessage(); System.err.println( message ); } } // override if found from system properties String jobs = System.getProperty( P4ScmProviderRepository.P4_JOBS_PROPERTY ); if ( jobs != null ) { settings.setJobs( jobs ); } // nullify value in the p4maven-settings.xml, we dont want user to set it there settings.setClientName( null ); String clientName = System.getProperty( P4ScmProviderRepository.P4_CLIENT_PROPERTY ); if ( clientName != null ) { settings.setClientName( clientName ); } String lockTag = System.getProperty( P4ScmProviderRepository.P4_LOCK_TAG_PROPERTY ); if ( lockTag != null ) { settings.setLockTag( "true".equals( lockTag ) ); } String charset = System.getProperty( P4ScmProviderRepository.P4_CHARSET_PROPERTY ); if ( charset != null ) { settings.setCharset( charset ); } return settings; } public static List<String> getJobs() { String jobs = getSettings().getJobs(); if ( jobs == null ) { jobs = ""; } String[] tokens = StringUtils.split( jobs ); return new ArrayList<String>( Arrays.asList( tokens ) ); } public static File getSettingsFile() { return new File( settingsDirectory, P4MAVEN_SETTINGS_FILENAME ); } public static void setSettingsDirectory( File directory ) { settingsDirectory = directory; } }
# | Change | User | Description | Committed | |
---|---|---|---|---|---|
#21 | 12874 | dantran | -Dp4verbose must be able to override the value set at ~/.m2/p4maven-settings.xml | ||
#20 | 12266 | dantran | move p4maven-settings.xml to ~/.m2 | ||
#19 | 11533 | dantran | Gracefully fault back latest client revision to latest repo revision when client have not sync with server yet | ||
#18 | 11530 | dantran | -add -Dverbose=true to dump p4 server messages to stdout | ||
#17 | 11507 | dantran |
- Tagging should use revision of last sync - Info pickup both latest from server and latest from client workspace last sync |
||
#16 | 11506 | dantran | Minor typos cleanup | ||
#15 | 11505 | dantran | Allow option to enable P4 server log at command line via P4VERBOSE system property and p4maven-settings | ||
#14 | 11424 | dantran |
- P4Java logs are no under debug mode to reduce verbosity. To enable, pass in -X into mvn command - Info command now supports tag - Add p4java into export extension - Use BSD for license name - Update doc |
||
#13 | 11392 | dantran |
Add missing provider info implementation. This is needed by buildnumber-maven-plugin to create build number using latest changelist |
||
#12 | 9680 | dantran | cleanup | ||
#11 | 9678 | dantran | add p4maven-settings test | ||
#10 | 9632 | dantran |
- use groupId:artifactId:version to test release automation - Implment p4maven-settings.xml's p4Port field |
||
#9 | 9627 | dantran |
fix invalid default port. some minor cleanup |
||
#8 | 9621 | dantran | add strictClientDiscovery external setting | ||
#7 | 9618 | dantran | cleanup | ||
#6 | 9590 | dantran |
- add option to fail tag when it already exist - add P4ScmUrl parser test - cleanup |
||
#5 | 9566 | dantran |
- pickup charset from external config - Use repo's path during branch, if is not value use the basedir. This means it assumes maven user likely to name artifactId and module the same - Less verbose on server info |
||
#4 | 9562 | dantran | remove P4Utils.checkForError(), it should be under P4Result.process | ||
#3 | 9548 | dantran |
- pickup P4PORT form env and system properties to support multi site using proxy - add development doc - check for error after each action |
||
#2 | 9533 | dantran | source format | ||
#1 | 9519 | dantran | folder rename to match with its artifactId | ||
//guest/dantran/p4maven/com.perforce.maven/src/main/java/com/perforce/maven/scm/provider/p4/util/P4Utils.java | |||||
#15 | 9514 | dantran |
- Remove support to pick up p4port and its credential from ENV and System properties. These setttings has no use since Maven requires user to provide the required URL which has both p4port and credential. Also user can always fall back to settings.xml to store credential - Rewrite URL parser and also support password as part of URL - TCK test now has default URL and its credential is store under settings.xml - User can also issue her how scmTckUrl system properties ( to be doc as part of maven site) |
||
#14 | 9513 | dantran | add provider doc, deploy site:jar, support external charset config | ||
#13 | 9498 | dantran |
- Setup Maven site for documetation - Implement ~/m2/p4maven-settings.xml to store external config overridable by system properties. All global settings now can be retrieved va P4Utils |
||
#12 | 9477 | dantran | add logger, prepare the next release | ||
#11 | 9471 | dantran |
- cleanup diff command - simplify branch command and full compliant with maven-scm-test - add checkout with branch - add repo's path as client manager lookup key in addition to p4port and rootdir so that we can handle mutiple clients on the same rootdir |
||
#10 | 9451 | dantran | Discover current client | ||
#9 | 9444 | dantran | Handle ScmFileSet's fileList has absolute paths | ||
#8 | 9442 | dantran | Handle ScmFileSet which has a file named "." | ||
#7 | 9441 | dantran | discover existing client, so that we dont need pass in this name via system property during release:prepare | ||
#6 | 9423 | dantran | get all test to use the same setup, handle checkout with tag, need to revisit how we handle ScmVersion | ||
#5 | 9422 | dantran | add update, changelog TCK | ||
#4 | 9342 | dantran | Add CheckIn TCK | ||
#3 | 9290 | dantran | Introduce the reusable P4Utils.scmFileSet2P4FileSpecs util, and have edit and checkin command to use it | ||
#2 | 9259 | dantran |
hookup with maven-scm-test. Pickup user/password from system properties |
||
#1 | 9250 | dantran | caching client across mutiple commands |