Class CaseTrigger
In: checkcase.rb
Parent: P4Trigger

The trigger class itself. The main method in here is validate() which is invoked from the super-class’ parse_change() method.

Methods
mismatch_depot    mismatch_dirs    mismatch_exists    new    report    validate   
Public Class methods
new( max_errors )

Constructor. In this trigger we want to limit the number of errors we might report to the user because on a large changelist that could be a real pain. Simply pass the maximum number you want your users to deal with at one time.

# File checkcase.rb, line 54
    def initialize( max_errors )
        @max_errors = max_errors
        super()
    end
Public Instance methods
validate()

Enforce case checking. the basic algorithm is that we split the depot path of each file up into its components and use "p4 depots", "p4 dirs" (depending on what level we’re at to locate existing depots/dirs with the same names in different case. If we find any we reject submission. Note that we are only interested in new files being added/branched since existing files are assumed to be OK.

# File checkcase.rb, line 79
    def validate()
        badlist = Hash.new
        change.each_file do
            |file|
            # Ignore files not open for add or branch
            action = file.revisions[ 0 ].action
            next unless ( action == "add" || action == "branch" )

            if ( mismatch_exists( file.depot_file ) )
                # @mismatch set by mismatch_exists() et. al.
                badlist[ file.depot_file ] = @mismatch
            end
        end

        # Now report any problems to the user
        report( badlist ) if ( ! badlist.empty? )
        return badlist.empty?
    end
mismatch_exists( path )

This method does the work to check whether or not the components of a path already exist in different case. We do it by breaking the depot path up into components where the first part is the depot name, the last part is the filename and everything in between is a directory name. We then start at the depot and then iteratively check the directories one by one.

# File checkcase.rb, line 104
    def mismatch_exists( path )
        path = path[ 2..-1 ]   # Strip off leading //
        dirs = path.split( "/" )
        depot = dirs.shift
        file  = dirs.pop

        # Now look for mis-matching depots
        return true if mismatch_depot( depot )

        # Now look for mis-matching directories
        return true if mismatch_dirs( depot, dirs )

        return false
    end
mismatch_depot( depot )

Method to see whether a depot with a name matching the argument already exists.

# File checkcase.rb, line 121
    def mismatch_depot( depot )
        match = false
        lcdepot = depot.downcase
        p4.run_depots.each do
            |line|
            dname = line.split()[ 1 ]
            lcdname = dname.downcase
            if ( lcdname == lcdepot && dname != depot )
                match = true
                @mismatch = "//" + dname
                break
            end
        end
        match
    end
mismatch_dirs( depot, dirs )

Method to descend the tree looking for mismatched directory names. If we find a mismatch at any level we break off and just return true. If there are no mismatches, returns false.

# File checkcase.rb, line 140
    def mismatch_dirs( depot, dirs )
        match = false
        path = "//" + depot
        dirs.each do
            |dir|
            lcpath = path.downcase
            p4.run_dirs( path + "/*" ).each do
                |d|
                d = d[ "dir" ] # We're in tagged mode
                dname = d.sub( path + "/", "" )

                if ( dir.downcase == dname.downcase )
                    # We found a match
                    if ( dir != dname )
                        match = true
                        @mismatch = d
                    end
                    break
                end
            end

            # If we found a mismatch, we can break out now
            break if ( match )

            # This level is now OK, we need to descend to the
            # next level in the tree
            path << "/" << dir
        end
        match
    end
report( badfiles )

Method to report the error to the user. Just formats the error message and sends it. We only report the first @max_errors bad files. On a large changelist they’ll be grateful for that.

# File checkcase.rb, line 174
    def report( badfiles )
        errors = 0
        msg = @@USER_MESSAGE
        badfiles.each do
            |file,mismatch|
            msg += sprintf( @@BADFILE_FORMAT, file, mismatch )
            errors += 1
            break if ( errors >= @max_errors )

        end
        message( msg )
    end