#!/usr/local/bin/ruby # # Copyright 2005 Perforce Software. All rights reserved. # # # P4 Form Data Class and associated useful functions # # # Extract a set from a string # def extract_set(str) list = [] if str != nil && str.length > 0 then list = str.split(/[\t \n,]+/).compact # Drop nil list.delete_if { |val| val =~ /^[\t ]*$/ } # Drop "" list.uniq! # Drop dups end return list end # # Lookup email address for userid # def get_email(userid) if !(userid =~ /@/) then # # p4 user will always return a value so this may not # be a real email address. # P4D: if p4 user -o uid would return an error for non-existant # users, then this would need to change to handle that case cmd=`#{P4_BIN} -u #{P4USER} -p #{P4PORT} user -o #{userid} | egrep "^Email:"`.chomp! parts = cmd.split(/[ \t][ \t]*/) if parts.length > 1 then return parts[1] else return nil end else return userid end end # # Tests if the strlist string is a list of the specified kind # def islistof(strlist, kind) list=extract_set(strlist) list.each do |item| cmd="#{kind}(\"#{item}\")" if (item =~ /["]/) || (not eval(cmd)) then return false end end return true end # # Tests if value string is a changelist # def ischangelist(in_value) if in_value == nil || in_value.strip == "" then return true end value = in_value.strip if value =~ /^[1-9][0-9]*$/ then # # p4 change -o cid returns an error if cid does not exist # cmd=`#{P4_BIN} -u #{P4USER} -p #{P4PORT} change -o #{value} > /dev/null 2>&1 ; echo $?`.chomp! if cmd == "0" then return true else return false end else return false end return false end # # Tests if value string is a userid # def isuserid(in_value) if in_value == nil || in_value.strip == "" then return true end value = in_value.strip if value =~ /^[-_.a-zA-Z0-9]+$/ then # # p4 user -o uid always returns something even if uid does not exist # so this uses p4 users to list them all and see if the one exists # This is terribly inefficient # P4D: add support so that p4 user -o uid returns an error if the # user does not exist. If this is done then the change would # be to make this like ischangelist above # cmd=`#{P4_BIN} -u #{P4USER} -p #{P4PORT} users | egrep "^#{value} " > /dev/null 2>&1 ; echo $?`.chomp! if cmd == "0" then return true else return false end else return false end return false end # # Tests if value string is a jobid # def isjobid(in_value) if in_value == nil || in_value.strip == "" then return true end value = in_value.strip if value =~ /^[-_.a-zA-Z0-9]+$/ then # # This requires the spec depot to be enabled in order to work # P4D: add support such that p4 job -o jid returns an error if the # jid does not exist. If this is done then the change would be # to make this like ischangelist above # cmd= `#{P4_BIN} -u #{P4USER} -p #{P4PORT} fstat //spec/job/#{value}#{P4SPECSUFFIX} 2>&1 | wc -l | awk '{ print $1; }'`.to_i if cmd > 1 then return true else return false end else return false end return false end # # Tests if value string is a depot path # def isdepotpath(in_value) if in_value == nil || in_value.strip == "" then return true end value = in_value.strip # # This does not do much checking, just basic syntax of // followed by # something that is not whitespace # if value =~ /^\/\/[^\t ]+.*$/ then return true else return false end return false end # # Tests if value string is a path to an existing file # def isfilepath(in_value) if in_value == nil || in_value.strip == "" then return true end value = in_value.strip if value =~ /.*[.][.][.]$/ then return false end if value =~ /^\/\/[^\t ]+.*$/ then # # This is a bit hokey, there may be a better way to check to # see if a file exists in the depot # cmd=`#{P4_BIN} -u #{P4USER} -p #{P4PORT} fstat #{value} 2>&1 | wc -l | awk '{ print $1; }'`.to_i if cmd > 1 then return true else return false end else return false end return false end # # Applies the test specified by check to the string value # def checkfield( check, value ) if check == nil then return true end thetest = check.gsub(/[$]VALUE/, "#{value}") result=eval(thetest) if result then return true else return false end end class P4Form # # A form is composed of a set of fields interspersed with # comments delimited by the # character # # Fields are of the following two varieties: # ^field: value # # ^field: # [\t ]value... # # EJPUserID: user Special field indicating that EJP is updating job # so allow read-only fields to be updated and use # this value as the user def initialize( formdata ) @fields = {} @userid = nil # Special field, see below for description @chain = [] # Special field, see below for description @revnum = nil # Special field, see below for description infield=false curfield=nil curvalue=nil formdata.each do |line| line.chomp! case line when /^#/ # ignore comment lines when /^[^\t ]/ # begin field if infield && curvalue != nil && curvalue.strip != "" then @fields[curfield] = curvalue end infield=true curfield = line[/^[^:]*/].strip curvalue = line.sub(/^[^:]*:[\t ]*/, "") when /^[\t ]/ # continue field if infield then curvalue = "#{curvalue}\n#{line}" else # unknown end else # unknown end end # If in a field, make sure to save it if infield && curvalue != nil && curvalue.strip != "" then @fields[curfield] = curvalue end # # Special Field indicating overriding of readonly fields and the # UserID to be used for such changes # if @fields.has_key?("EJPUserID") then @userid = @fields["EJPUserID"] @fields.delete("EJPUserID") end # # Special Field indicating previous Jobs that should not be modified # as a result of any changes/additions/deletions # if @fields.has_key?("EJPChain") then @chain = extract_set(@fields["EJPChain"]) @fields.delete("EJPChain") end # # Special Field indicating which revision in the spec depot to # use for determining changes # if @fields.has_key?("EJPRevNum") then @revnum = extract_set(@fields["EJPRevNum"]) @fields.delete("EJPRevNum") end end attr_reader :fields attr_reader :userid attr_reader :chain attr_reader :revnum def print(obj) for f in @fields.keys do obj.printf("%s: %s\n\n", f, fields[f]) end end def validate( checks ) invalid = [] invalid << @fields.keys invalid.delete_if { |val| checkfield(checks[val], @fields[val]) } return invalid end def validate_fields( thesefields, checks ) invalid = [] invalid = thesefields.clone invalid.delete_if { |val| checkfield(checks[val], @fields[val]) } return invalid end end