#
# Copyright 2005 Perforce Software. All rights reserved.
#
require "P4Data.rb"
require "P4Form.rb"
require "P4Valid.rb"
require "P4Jobs.rb"
require "P4Mail.rb"
def notify_people(notify, job, type, n_form, body)
#
# Notifications
#
if n_form.fields[P4OWNEDBYFIELD] != nil then
notify["to"] << n_form.fields[P4OWNEDBYFIELD]
end
if n_form.fields[P4INTERESTEDINFIELD] != nil then
notify["cc"] << extract_set(n_form.fields[P4INTERESTEDINFIELD])
end
notify["cc"] << product_watchers(P4INTERESTED, n_form.fields[P4PRODUCTFIELD])
notify["cc"].flatten!
notify["cc"].compact!
notify["cc"].sort!
notify["cc"].uniq!
notify["to"].flatten!
notify["to"].compact!
notify["to"].sort!
notify["to"].uniq!
if notify["to"].length > 0 || notify["cc"].length > 0 then
dlist = n_form.fields[P4DESCRIPTIONFIELD].split(/[ \t]*\n[ \t\n]*/)
description = ""
if dlist[0] == nil || dlist[0].strip == "" then
if dlist[1] == nil then
description = ""
else
description = dlist[1].strip
end
else
description = dlist[0].strip
end
msg = P4Mail.new
msg.from = P4ADMINEMAIL
msg.to_list << notify["to"]
msg.to_list.flatten!
msg.cc_list << notify["cc"]
msg.cc_list.flatten!
msg.subject = sprintf("Job %s: %s - %s", type, job, description)
msg.body = body.join("\n")
msg.send()
end
end
#
# Logic for processing of duplicates
# Return "" for accepting job or "problem desc" for rejecting job
#
# Duplicate Handling:
# - Update DuplicateOf job in the following ways:
# Add current jobid to DuplicateJobs
# For each field in P4DUPAPPEND, append dup's field values
# - Generate a discrepency report if needed
#
def dup_job(u, logfile, myjobid, dupjobid, n_form, chain)
rejected = ""
d_form = P4Form.new(`#{P4_BIN} -u #{P4USER} -p #{P4PORT} job -o #{dupjobid}`.split("\n"))
#
# Update DuplicateJob field
#
curdups = extract_set(d_form.fields[P4DUPLICATEJOBSFIELD])
logfile.printf("Adding to DuplicateJobs [%s]: [%s]\n", ##DEBUG
curdups.join(", "), myjobid) ##DEBUG
if curdups.include?(myjobid) then
logfile.printf("DuplicateJobs already contains: [%s]\n", ##DEBUG
myjobid) ##DEBUG
return rejected
end
curdups << myjobid
curdups.uniq!
curdups.sort!
if P4SETS[P4DUPLICATEJOBSFIELD] == "1" then
d_form.fields[P4DUPLICATEJOBSFIELD] = curdups.join(" ")
else
d_form.fields[P4DUPLICATEJOBSFIELD] = curdups.join("\n\t")
end
#
# COPY/CUT Fields
#
(P4DUPCOPY+P4DUPCUT).each do |field|
if n_form.fields.keys.include?(field) then
newval = ""
if d_form.fields.keys.include?(field) then
if P4HISTORY[field] != "text" then
newval = sprintf("%s %s", d_form.fields[field], n_form.fields[field])
else
newval = sprintf("%s\n\t%s", d_form.fields[field],
n_form.fields[field])
end
else
newval = n_form.fields[field]
end
if P4SETS.keys.include?(field) then
if P4SETS[field] == "1" then
d_form.fields[field] = extract_set(newval).sort.join(" ")
else
d_form.fields[field] = extract_set(newval).sort.join("\n\t")
end
else
d_form.fields[field] = newval
end
end
end
#
# Save Job
#
p4proc = IO.popen("p4 -u #{u} job -i", "w+") # Force user to be 'u'
logfile.printf("Updating job:\n") ##DEBUG
d_form.print(logfile) ##DEBUG
d_form.print(p4proc)
p4proc.printf("EJPUserID: %s\n", u) # Tag as EJP update and save UserID
p4proc.printf("EJPChain: %s %s\n", myjobid, chain) # Add cur to chain
p4proc.close_write
saved = false
p4proc.each do |line|
logfile.print line ##DEBUG
if line =~ /Job #{dupjobid} saved/ then
saved = true
end
end
p4proc.close_read
if !saved then
rejected = "Unable to update specified DuplicateOf job"
end
return rejected
end
def undup_job(u, logfile, myjobid, dupjobid, n_form, chain)
rejected = ""
d_form = P4Form.new(`#{P4_BIN} -u #{P4USER} -p #{P4PORT} job -o #{dupjobid}`.split("\n"))
#
# Update DuplicateJob field
#
curdups = extract_set(d_form.fields[P4DUPLICATEJOBSFIELD])
logfile.printf("Removing from DuplicateJob: [%s] with [%s]\n", ##DEBUG
curdups.join(", "), myjobid) ##DEBUG
curdups.delete(myjobid)
curdups.uniq!
curdups.sort!
if P4SETS[P4DUPLICATEJOBSFIELD] == "1" then
d_form.fields[P4DUPLICATEJOBSFIELD] = curdups.join(" ")
else
d_form.fields[P4DUPLICATEJOBSFIELD] = curdups.join("\n\t")
end
#
# Save Job
#
p4proc = IO.popen("p4 -u #{u} job -i", "w+") # Force user to be 'u'
logfile.printf("Updating job:\n") ##DEBUG
d_form.print(logfile) ##DEBUG
d_form.print(p4proc)
p4proc.printf("EJPUserID: %s\n", u) # Tag as EJP update and save UserID
p4proc.printf("EJPChain: %s %s\n", myjobid, chain) # Add cur to chain
p4proc.close_write
saved = false
p4proc.each do |line|
logfile.print line ##DEBUG
if line =~ /Job #{dupjobid} saved/ then
saved = true
end
end
p4proc.close_read
if !saved then
rejected = "Unable to update specified DuplicateOf job"
end
return rejected
end
#
# Logic for processing of RelatedJobs
# Return "" for accepting job or "problem desc" for rejecting job
#
# RelatedJobs Handling: maintain cross-reference btw jobs
#
def related_job(u, logfile, add_flag, myjobid, reljobid, chain)
rejected = ""
if myjobid == reljobid then
return rejected
end
r_form = P4Form.new(`#{P4_BIN} -u #{P4USER} -p #{P4PORT} job -o #{reljobid}`.split("\n"))
related_jobs = extract_set(r_form.fields[P4RELATEDJOBSFIELD])
logfile.printf("RelatedJobs(Pre)[%s]\n", related_jobs.join("|")) ##DEBUG
if add_flag then
related_jobs << myjobid
else
related_jobs.delete(myjobid)
end
logfile.printf("RelatedJobs(Post)[%s]\n", related_jobs.join("|")) ##DEBUG
r_form.fields[P4RELATEDJOBSFIELD] = related_jobs.join(", ")
p4proc = IO.popen("p4 -u #{u} job -i", "w+") # Force user to be 'u'
logfile.printf("Updating job:\n") ##DEBUG
r_form.print(logfile) ##DEBUG
r_form.print(p4proc)
p4proc.printf("EJPUserID: %s\n", u) # Tag as EJP update and save UserID
p4proc.printf("EJPChain: %s %s\n", myjobid, chain) # Add cur to chain
p4proc.close_write
saved = false
p4proc.each do |line|
logfile.print line ##DEBUG
if line =~ /Job #{reljobid} saved/ then
saved = true
end
end
p4proc.close_read
if !saved then
rejected = "Unable to update specified RelatedJob job"
end
return rejected
end
#
# Logic for processing of job changes
# Return "" for accepting job or "problem desc" for rejecting job
#
# Update n_form with any changes to be made to job
#
def job_changed(ts, u, logfile, n_form, o_form, changed, added, deleted)
notify = { "to" => [], "cc" => [] }
rejected = ""
myjobid = n_form.fields[P4JOBFIELD].strip
if (changed.include?(P4DUPLICATEOFFIELD) ||
added.include?(P4DUPLICATEOFFIELD)) &&
n_form.fields[P4STATUSFIELD].strip != "duplicate" then
rejected = "DuplicateOf cannot be defined for non-duplicate jobs"
elsif (n_form.fields[P4STATUSFIELD].strip == "duplicate" &&
n_form.fields[P4DUPLICATEOFFIELD] == nil) then
rejected = "Duplicate jobs must have DuplicateOf defined\n"
elsif changed.include?(P4DUPLICATEOFFIELD) then
rejected =
"DuplicateOf cannot be changed, change state and delete field"
end
duped = false
if rejected == "" && changed.include?(P4STATUSFIELD) then
if n_form.fields[P4STATUSFIELD].strip == "duplicate" then
#
# Duplicate Handling:
# - Check that DupliateOf is defined, else error
#
dupjobid = n_form.fields[P4DUPLICATEOFFIELD]
if dupjobid == nil then
rejected = "Duplicate jobs must have DuplicateOf defined\n"
elsif ( dupjobid == myjobid )
rejected = "Duplicate jobs may not be a duplicate of themselves\n"
else
rejected = dup_job(u, logfile, myjobid, dupjobid.strip,
n_form, n_form.chain)
duped = true
if !changed.include?(P4OWNEDBYFIELD) then
# Since the owner wasn't changed, update accordingly
newowner = state_owner(P4FLOW, n_form.fields, P4STATUSFIELD,
P4PRODUCTFIELD)
if newowner != "" && newowner != n_form.fields[P4OWNEDBYFIELD] then
if n_form.fields[P4OWNEDBYFIELD] != nil then
changed << P4OWNEDBYFIELD
else
added << P4OWNEDBYFIELD
end
n_form.fields[P4OWNEDBYFIELD] = newowner
end
end
end
elsif n_form.fields.keys.include?(P4DUPLICATEOFFIELD) then
rejected = "DuplicateOf cannot be defined for non-duplicate jobs"
else
# SOME OTHER STATUS CHANGE TO BE HANDLED
if o_form.fields[P4STATUSFIELD].strip == "duplicate" then
dupjobid = o_form.fields[P4DUPLICATEOFFIELD]
rejected = undup_job(u, logfile, myjobid, dupjobid.strip,
n_form, n_form.chain)
end
if n_form.fields[P4STATUSFIELD].strip == "closed" then
# Save who closed the job
n_form.fields[P4CLOSEDBYFIELD] = u
if o_form.fields[P4CLOSEDBYFIELD] != nil then
changed << P4CLOSEDBYFIELD
else
added << P4CLOSEDBYFIELD
end
end
if !changed.include?(P4OWNEDBYFIELD) then
# Since the owner wasn't changed, update accordingly
newowner = ""
if n_form.fields[P4STATUSFIELD].strip == "closed" &&
n_form.fields["ClosedOwner"] != nil then
newowner = n_form.fields["ClosedOwner"]
else
newowner = state_owner(P4FLOW, n_form.fields, P4STATUSFIELD,
P4PRODUCTFIELD)
end
if newowner != "" && newowner != n_form.fields[P4OWNEDBYFIELD] then
if n_form.fields[P4OWNEDBYFIELD] != nil then
changed << P4OWNEDBYFIELD
else
added << P4OWNEDBYFIELD
end
n_form.fields[P4OWNEDBYFIELD] = newowner
end
end
end
end
#
# Handle RelatedJobs field, but only for the first job
#
if rejected == "" &&
(changed.include?(P4RELATEDJOBSFIELD) ||
added.include?(P4RELATEDJOBSFIELD) ||
deleted.include?(P4RELATEDJOBSFIELD)) then
n_jobs = extract_set(n_form.fields[P4RELATEDJOBSFIELD])
o_jobs = extract_set(o_form.fields[P4RELATEDJOBSFIELD])
del_jobs = o_jobs - n_jobs
del_jobs.each do |job|
if !n_form.chain.include?(job) then
rejected = related_job(u, logfile, false, myjobid, job, n_form.chain)
end
if rejected != "" then
break
end
end
if rejected == "" then
add_jobs = n_jobs - o_jobs
add_jobs.each do |job|
if !n_form.chain.include?(job) then
rejected = related_job(u, logfile, true, myjobid, job, n_form.chain)
end
if rejected != "" then
break
end
end
end
end
#
# Add History Info
#
if rejected == "" then
moved = []
if duped then
P4DUPCUT.each do |field|
if n_form.fields.keys.include?(field) then
moved << field
end
end
end
append_history(ts, u, logfile, n_form, o_form, changed, added, deleted, moved)
moved.each do |field|
n_form.fields[field] = ""
end
if changed.include?(P4OWNEDBYFIELD) ||
deleted.include?(P4OWNEDBYFIELD) then
notify["to"] << o_form.fields[P4OWNEDBYFIELD]
end
if changed.include?(P4STATUSFIELD) &&
n_form.fields[P4STATUSFIELD] =~ /(closed|punted)/ then
notify["to"] << n_form.fields[P4REPORTEDBYFIELD]
end
if changed.include?(P4REPORTEDBYFIELD) then
notify["to"] << o_form.fields[P4REPORTEDBYFIELD]
end
if o_form.fields[P4INTERESTEDINFIELD] != nil then
# May be duplicates and such but they will be dropped later on
notify["cc"] << extract_set(o_form.fields[P4INTERESTEDINFIELD])
end
history_chunks = n_form.fields[P4HISTORYFIELD].split(/[ \t]*\n/)
body = []
history_chunks.each do |line|
if line == "" then
break;
end
body << line[1..-1]
end
notify_people(notify, myjobid, "Updated", n_form, body)
end
return rejected
end
#
# Logic for processing of new jobs
# Return "" for accepting job or "problem desc" for rejecting job
#
# Update n_form with any changes to be made to job
#
def job_added(ts, u, logfile, n_form)
logfile.printf("job_added(%s %s)\n", ts, u) ##DEBUG
logfile.printf("n_form:\n") ##DEBUG
n_form.print(logfile) ##DEBUG
if n_form.fields[P4STATUSFIELD] == nil then
return "Status must be specified"
end
if n_form.fields[P4STATUSFIELD].strip == "duplicate" then
return "Status cannot be initialized as duplicate"
end
if n_form.fields[P4STATUSFIELD].strip == "closed" then
return "Status cannot be initialized as closed"
end
if n_form.fields.keys.include?(P4DUPLICATEOFFIELD) then
return "DuplicateOf cannot be defined for non-duplicate jobs"
end
if !n_form.fields.keys.include?(P4OWNEDBYFIELD) then
# Since the owner has not been set, update accordingly
newowner = state_owner(P4FLOW, n_form.fields, P4STATUSFIELD, P4PRODUCTFIELD)
logfile.printf("RevisedOwner: %s\n", newowner) ##DEBUG
if newowner != "" then
n_form.fields[P4OWNEDBYFIELD] = newowner
end
end
n_form.fields[P4HISTORYFIELD] = sprintf("%s user %s created job", ts, u)
return ""
end