-
Notifications
You must be signed in to change notification settings - Fork 2
/
perforce.rb
101 lines (80 loc) · 3.35 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
require 'builder_error'
# Perforce source control implementation for CruiseControl.rb
# Written by Christopher Bailey, mailto:chris@cobaltedge.com
class Perforce
include CommandLine
attr_accessor :port, :client_spec, :username, :password, :path
MAX_CHANGELISTS_TO_FETCH = 25
def initialize(options = {})
@port, @clientspec, @username, @password, @path, @interactive =
options.delete(:port), options.delete(:clientspec),
options.delete(:user), options.delete(:password),
options.delete(:path), 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'
@path or raise 'P4 depot path not specified'
end
def checkout(target_directory, revision = nil)
# No need for target_directory with Perforce, since this is controlled by
# the clientspec.
options = ""
options << "#{@path}##{revision_number(revision)}" unless revision.nil?
# need to read from command output, because otherwise tests break
p4(:sync, options).each {|line| puts line.to_s }
end
def latest_revision(project)
# Get the latest changelist for this project
change = p4(:changes, "-m 1 #{@path}").first
# TODO: This isn't right - changesets I believe is supposed to be the set
# of files that were changed as part of this changelist.
changesets = [ ChangesetEntry.new(change['status'], change['desc']) ]
Revision.new(change['change'].to_i, change['user'], Time.at(change['time'].to_i), change['desc'], changesets)
end
def revisions_since(project, revision_number)
# This should get all changelists since the last one we used, but when using
# the -R flag with P4 it only seems to get the latest one.
changelists = p4(:changes, "-m #{MAX_CHANGELISTS_TO_FETCH} #{@path}@#{revision_number},#head")
changes = Array.new
changelists.each do |cl|
changeset = [ ChangesetEntry.new(cl['status'], cl['desc']) ]
changes << Revision.new(cl['change'].to_i, cl['user'], Time.at(cl['time'].to_i), cl['desc'], changeset)
end
changes.delete_if { |r| r.number == revision_number }
changes
end
SYNC_PATTERN = /^(\/\/.+#\d+) - (\w+) .+$/
def update(project, revision = nil)
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} -P #{@password} "
p4cmd << "#{operation.to_s}"
p4cmd << " " << options if options
p4_output = Array.new
IO.popen(p4cmd, "rb") do |file|
while not file.eof
p4_output << Marshal.load(file)
end
end
p4_output
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