forked from bcurren/cruisecontrolrb_perforce
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathperforce.rb
135 lines (109 loc) · 4.03 KB
/
perforce.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
require 'builder_error'
# Perforce source control implementation for CruiseControl.rb
class Perforce
include CommandLine
attr_accessor :port, :client_spec, :username, :password, :path, :p4path
MAX_CHANGELISTS_TO_FETCH = 25
def initialize(options = {})
@port, @clientspec, @username, @password, @path, @p4path, @interactive =
options.delete(:port), options.delete(:clientspec),
options.delete(:user), options.delete(:password),
options.delete(:path), options.delete(:p4path),
options.delete(:interactive)
raise "don't know how to handle '#{options.keys.first}'" if options.length > 0
@clientspec or raise 'P4 Clientspec not specified'
@port or raise 'P4 Port not specified'
@username or raise 'P4 username not specified'
@password or raise 'P4 password not specified'
@p4path or raise 'P4 depot path not specified'
end
def checkout(revision = nil, stdout = $stdout)
options = ""
options << "#{@p4path}@#{revision_number(revision)}" unless revision.nil?
# need to read from command output, because otherwise tests break
p4(:sync, options).each {|line| stdout.puts line.to_s }
end
def clean_checkout(revision = nil, stdout = $stdout)
FileUtils.rm_rf(path)
checkout(revision, stdout)
end
def latest_revision
build_revision_from(p4(:changes, "-m 1 #{@p4path}").first)
end
def last_locally_known_revision
return Revision.new(0) unless File.exist?(path)
Revision.new(info.revision)
end
def up_to_date?(reasons = [], revision_number = last_locally_known_revision.number)
result = true
latest_revision = self.latest_revision()
if latest_revision > Revision.new(revision_number)
reasons << "New revision #{latest_revision.number} detected"
reasons << revisions_since(revision_number)
result = false
end
return result
end
# SYNC_PATTERN = /^(\/\/.+#\d+) - (\w+) .+$/
def update(revision = nil)
checkout(revision)
# sync_output = p4(:sync, revision.nil? ? "" : "#{@path}@#{revision_number(revision)}")
# synced_files = Array.new
#
# sync_output.each do |line|
# match = SYNC_PATTERN.match(line['data'])
# if match
# file, operation = match[1..2]
# synced_files << ChangesetEntry.new(operation, file)
# end
# end.compact
#
# synced_files
end
private
# Execute a P4 command, and return an array of the resulting output lines
# The array will contain a hash for each line out output
def p4(operation, options = nil)
p4cmd = "p4 -R -p #{@port} -c #{@clientspec} -u #{@username} " + password_args
p4cmd << "#{operation.to_s}"
p4cmd << " " << options if options
p4_output = Array.new
# puts p4cmd
IO.popen(p4cmd, "rb") do |file|
while not file.eof
p4_output << Marshal.load(file)
end
end
p4_output
end
def password_args
(@password.blank?) ? "" : "-P #{@password} "
end
def info
change1 = p4(:changes, "-m 1 #{@p4path}#have").first
change2 = p4(:changes, "-m 1 #{@p4path}#head").first
Perforce::Info.new(change1['change'].to_i, change2['change'].to_i, change2['user'])
end
def build_revision_from(change)
return nil unless change
changeset = change['change'].to_i
# Build the array of changes
changed_files = p4(:describe, "-s #{changeset}").first
i = 0
changesets = []
while (changed_files["action#{i}"])
changesets << ChangesetEntry.new(changed_files["action#{i}"], changed_files["depotFile#{i}"])
i = i + 1
end
Revision.new(changeset, change['user'], Time.at(change['time'].to_i), change['desc'], changesets)
end
def revisions_since(revision_number)
p4(:changes, "-m #{MAX_CHANGELISTS_TO_FETCH} #{@p4path}@#{revision_number},#head").collect do |change|
build_revision_from(change)
end
end
def revision_number(revision)
revision.respond_to?(:number) ? revision.number : revision.to_i
end
Info = Struct.new :revision, :last_changed_revision, :last_changed_author
end