http://git-wip-us.apache.org/repos/asf/maven-scm/blob/8ad9801d/maven-scm-providers/maven-scm-provider-integrity/src/main/java/org/apache/maven/scm/provider/integrity/Member.java ---------------------------------------------------------------------- diff --git a/maven-scm-providers/maven-scm-provider-integrity/src/main/java/org/apache/maven/scm/provider/integrity/Member.java b/maven-scm-providers/maven-scm-provider-integrity/src/main/java/org/apache/maven/scm/provider/integrity/Member.java index 0317865..bca7e80 100644 --- a/maven-scm-providers/maven-scm-provider-integrity/src/main/java/org/apache/maven/scm/provider/integrity/Member.java +++ b/maven-scm-providers/maven-scm-provider-integrity/src/main/java/org/apache/maven/scm/provider/integrity/Member.java @@ -1,264 +1,264 @@ -package org.apache.maven.scm.provider.integrity; - -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import com.mks.api.Command; -import com.mks.api.FileOption; -import com.mks.api.Option; -import com.mks.api.response.APIException; -import com.mks.api.response.Response; -import com.mks.api.response.WorkItem; - -import java.io.File; -import java.util.Date; - -/** - * This class represents an Integrity SCM Member - * <br>It contains all the necessary metadata to check this file out individually - * - * @author <a href="mailto:cle...@mks.com">Cletus D'Souza</a> - * @version $Id: Member.java 1.2 2011/08/22 13:06:47EDT Cletus D'Souza (dsouza) Exp $ - * @since 1.6 - */ -public class Member -{ - private String memberID; - - private String memberName; - - private Date memberTimestamp; - - private String memberDescription; - - private String projectConfigPath; - - private String memberRev; - - private File targetFile; - - private String relativeFile; - - private String lineTerminator; - - private String overwriteExisting; - - private String restoreTimestamp; - - /** - * This class represents an MKS Integrity Source File - * It needs the Member Name (relative path to pj), Full Member Path, Project Configuration Path, Revision, - * Project's Root Path, and the current Workspace directory (to compute the working file path) for its - * instantiation. This helper class will be used to then perform a project checkout from the repository - * - * @param wi A MKS API Response Work Item representing metadata related to a Integrity Member - * @param configPath Configuration Path for this file's project/subproject - * @param projectRoot Full path to the root location for this file's parent project - * @param workspaceDir Full path to the workspace root directory - */ - public Member( WorkItem wi, String configPath, String projectRoot, String workspaceDir ) - { - // Initialize our parent with the information needed - this.projectConfigPath = configPath; - this.memberID = wi.getId(); - this.memberName = wi.getField( "name" ).getValueAsString(); - this.memberRev = wi.getField( "memberrev" ).getItem().getId(); - this.memberTimestamp = wi.getField( "membertimestamp" ).getDateTime(); - if ( null != wi.getField( "memberdescription" ) && null != wi.getField( - "memberdescription" ).getValueAsString() ) - { - this.memberDescription = wi.getField( "memberdescription" ).getValueAsString(); - } - else - { - this.memberDescription = new String( "" ); - } - this.lineTerminator = "native"; - this.overwriteExisting = "overwriteExisting"; - this.restoreTimestamp = "restoreTimestamp"; - this.relativeFile = this.memberName.substring( projectRoot.length() ); - this.targetFile = new File( workspaceDir + relativeFile ); - } - - /** - * Returns a string representation of this file's full path name, where it will checked out to disk for the build. - * - * @return - */ - public String getTargetFilePath() - { - return targetFile.getAbsolutePath(); - } - - /** - * Returns a string representation of this member's revision - * - * @return - */ - public String getRevision() - { - return memberRev; - } - - /** - * Returns the date/time associated with this member revision - * - * @return - */ - public Date getTimestamp() - { - return memberTimestamp; - } - - /** - * Returns any check-in comments associated with this revision - * - * @return - */ - public String getDescription() - { - return memberDescription; - } - - /** - * Returns the full server-side member path for this member - * - * @return - */ - public String getMemberName() - { - return memberName; - } - - /** - * Returns only the file name portion for this full server-side member path - * - * @return - */ - public String getName() - { - if ( memberID.indexOf( '/' ) > 0 ) - { - return memberID.substring( memberID.lastIndexOf( '/' ) + 1 ); - } - else if ( memberID.indexOf( '\\' ) > 0 ) - { - return memberID.substring( memberID.lastIndexOf( '\\' ) + 1 ); - } - else - { - return memberID; - } - } - - /** - * Optionally, one may set a line terminator, if the default is not desired. - * - * @param lineTerminator - */ - public void setLineTerminator( String lineTerminator ) - { - this.lineTerminator = lineTerminator; - } - - /** - * Optionally, one may choose not to overwrite existing files, this may speed up the synchronization process. - * - * @param overwriteExisting - */ - public void setOverwriteExisting( String overwriteExisting ) - { - this.overwriteExisting = overwriteExisting; - } - - /** - * Optionally, one might want to restore the timestamp, if the build is smart not to recompile files that were not touched. - * - * @param restoreTimestamp - */ - public void setRestoreTimestamp( boolean restoreTime ) - { - if ( restoreTime ) - { - this.restoreTimestamp = "restoreTimestamp"; - } - else - { - this.restoreTimestamp = "norestoreTimestamp"; - } - } - - /** - * Performs a checkout of this MKS Integrity Source File to a working file location on the build server represented by targetFile - * - * @param api MKS API Session - * @return true if the operation succeeded or false if failed - * @throws APIException - */ - public boolean checkout( APISession api ) - throws APIException - { - // Make sure the directory is created - if ( !targetFile.getParentFile().isDirectory() ) - { - targetFile.getParentFile().mkdirs(); - } - // Construct the project check-co command - Command coCMD = new Command( Command.SI, "projectco" ); - coCMD.addOption( new Option( overwriteExisting ) ); - coCMD.addOption( new Option( "nolock" ) ); - coCMD.addOption( new Option( "project", projectConfigPath ) ); - coCMD.addOption( new FileOption( "targetFile", targetFile ) ); - coCMD.addOption( new Option( restoreTimestamp ) ); - coCMD.addOption( new Option( "lineTerminator", lineTerminator ) ); - coCMD.addOption( new Option( "revision", memberRev ) ); - // Add the member selection - coCMD.addSelection( memberID ); - - // Execute the checkout command - Response res = api.runCommand( coCMD ); - - // Return true if we were successful - if ( res.getExitCode() == 0 ) - { - return true; - } - // Otherwise return false... - else - { - return false; - } - } - - /** - * Uses the name of file for equality check - */ - @Override - public boolean equals( Object o ) - { - if ( o instanceof Member ) - { - if ( null != o ) - { - return ( (Member) o ).getMemberName().equals( this.getMemberName() ); - } - } - return false; - } -} +package org.apache.maven.scm.provider.integrity; + +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import com.mks.api.Command; +import com.mks.api.FileOption; +import com.mks.api.Option; +import com.mks.api.response.APIException; +import com.mks.api.response.Response; +import com.mks.api.response.WorkItem; + +import java.io.File; +import java.util.Date; + +/** + * This class represents an Integrity SCM Member + * <br>It contains all the necessary metadata to check this file out individually + * + * @author <a href="mailto:cle...@mks.com">Cletus D'Souza</a> + * @version $Id: Member.java 1.2 2011/08/22 13:06:47EDT Cletus D'Souza (dsouza) Exp $ + * @since 1.6 + */ +public class Member +{ + private String memberID; + + private String memberName; + + private Date memberTimestamp; + + private String memberDescription; + + private String projectConfigPath; + + private String memberRev; + + private File targetFile; + + private String relativeFile; + + private String lineTerminator; + + private String overwriteExisting; + + private String restoreTimestamp; + + /** + * This class represents an MKS Integrity Source File + * It needs the Member Name (relative path to pj), Full Member Path, Project Configuration Path, Revision, + * Project's Root Path, and the current Workspace directory (to compute the working file path) for its + * instantiation. This helper class will be used to then perform a project checkout from the repository + * + * @param wi A MKS API Response Work Item representing metadata related to a Integrity Member + * @param configPath Configuration Path for this file's project/subproject + * @param projectRoot Full path to the root location for this file's parent project + * @param workspaceDir Full path to the workspace root directory + */ + public Member( WorkItem wi, String configPath, String projectRoot, String workspaceDir ) + { + // Initialize our parent with the information needed + this.projectConfigPath = configPath; + this.memberID = wi.getId(); + this.memberName = wi.getField( "name" ).getValueAsString(); + this.memberRev = wi.getField( "memberrev" ).getItem().getId(); + this.memberTimestamp = wi.getField( "membertimestamp" ).getDateTime(); + if ( null != wi.getField( "memberdescription" ) && null != wi.getField( + "memberdescription" ).getValueAsString() ) + { + this.memberDescription = wi.getField( "memberdescription" ).getValueAsString(); + } + else + { + this.memberDescription = new String( "" ); + } + this.lineTerminator = "native"; + this.overwriteExisting = "overwriteExisting"; + this.restoreTimestamp = "restoreTimestamp"; + this.relativeFile = this.memberName.substring( projectRoot.length() ); + this.targetFile = new File( workspaceDir + relativeFile ); + } + + /** + * Returns a string representation of this file's full path name, where it will checked out to disk for the build. + * + * @return + */ + public String getTargetFilePath() + { + return targetFile.getAbsolutePath(); + } + + /** + * Returns a string representation of this member's revision + * + * @return + */ + public String getRevision() + { + return memberRev; + } + + /** + * Returns the date/time associated with this member revision + * + * @return + */ + public Date getTimestamp() + { + return memberTimestamp; + } + + /** + * Returns any check-in comments associated with this revision + * + * @return + */ + public String getDescription() + { + return memberDescription; + } + + /** + * Returns the full server-side member path for this member + * + * @return + */ + public String getMemberName() + { + return memberName; + } + + /** + * Returns only the file name portion for this full server-side member path + * + * @return + */ + public String getName() + { + if ( memberID.indexOf( '/' ) > 0 ) + { + return memberID.substring( memberID.lastIndexOf( '/' ) + 1 ); + } + else if ( memberID.indexOf( '\\' ) > 0 ) + { + return memberID.substring( memberID.lastIndexOf( '\\' ) + 1 ); + } + else + { + return memberID; + } + } + + /** + * Optionally, one may set a line terminator, if the default is not desired. + * + * @param lineTerminator + */ + public void setLineTerminator( String lineTerminator ) + { + this.lineTerminator = lineTerminator; + } + + /** + * Optionally, one may choose not to overwrite existing files, this may speed up the synchronization process. + * + * @param overwriteExisting + */ + public void setOverwriteExisting( String overwriteExisting ) + { + this.overwriteExisting = overwriteExisting; + } + + /** + * Optionally, one might want to restore the timestamp, if the build is smart not to recompile files that were not touched. + * + * @param restoreTimestamp + */ + public void setRestoreTimestamp( boolean restoreTime ) + { + if ( restoreTime ) + { + this.restoreTimestamp = "restoreTimestamp"; + } + else + { + this.restoreTimestamp = "norestoreTimestamp"; + } + } + + /** + * Performs a checkout of this MKS Integrity Source File to a working file location on the build server represented by targetFile + * + * @param api MKS API Session + * @return true if the operation succeeded or false if failed + * @throws APIException + */ + public boolean checkout( APISession api ) + throws APIException + { + // Make sure the directory is created + if ( !targetFile.getParentFile().isDirectory() ) + { + targetFile.getParentFile().mkdirs(); + } + // Construct the project check-co command + Command coCMD = new Command( Command.SI, "projectco" ); + coCMD.addOption( new Option( overwriteExisting ) ); + coCMD.addOption( new Option( "nolock" ) ); + coCMD.addOption( new Option( "project", projectConfigPath ) ); + coCMD.addOption( new FileOption( "targetFile", targetFile ) ); + coCMD.addOption( new Option( restoreTimestamp ) ); + coCMD.addOption( new Option( "lineTerminator", lineTerminator ) ); + coCMD.addOption( new Option( "revision", memberRev ) ); + // Add the member selection + coCMD.addSelection( memberID ); + + // Execute the checkout command + Response res = api.runCommand( coCMD ); + + // Return true if we were successful + if ( res.getExitCode() == 0 ) + { + return true; + } + // Otherwise return false... + else + { + return false; + } + } + + /** + * Uses the name of file for equality check + */ + @Override + public boolean equals( Object o ) + { + if ( o instanceof Member ) + { + if ( null != o ) + { + return ( (Member) o ).getMemberName().equals( this.getMemberName() ); + } + } + return false; + } +}
http://git-wip-us.apache.org/repos/asf/maven-scm/blob/8ad9801d/maven-scm-providers/maven-scm-provider-integrity/src/main/java/org/apache/maven/scm/provider/integrity/Project.java ---------------------------------------------------------------------- diff --git a/maven-scm-providers/maven-scm-provider-integrity/src/main/java/org/apache/maven/scm/provider/integrity/Project.java b/maven-scm-providers/maven-scm-provider-integrity/src/main/java/org/apache/maven/scm/provider/integrity/Project.java index 80be22c..cc071a6 100644 --- a/maven-scm-providers/maven-scm-provider-integrity/src/main/java/org/apache/maven/scm/provider/integrity/Project.java +++ b/maven-scm-providers/maven-scm-provider-integrity/src/main/java/org/apache/maven/scm/provider/integrity/Project.java @@ -1,413 +1,413 @@ -package org.apache.maven.scm.provider.integrity; - -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import com.mks.api.Command; -import com.mks.api.MultiValue; -import com.mks.api.Option; -import com.mks.api.response.APIException; -import com.mks.api.response.Field; -import com.mks.api.response.Response; -import com.mks.api.response.WorkItem; -import com.mks.api.response.WorkItemIterator; -import com.mks.api.si.SIModelTypeName; - -import java.util.ArrayList; -import java.util.Calendar; -import java.util.Collections; -import java.util.Comparator; -import java.util.Date; -import java.util.Hashtable; -import java.util.List; -import java.util.NoSuchElementException; - -/** - * This class represents a MKS Integrity Configuration Management Project - * <br>Provides metadata information about a Project - * - * @author <a href="mailto:cle...@mks.com">Cletus D'Souza</a> - * @version $Id: Project.java 1.6 2011/08/22 13:06:48EDT Cletus D'Souza (dsouza) Exp $ - * @since 1.6 - */ -public class Project -{ - public static final String NORMAL_PROJECT = "Normal"; - - public static final String VARIANT_PROJECT = "Variant"; - - public static final String BUILD_PROJECT = "Build"; - - private String projectName; - - private String projectType; - - private String projectRevision; - - private String fullConfigSyntax; - - private Date lastCheckpoint; - - private APISession api; - - // Create a custom comparator to compare project members - public static final Comparator<Member> FILES_ORDER = new Comparator<Member>() - { - public int compare( Member cmm1, Member cmm2 ) - { - return cmm1.getMemberName().compareToIgnoreCase( cmm2.getMemberName() ); - } - }; - - /** - * Checks if the given value is a valid MKS Integrity Label. - * <br>If it's invalid, this method throws an exception providing the reason as string. - * - * @param tagName The checkpoint label name - * @return the error message, or null if label is valid - */ - public static void validateTag( String tagName ) - throws Exception - { - if ( tagName == null || tagName.length() == 0 ) - { - throw new Exception( "The checkpoint label string is empty!" ); - } - - char ch = tagName.charAt( 0 ); - if ( !( ( 'A' <= ch && ch <= 'Z' ) || ( 'a' <= ch && ch <= 'z' ) ) ) - { - throw new Exception( "The checkpoint label must start with an alpha character!" ); - } - - for ( char invalid : "$,.:;/\\@".toCharArray() ) - { - if ( tagName.indexOf( invalid ) >= 0 ) - { - throw new Exception( - "The checkpoint label may cannot contain one of the following characters: $ , . : ; / \\ @" ); - } - } - } - - /** - * Creates an instance of an Integrity SCM Project - * - * @param api MKS API Session object - * @param configPath Configuration path for the MKS Integrity SCM Project - * @throws APIException - */ - public Project( APISession api, String configPath ) - throws APIException - { - // Initialize our local APISession - this.api = api; - try - { - // Get the project information for this project - Command siProjectInfoCmd = new Command( Command.SI, "projectinfo" ); - siProjectInfoCmd.addOption( new Option( "project", configPath ) ); - api.getLogger().info( "Preparing to execute si projectinfo for " + configPath ); - Response infoRes = api.runCommand( siProjectInfoCmd ); - // Get the only work item from the response - WorkItem wi = infoRes.getWorkItems().next(); - // Get the metadata information about the project - Field pjNameFld = wi.getField( "projectName" ); - Field pjTypeFld = wi.getField( "projectType" ); - Field pjCfgPathFld = wi.getField( "fullConfigSyntax" ); - Field pjChkptFld = wi.getField( "lastCheckpoint" ); - - // Convert to our class fields - // First obtain the project name field - if ( null != pjNameFld && null != pjNameFld.getValueAsString() ) - { - projectName = pjNameFld.getValueAsString(); - } - else - { - api.getLogger().warn( "Project info did not provide a value for the 'projectName' field!" ); - projectName = ""; - } - // Next, we'll need to know the project type - if ( null != pjTypeFld && null != pjTypeFld.getValueAsString() ) - { - projectType = pjTypeFld.getValueAsString(); - if ( isBuild() ) - { - // Next, we'll need to know the current build checkpoint for this configuration - Field pjRevFld = wi.getField( "revision" ); - if ( null != pjRevFld && null != pjRevFld.getItem() ) - { - projectRevision = pjRevFld.getItem().getId(); - } - else - { - projectRevision = ""; - api.getLogger().warn( "Project info did not provide a vale for the 'revision' field!" ); - } - } - } - else - { - api.getLogger().warn( "Project info did not provide a value for the 'projectType' field!" ); - projectType = ""; - } - // Most important is the configuration path - if ( null != pjCfgPathFld && null != pjCfgPathFld.getValueAsString() ) - { - fullConfigSyntax = pjCfgPathFld.getValueAsString(); - } - else - { - api.getLogger().error( "Project info did not provide a value for the 'fullConfigSyntax' field!" ); - fullConfigSyntax = ""; - } - // Finally, we'll need to store the last checkpoint to figure out differences, etc. - if ( null != pjChkptFld && null != pjChkptFld.getDateTime() ) - { - lastCheckpoint = pjChkptFld.getDateTime(); - } - else - { - api.getLogger().warn( "Project info did not provide a value for the 'lastCheckpoint' field!" ); - lastCheckpoint = Calendar.getInstance().getTime(); - } - } - catch ( NoSuchElementException nsee ) - { - api.getLogger().error( "Project info did not provide a value for field " + nsee.getMessage() ); - } - } - - /** - * Returns the project path for this Integrity SCM Project - * - * @return - */ - public String getProjectName() - { - return projectName; - } - - /** - * Returns the project revision for this Integrity SCM Project - * - * @return - */ - public String getProjectRevision() - { - return projectRevision; - } - - /** - * Returns true is this is a Normal Project - * - * @return - */ - public boolean isNormal() - { - if ( projectType.equalsIgnoreCase( NORMAL_PROJECT ) ) - { - return true; - } - else - { - return false; - } - } - - /** - * Returns true if this is a Variant Project - * - * @return - */ - public boolean isVariant() - { - if ( projectType.equalsIgnoreCase( VARIANT_PROJECT ) ) - { - return true; - } - else - { - return false; - } - } - - /** - * Returns true if this is a Build Project - * - * @return - */ - public boolean isBuild() - { - if ( projectType.equalsIgnoreCase( BUILD_PROJECT ) ) - { - return true; - } - else - { - return false; - } - } - - /** - * Returns the Full Configuration Path for this Integrity SCM Project - * - * @return - */ - public String getConfigurationPath() - { - return fullConfigSyntax; - } - - /** - * Returns the date when the last checkpoint was performed on this Project - * - * @return - */ - public Date getLastCheckpointDate() - { - return lastCheckpoint; - } - - /** - * Parses the output from the si viewproject command to get a list of members - * - * @param workspaceDir The current workspace directory, which is required for an export - * @return The list of Member objects for this project - * @throws APIException - */ - public List<Member> listFiles( String workspaceDir ) - throws APIException - { - // Re-initialize the member list for this project - List<Member> memberList = new ArrayList<Member>(); - // Initialize the project config hash - Hashtable<String, String> pjConfigHash = new Hashtable<String, String>(); - // Add the mapping for this project - pjConfigHash.put( projectName, fullConfigSyntax ); - // Compute the project root directory - String projectRoot = projectName.substring( 0, projectName.lastIndexOf( '/' ) ); - - // Now, lets parse this project - Command siViewProjectCmd = new Command( Command.SI, "viewproject" ); - siViewProjectCmd.addOption( new Option( "recurse" ) ); - siViewProjectCmd.addOption( new Option( "project", fullConfigSyntax ) ); - MultiValue mvFields = new MultiValue( "," ); - mvFields.add( "name" ); - mvFields.add( "context" ); - mvFields.add( "memberrev" ); - mvFields.add( "membertimestamp" ); - mvFields.add( "memberdescription" ); - siViewProjectCmd.addOption( new Option( "fields", mvFields ) ); - api.getLogger().info( "Preparing to execute si viewproject for " + fullConfigSyntax ); - Response viewRes = api.runCommand( siViewProjectCmd ); - - // Iterate through the list of members returned by the API - WorkItemIterator wit = viewRes.getWorkItems(); - while ( wit.hasNext() ) - { - WorkItem wi = wit.next(); - if ( wi.getModelType().equals( SIModelTypeName.SI_SUBPROJECT ) ) - { - // Save the configuration path for the current subproject, using the canonical path name - pjConfigHash.put( wi.getField( "name" ).getValueAsString(), wi.getId() ); - } - else if ( wi.getModelType().equals( SIModelTypeName.MEMBER ) ) - { - // Figure out this member's parent project's canonical path name - String parentProject = wi.getField( "parent" ).getValueAsString(); - // Instantiate our Integrity CM Member object - Member iCMMember = new Member( wi, pjConfigHash.get( parentProject ), projectRoot, workspaceDir ); - // Add this to the full list of members in this project - memberList.add( iCMMember ); - } - else - { - api.getLogger().warn( "View project output contains an invalid model type: " + wi.getModelType() ); - } - } - - // Sort the files list... - Collections.sort( memberList, FILES_ORDER ); - return memberList; - } - - /** - * Performs a checkpoint on the Integrity SCM Project - * - * @param message Checkpoint description - * @param tag Checkpoint label - * @return MKS API Response object - * @throws APIException - */ - public Response checkpoint( String message, String tag ) - throws APIException - { - // Setup the checkpoint command - api.getLogger().debug( "Checkpointing project " + fullConfigSyntax + " with label '" + tag + "'" ); - // Construct the checkpoint command - Command siCheckpoint = new Command( Command.SI, "checkpoint" ); - siCheckpoint.addOption( new Option( "recurse" ) ); - // Set the project name - siCheckpoint.addOption( new Option( "project", fullConfigSyntax ) ); - // Set the label - siCheckpoint.addOption( new Option( "label", tag ) ); - // Set the description, if specified - if ( null != message && message.length() > 0 ) - { - siCheckpoint.addOption( new Option( "description", message ) ); - } - // Run the checkpoint command - return api.runCommand( siCheckpoint ); - } - - /** - * Creates a Development Path (project branch) for the MKS Integrity SCM Project - * - * @param devPath Development Path Name - * @return MKS API Response object - * @throws APIException - */ - public Response createDevPath( String devPath ) - throws APIException - { - // First we need to obtain a checkpoint from the current configuration (normal or variant) - String chkpt = projectRevision; - if ( !isBuild() ) - { - Response chkptRes = checkpoint( "Pre-checkpoint for development path " + devPath, devPath + " Baseline" ); - WorkItem wi = chkptRes.getWorkItem( fullConfigSyntax ); - chkpt = wi.getResult().getField( "resultant" ).getItem().getId(); - } - - // Now lets setup the create development path command - api.getLogger().debug( - "Creating development path '" + devPath + "' for project " + projectName + " at revision '" + chkpt + "'" ); - Command siCreateDevPath = new Command( Command.SI, "createdevpath" ); - siCreateDevPath.addOption( new Option( "devpath", devPath ) ); - // Set the project name - siCreateDevPath.addOption( new Option( "project", projectName ) ); - // Set the checkpoint we want to create the development path from - siCreateDevPath.addOption( new Option( "projectRevision", chkpt ) ); - // Run the create development path command - return api.runCommand( siCreateDevPath ); - } -} - +package org.apache.maven.scm.provider.integrity; + +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import com.mks.api.Command; +import com.mks.api.MultiValue; +import com.mks.api.Option; +import com.mks.api.response.APIException; +import com.mks.api.response.Field; +import com.mks.api.response.Response; +import com.mks.api.response.WorkItem; +import com.mks.api.response.WorkItemIterator; +import com.mks.api.si.SIModelTypeName; + +import java.util.ArrayList; +import java.util.Calendar; +import java.util.Collections; +import java.util.Comparator; +import java.util.Date; +import java.util.Hashtable; +import java.util.List; +import java.util.NoSuchElementException; + +/** + * This class represents a MKS Integrity Configuration Management Project + * <br>Provides metadata information about a Project + * + * @author <a href="mailto:cle...@mks.com">Cletus D'Souza</a> + * @version $Id: Project.java 1.6 2011/08/22 13:06:48EDT Cletus D'Souza (dsouza) Exp $ + * @since 1.6 + */ +public class Project +{ + public static final String NORMAL_PROJECT = "Normal"; + + public static final String VARIANT_PROJECT = "Variant"; + + public static final String BUILD_PROJECT = "Build"; + + private String projectName; + + private String projectType; + + private String projectRevision; + + private String fullConfigSyntax; + + private Date lastCheckpoint; + + private APISession api; + + // Create a custom comparator to compare project members + public static final Comparator<Member> FILES_ORDER = new Comparator<Member>() + { + public int compare( Member cmm1, Member cmm2 ) + { + return cmm1.getMemberName().compareToIgnoreCase( cmm2.getMemberName() ); + } + }; + + /** + * Checks if the given value is a valid MKS Integrity Label. + * <br>If it's invalid, this method throws an exception providing the reason as string. + * + * @param tagName The checkpoint label name + * @return the error message, or null if label is valid + */ + public static void validateTag( String tagName ) + throws Exception + { + if ( tagName == null || tagName.length() == 0 ) + { + throw new Exception( "The checkpoint label string is empty!" ); + } + + char ch = tagName.charAt( 0 ); + if ( !( ( 'A' <= ch && ch <= 'Z' ) || ( 'a' <= ch && ch <= 'z' ) ) ) + { + throw new Exception( "The checkpoint label must start with an alpha character!" ); + } + + for ( char invalid : "$,.:;/\\@".toCharArray() ) + { + if ( tagName.indexOf( invalid ) >= 0 ) + { + throw new Exception( + "The checkpoint label may cannot contain one of the following characters: $ , . : ; / \\ @" ); + } + } + } + + /** + * Creates an instance of an Integrity SCM Project + * + * @param api MKS API Session object + * @param configPath Configuration path for the MKS Integrity SCM Project + * @throws APIException + */ + public Project( APISession api, String configPath ) + throws APIException + { + // Initialize our local APISession + this.api = api; + try + { + // Get the project information for this project + Command siProjectInfoCmd = new Command( Command.SI, "projectinfo" ); + siProjectInfoCmd.addOption( new Option( "project", configPath ) ); + api.getLogger().info( "Preparing to execute si projectinfo for " + configPath ); + Response infoRes = api.runCommand( siProjectInfoCmd ); + // Get the only work item from the response + WorkItem wi = infoRes.getWorkItems().next(); + // Get the metadata information about the project + Field pjNameFld = wi.getField( "projectName" ); + Field pjTypeFld = wi.getField( "projectType" ); + Field pjCfgPathFld = wi.getField( "fullConfigSyntax" ); + Field pjChkptFld = wi.getField( "lastCheckpoint" ); + + // Convert to our class fields + // First obtain the project name field + if ( null != pjNameFld && null != pjNameFld.getValueAsString() ) + { + projectName = pjNameFld.getValueAsString(); + } + else + { + api.getLogger().warn( "Project info did not provide a value for the 'projectName' field!" ); + projectName = ""; + } + // Next, we'll need to know the project type + if ( null != pjTypeFld && null != pjTypeFld.getValueAsString() ) + { + projectType = pjTypeFld.getValueAsString(); + if ( isBuild() ) + { + // Next, we'll need to know the current build checkpoint for this configuration + Field pjRevFld = wi.getField( "revision" ); + if ( null != pjRevFld && null != pjRevFld.getItem() ) + { + projectRevision = pjRevFld.getItem().getId(); + } + else + { + projectRevision = ""; + api.getLogger().warn( "Project info did not provide a vale for the 'revision' field!" ); + } + } + } + else + { + api.getLogger().warn( "Project info did not provide a value for the 'projectType' field!" ); + projectType = ""; + } + // Most important is the configuration path + if ( null != pjCfgPathFld && null != pjCfgPathFld.getValueAsString() ) + { + fullConfigSyntax = pjCfgPathFld.getValueAsString(); + } + else + { + api.getLogger().error( "Project info did not provide a value for the 'fullConfigSyntax' field!" ); + fullConfigSyntax = ""; + } + // Finally, we'll need to store the last checkpoint to figure out differences, etc. + if ( null != pjChkptFld && null != pjChkptFld.getDateTime() ) + { + lastCheckpoint = pjChkptFld.getDateTime(); + } + else + { + api.getLogger().warn( "Project info did not provide a value for the 'lastCheckpoint' field!" ); + lastCheckpoint = Calendar.getInstance().getTime(); + } + } + catch ( NoSuchElementException nsee ) + { + api.getLogger().error( "Project info did not provide a value for field " + nsee.getMessage() ); + } + } + + /** + * Returns the project path for this Integrity SCM Project + * + * @return + */ + public String getProjectName() + { + return projectName; + } + + /** + * Returns the project revision for this Integrity SCM Project + * + * @return + */ + public String getProjectRevision() + { + return projectRevision; + } + + /** + * Returns true is this is a Normal Project + * + * @return + */ + public boolean isNormal() + { + if ( projectType.equalsIgnoreCase( NORMAL_PROJECT ) ) + { + return true; + } + else + { + return false; + } + } + + /** + * Returns true if this is a Variant Project + * + * @return + */ + public boolean isVariant() + { + if ( projectType.equalsIgnoreCase( VARIANT_PROJECT ) ) + { + return true; + } + else + { + return false; + } + } + + /** + * Returns true if this is a Build Project + * + * @return + */ + public boolean isBuild() + { + if ( projectType.equalsIgnoreCase( BUILD_PROJECT ) ) + { + return true; + } + else + { + return false; + } + } + + /** + * Returns the Full Configuration Path for this Integrity SCM Project + * + * @return + */ + public String getConfigurationPath() + { + return fullConfigSyntax; + } + + /** + * Returns the date when the last checkpoint was performed on this Project + * + * @return + */ + public Date getLastCheckpointDate() + { + return lastCheckpoint; + } + + /** + * Parses the output from the si viewproject command to get a list of members + * + * @param workspaceDir The current workspace directory, which is required for an export + * @return The list of Member objects for this project + * @throws APIException + */ + public List<Member> listFiles( String workspaceDir ) + throws APIException + { + // Re-initialize the member list for this project + List<Member> memberList = new ArrayList<Member>(); + // Initialize the project config hash + Hashtable<String, String> pjConfigHash = new Hashtable<String, String>(); + // Add the mapping for this project + pjConfigHash.put( projectName, fullConfigSyntax ); + // Compute the project root directory + String projectRoot = projectName.substring( 0, projectName.lastIndexOf( '/' ) ); + + // Now, lets parse this project + Command siViewProjectCmd = new Command( Command.SI, "viewproject" ); + siViewProjectCmd.addOption( new Option( "recurse" ) ); + siViewProjectCmd.addOption( new Option( "project", fullConfigSyntax ) ); + MultiValue mvFields = new MultiValue( "," ); + mvFields.add( "name" ); + mvFields.add( "context" ); + mvFields.add( "memberrev" ); + mvFields.add( "membertimestamp" ); + mvFields.add( "memberdescription" ); + siViewProjectCmd.addOption( new Option( "fields", mvFields ) ); + api.getLogger().info( "Preparing to execute si viewproject for " + fullConfigSyntax ); + Response viewRes = api.runCommand( siViewProjectCmd ); + + // Iterate through the list of members returned by the API + WorkItemIterator wit = viewRes.getWorkItems(); + while ( wit.hasNext() ) + { + WorkItem wi = wit.next(); + if ( wi.getModelType().equals( SIModelTypeName.SI_SUBPROJECT ) ) + { + // Save the configuration path for the current subproject, using the canonical path name + pjConfigHash.put( wi.getField( "name" ).getValueAsString(), wi.getId() ); + } + else if ( wi.getModelType().equals( SIModelTypeName.MEMBER ) ) + { + // Figure out this member's parent project's canonical path name + String parentProject = wi.getField( "parent" ).getValueAsString(); + // Instantiate our Integrity CM Member object + Member iCMMember = new Member( wi, pjConfigHash.get( parentProject ), projectRoot, workspaceDir ); + // Add this to the full list of members in this project + memberList.add( iCMMember ); + } + else + { + api.getLogger().warn( "View project output contains an invalid model type: " + wi.getModelType() ); + } + } + + // Sort the files list... + Collections.sort( memberList, FILES_ORDER ); + return memberList; + } + + /** + * Performs a checkpoint on the Integrity SCM Project + * + * @param message Checkpoint description + * @param tag Checkpoint label + * @return MKS API Response object + * @throws APIException + */ + public Response checkpoint( String message, String tag ) + throws APIException + { + // Setup the checkpoint command + api.getLogger().debug( "Checkpointing project " + fullConfigSyntax + " with label '" + tag + "'" ); + // Construct the checkpoint command + Command siCheckpoint = new Command( Command.SI, "checkpoint" ); + siCheckpoint.addOption( new Option( "recurse" ) ); + // Set the project name + siCheckpoint.addOption( new Option( "project", fullConfigSyntax ) ); + // Set the label + siCheckpoint.addOption( new Option( "label", tag ) ); + // Set the description, if specified + if ( null != message && message.length() > 0 ) + { + siCheckpoint.addOption( new Option( "description", message ) ); + } + // Run the checkpoint command + return api.runCommand( siCheckpoint ); + } + + /** + * Creates a Development Path (project branch) for the MKS Integrity SCM Project + * + * @param devPath Development Path Name + * @return MKS API Response object + * @throws APIException + */ + public Response createDevPath( String devPath ) + throws APIException + { + // First we need to obtain a checkpoint from the current configuration (normal or variant) + String chkpt = projectRevision; + if ( !isBuild() ) + { + Response chkptRes = checkpoint( "Pre-checkpoint for development path " + devPath, devPath + " Baseline" ); + WorkItem wi = chkptRes.getWorkItem( fullConfigSyntax ); + chkpt = wi.getResult().getField( "resultant" ).getItem().getId(); + } + + // Now lets setup the create development path command + api.getLogger().debug( + "Creating development path '" + devPath + "' for project " + projectName + " at revision '" + chkpt + "'" ); + Command siCreateDevPath = new Command( Command.SI, "createdevpath" ); + siCreateDevPath.addOption( new Option( "devpath", devPath ) ); + // Set the project name + siCreateDevPath.addOption( new Option( "project", projectName ) ); + // Set the checkpoint we want to create the development path from + siCreateDevPath.addOption( new Option( "projectRevision", chkpt ) ); + // Run the create development path command + return api.runCommand( siCreateDevPath ); + } +} +