rscm 0.2.1.1404 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README +34 -23
- data/Rakefile +24 -29
- data/bin/touch.exe +0 -0
- data/lib/rscm.rb +6 -3
- data/lib/rscm/annotations.rb +26 -7
- data/lib/rscm/{abstract_scm.rb → base.rb} +109 -71
- data/lib/rscm/better.rb +16 -0
- data/lib/rscm/logging.rb +11 -5
- data/lib/rscm/path_converter.rb +9 -16
- data/lib/rscm/revision.rb +201 -0
- data/lib/rscm/revision_file.rb +71 -0
- data/lib/rscm/scm/clearcase.rb +7 -7
- data/lib/rscm/scm/cvs.rb +69 -70
- data/lib/rscm/scm/cvs_log_parser.rb +29 -29
- data/lib/rscm/scm/darcs.rb +82 -34
- data/lib/rscm/scm/darcs_log_parser.rb +65 -0
- data/lib/rscm/scm/monotone.rb +249 -77
- data/lib/rscm/scm/monotone_log_parser.rb +57 -43
- data/lib/rscm/scm/mooky.rb +3 -3
- data/lib/rscm/scm/perforce.rb +196 -134
- data/lib/rscm/scm/star_team.rb +10 -10
- data/lib/rscm/scm/subversion.rb +106 -77
- data/lib/rscm/scm/subversion_log_parser.rb +76 -47
- data/lib/rscm/time_ext.rb +2 -116
- data/test/rscm/annotations_test.rb +15 -2
- data/test/rscm/{abstract_scm_test.rb → base_test.rb} +3 -3
- data/test/rscm/difftool_test.rb +9 -3
- data/test/rscm/generic_scm_tests.rb +195 -124
- data/test/rscm/revision_fixture.rb +20 -0
- data/test/rscm/revision_test.rb +129 -0
- data/test/rscm/{changesets.yaml → revisions.yaml} +10 -10
- data/test/rscm/scm/clearcase.log +608 -0
- data/test/rscm/scm/clearcase_test.rb +39 -0
- data/test/rscm/scm/cvs_log_parser_test.rb +73 -73
- data/test/rscm/scm/cvs_test.rb +1 -1
- data/test/rscm/scm/darcs_log_parser_test.rb +171 -0
- data/test/rscm/scm/monotone_log_parser_test.rb +49 -31
- data/test/rscm/scm/monotone_test.rb +3 -2
- data/test/rscm/scm/p4client_test.rb +33 -0
- data/test/rscm/scm/perforce_test.rb +25 -3
- data/test/rscm/scm/star_team.rb +9 -9
- data/test/rscm/scm/subversion_log_parser_test.rb +107 -47
- metadata +17 -13
- data/lib/multipart.rb +0 -95
- data/lib/rscm/RSS.txt +0 -41
- data/lib/rscm/changes.rb +0 -268
- data/lib/rscm/example.yaml +0 -21
- data/lib/rubyforge_file_publisher.rb +0 -176
- data/test/rscm/changes_fixture.rb +0 -20
- data/test/rscm/changes_test.rb +0 -129
@@ -6,49 +6,56 @@ module RSCM
|
|
6
6
|
|
7
7
|
class MonotoneLogParser
|
8
8
|
|
9
|
-
def
|
9
|
+
def parse_revisions(io, from_identifier=Time.epoch, to_identifier=Time.infinity)
|
10
10
|
# skip first separator
|
11
11
|
io.readline
|
12
12
|
|
13
|
-
|
14
|
-
|
13
|
+
all_revisions = []
|
14
|
+
revision_string = ""
|
15
15
|
|
16
16
|
# hash of path => [array of revisions]
|
17
17
|
path_revisions = {}
|
18
18
|
io.each_line do |line|
|
19
19
|
if(line =~ /-----------------------------------------------------------------/)
|
20
|
-
|
21
|
-
|
22
|
-
|
20
|
+
revision = parse_revision(StringIO.new(revision_string), path_revisions)
|
21
|
+
all_revisions << revision
|
22
|
+
revision_string = ""
|
23
23
|
else
|
24
|
-
|
24
|
+
revision_string << line
|
25
25
|
end
|
26
26
|
end
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
27
|
+
revision = parse_revision(StringIO.new(revision_string), path_revisions)
|
28
|
+
all_revisions << revision
|
29
|
+
|
30
|
+
# Filter out the revisions and set the previous revisions, knowing that most recent is at index 0.
|
31
|
+
|
32
|
+
from_time = time(all_revisions, from_identifier, Time.epoch)
|
33
|
+
to_time = time(all_revisions, to_identifier, Time.infinity)
|
34
|
+
|
35
|
+
revisions = Revisions.new
|
36
|
+
|
37
|
+
all_revisions.each do |revision|
|
38
|
+
if((from_time < revision.time) && (revision.time <= to_time))
|
39
|
+
revisions.add(revision)
|
40
|
+
revision.each do |change|
|
41
|
+
current_index = path_revisions[change.path].index(change.native_revision_identifier)
|
42
|
+
change.previous_native_revision_identifier = path_revisions[change.path][current_index + 1]
|
43
|
+
end
|
37
44
|
end
|
38
45
|
end
|
39
|
-
|
40
|
-
end
|
41
|
-
|
42
|
-
def
|
43
|
-
|
46
|
+
revisions
|
47
|
+
end
|
48
|
+
|
49
|
+
def parse_revision(revision_io, path_revisions)
|
50
|
+
revision = Revision.new
|
44
51
|
state = nil
|
45
|
-
|
46
|
-
if(line =~ /^Revision: (.*)$/ &&
|
47
|
-
|
48
|
-
elsif(line =~ /^Author: (.*)$/ &&
|
49
|
-
|
50
|
-
elsif(line =~ /^Date: (.*)$/ &&
|
51
|
-
|
52
|
+
revision_io.each_line do |line|
|
53
|
+
if(line =~ /^Revision: (.*)$/ && revision.identifier.nil?)
|
54
|
+
revision.identifier = $1
|
55
|
+
elsif(line =~ /^Author: (.*)$/ && revision.developer.nil?)
|
56
|
+
revision.developer = $1
|
57
|
+
elsif(line =~ /^Date: (.*)$/ && revision.time.nil?)
|
58
|
+
revision.time = Time.utc(
|
52
59
|
$1[0..3].to_i,
|
53
60
|
$1[5..6].to_i,
|
54
61
|
$1[8..9].to_i,
|
@@ -56,37 +63,44 @@ module RSCM
|
|
56
63
|
$1[14..15].to_i,
|
57
64
|
$1[17..18].to_i
|
58
65
|
)
|
59
|
-
elsif(line =~ /^ChangeLog
|
66
|
+
elsif(line =~ /^ChangeLog:\s*$/ && revision.message.nil?)
|
60
67
|
state = :message
|
61
|
-
elsif(state == :message &&
|
62
|
-
|
63
|
-
elsif(state == :message &&
|
64
|
-
|
65
|
-
elsif(line =~ /^Added files
|
68
|
+
elsif(state == :message && revision.message.nil?)
|
69
|
+
revision.message = ""
|
70
|
+
elsif(state == :message && revision.message)
|
71
|
+
revision.message << line
|
72
|
+
elsif(line =~ /^Added files:\s*$/)
|
66
73
|
state = :added
|
67
74
|
elsif(state == :added)
|
68
|
-
add_changes(
|
69
|
-
elsif(line =~ /^Modified files
|
75
|
+
add_changes(revision, line, RevisionFile::ADDED, path_revisions)
|
76
|
+
elsif(line =~ /^Modified files:\s*$/)
|
70
77
|
state = :modified
|
71
78
|
elsif(state == :modified)
|
72
|
-
add_changes(
|
79
|
+
add_changes(revision, line, RevisionFile::MODIFIED, path_revisions)
|
73
80
|
end
|
74
81
|
end
|
75
|
-
|
76
|
-
|
82
|
+
revision.message.chomp! rescue revision.message = ''
|
83
|
+
revision
|
77
84
|
end
|
78
85
|
|
79
86
|
private
|
80
87
|
|
81
|
-
def
|
88
|
+
def time(revisions, identifier, default)
|
89
|
+
cs = revisions.find do |revision|
|
90
|
+
revision.identifier == identifier
|
91
|
+
end
|
92
|
+
cs ? cs.time : (identifier.is_a?(Time) ? identifier : default)
|
93
|
+
end
|
94
|
+
|
95
|
+
def add_changes(revision, line, state, path_revisions)
|
82
96
|
paths = line.split(" ")
|
83
97
|
paths.each do |path|
|
84
|
-
|
98
|
+
revision << RevisionFile.new(path, state, revision.developer, nil, revision.identifier, revision.time)
|
85
99
|
|
86
100
|
# now record path revisions so we can keep track of previous rev for each path
|
87
101
|
# doesn't work for moved files, and have no idea how to make it work either.
|
88
102
|
path_revisions[path] ||= []
|
89
|
-
path_revisions[path] <<
|
103
|
+
path_revisions[path] << revision.identifier
|
90
104
|
end
|
91
105
|
|
92
106
|
end
|
data/lib/rscm/scm/mooky.rb
CHANGED
data/lib/rscm/scm/perforce.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
require 'rscm/
|
1
|
+
require 'rscm/base'
|
2
2
|
require 'rscm/path_converter'
|
3
3
|
require 'rscm/line_editor'
|
4
4
|
|
@@ -9,26 +9,64 @@ require 'parsedate'
|
|
9
9
|
require 'stringio'
|
10
10
|
|
11
11
|
module RSCM
|
12
|
-
# RSCM implementation
|
12
|
+
# Perforce RSCM implementation.
|
13
13
|
#
|
14
14
|
# Understands operations against multiple client-workspaces
|
15
15
|
# You need the p4/p4d executable on the PATH in order for it to work.
|
16
16
|
#
|
17
|
-
class Perforce <
|
17
|
+
class Perforce < Base
|
18
18
|
register self
|
19
19
|
|
20
20
|
include FileUtils
|
21
21
|
|
22
|
-
|
23
|
-
|
22
|
+
@@counter = 0
|
23
|
+
|
24
|
+
ann :description => "P4CLIENT: workspace name"
|
25
|
+
attr_accessor :client_name
|
26
|
+
|
27
|
+
ann :description => "P4PORT: [host:port]", :tip => "perforce server address e.g. 10.12.1.55:1666"
|
28
|
+
attr_accessor :port
|
29
|
+
|
30
|
+
ann :description => "P4USER", :tip => "username"
|
31
|
+
attr_accessor :user
|
32
|
+
|
33
|
+
ann :description => "P4PASSWD", :tip => "password"
|
34
|
+
attr_accessor :pwd
|
35
|
+
|
36
|
+
attr_accessor :repository_root_dir
|
24
37
|
|
25
|
-
def initialize(
|
26
|
-
@
|
27
|
-
@depotpath = repository_root_dir
|
38
|
+
def initialize(port = "1666", user = ENV["LOGNAME"], pwd = "", client_name = Perforce.next_client_name)
|
39
|
+
@port, @user, @pwd, @client_name = port, user, pwd, client_name
|
28
40
|
end
|
29
41
|
|
30
|
-
def
|
31
|
-
|
42
|
+
def p4admin
|
43
|
+
@p4admin ||= P4Admin.new(@port, @user, @pwd)
|
44
|
+
end
|
45
|
+
|
46
|
+
def p4client
|
47
|
+
@p4client ||= p4admin.create_client(@checkout_dir, @client_name)
|
48
|
+
end
|
49
|
+
|
50
|
+
def can_create_central?
|
51
|
+
true
|
52
|
+
end
|
53
|
+
|
54
|
+
def create_central
|
55
|
+
raise "perforce depot can be created only from tests" unless @repository_root_dir
|
56
|
+
@p4d = P4Daemon.new(@repository_root_dir)
|
57
|
+
@p4d.start
|
58
|
+
end
|
59
|
+
|
60
|
+
def destroy_central
|
61
|
+
@p4d.shutdown
|
62
|
+
end
|
63
|
+
|
64
|
+
def central_exists?
|
65
|
+
p4admin.central_exists?
|
66
|
+
end
|
67
|
+
|
68
|
+
def can_create_central?
|
69
|
+
true
|
32
70
|
end
|
33
71
|
|
34
72
|
def name
|
@@ -39,35 +77,35 @@ module RSCM
|
|
39
77
|
true
|
40
78
|
end
|
41
79
|
|
42
|
-
def
|
80
|
+
def import_central(dir, comment)
|
43
81
|
with_create_client(dir) do |client|
|
44
82
|
client.add_all(list_files)
|
45
83
|
client.submit(comment)
|
46
84
|
end
|
47
85
|
end
|
48
86
|
|
49
|
-
def checkout(
|
50
|
-
|
87
|
+
def checkout(to_identifier = nil, &proc)
|
88
|
+
p4client.checkout(to_identifier, &proc)
|
51
89
|
end
|
52
90
|
|
53
|
-
def add(
|
54
|
-
|
91
|
+
def add(relative_filename)
|
92
|
+
p4client.add(relative_filename)
|
55
93
|
end
|
56
94
|
|
57
|
-
def commit(
|
58
|
-
|
95
|
+
def commit(message, &proc)
|
96
|
+
p4client.submit(message, &proc)
|
59
97
|
end
|
60
98
|
|
61
|
-
def
|
62
|
-
|
99
|
+
def revisions(from_identifier, to_identifier=Time.infinity)
|
100
|
+
p4client.revisions(from_identifier, to_identifier)
|
63
101
|
end
|
64
102
|
|
65
|
-
def uptodate?(
|
66
|
-
|
103
|
+
def uptodate?(from_identifier)
|
104
|
+
p4client.uptodate?
|
67
105
|
end
|
68
106
|
|
69
107
|
def edit(file)
|
70
|
-
|
108
|
+
p4client.edit(file)
|
71
109
|
end
|
72
110
|
|
73
111
|
def trigger_installed?(trigger_command, trigger_files_checkout_dir)
|
@@ -82,25 +120,18 @@ module RSCM
|
|
82
120
|
p4admin.uninstall_trigger(trigger_command)
|
83
121
|
end
|
84
122
|
|
85
|
-
|
86
|
-
|
87
|
-
def p4admin
|
88
|
-
@p4admin ||= P4Admin.new
|
123
|
+
def diff(revfile, &proc)
|
124
|
+
p4client.diff(revfile, &proc)
|
89
125
|
end
|
90
126
|
|
91
|
-
|
92
|
-
@clients.values.find {|client| client.contains?(path)}
|
93
|
-
end
|
94
|
-
|
95
|
-
def client(rootdir)
|
96
|
-
@clients[rootdir] ||= create_client(rootdir)
|
97
|
-
end
|
127
|
+
private
|
98
128
|
|
99
129
|
def with_create_client(rootdir)
|
100
130
|
raise "needs a block" unless block_given?
|
101
131
|
rootdir = File.expand_path(rootdir)
|
102
132
|
with_working_dir(rootdir) do
|
103
|
-
|
133
|
+
mkdir_p(rootdir)
|
134
|
+
client = p4admin.create_client(rootdir, Perforce.next_client_name)
|
104
135
|
begin
|
105
136
|
yield client
|
106
137
|
ensure
|
@@ -109,70 +140,43 @@ module RSCM
|
|
109
140
|
end
|
110
141
|
end
|
111
142
|
|
112
|
-
def
|
113
|
-
|
143
|
+
def self.next_client_name
|
144
|
+
"temp_client_#{@@counter += 1}"
|
114
145
|
end
|
115
146
|
|
116
|
-
def
|
117
|
-
|
118
|
-
mkdir_p(rootdir)
|
119
|
-
p4admin.create_client(rootdir)
|
147
|
+
def delete_client(client)
|
148
|
+
p4admin.delete_client(client)
|
120
149
|
end
|
121
150
|
|
122
151
|
def list_files
|
123
152
|
files = Dir["**/*"].delete_if{|f| File.directory?(f)}
|
124
153
|
files.collect{|f| File.expand_path(f)}
|
125
154
|
end
|
155
|
+
end
|
126
156
|
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
def initialize(depotpath)
|
131
|
-
@depotpath = depotpath
|
132
|
-
end
|
133
|
-
|
134
|
-
def start
|
135
|
-
shutdown if running?
|
136
|
-
launch
|
137
|
-
assert_running
|
138
|
-
end
|
139
|
-
|
140
|
-
def assert_running
|
141
|
-
raise "p4d did not start properly" if timeout(10) { running? }
|
142
|
-
end
|
143
|
-
|
144
|
-
def launch
|
145
|
-
fork do
|
146
|
-
mkdir_p(@depotpath)
|
147
|
-
cd(@depotpath)
|
148
|
-
debug "starting p4 server"
|
149
|
-
exec("p4d")
|
150
|
-
end
|
151
|
-
at_exit { shutdown }
|
152
|
-
end
|
157
|
+
# Understands p4 administrative operations (not specific to a client)
|
158
|
+
class P4Admin
|
153
159
|
|
154
|
-
|
155
|
-
|
156
|
-
|
160
|
+
def initialize(port, user, pwd)
|
161
|
+
@port, @user, @pwd = port, user, pwd
|
162
|
+
end
|
157
163
|
|
158
|
-
|
159
|
-
|
164
|
+
def create_client(rootdir, clientname)
|
165
|
+
rootdir = File.expand_path(rootdir) if rootdir =~ /\.\./
|
166
|
+
unless client_exists?(rootdir, clientname)
|
167
|
+
execute_popen("client -i", "w+", clientspec(clientname, rootdir))
|
160
168
|
end
|
169
|
+
P4Client.new(rootdir, clientname, @port, @user, @pwd)
|
161
170
|
end
|
162
|
-
end
|
163
|
-
|
164
|
-
# Understands p4 administrative operations (not specific to a client)
|
165
|
-
class P4Admin
|
166
|
-
@@counter = 0
|
167
171
|
|
168
|
-
def
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
+
def client_exists?(rootdir, clientname)
|
173
|
+
dir_regex = Regexp.new(rootdir)
|
174
|
+
name_regex = Regexp.new(clientname)
|
175
|
+
execute("clients").split("\n").find {|c| c =~ dir_regex && c =~ name_regex}
|
172
176
|
end
|
173
177
|
|
174
|
-
def delete_client(
|
175
|
-
execute("client -d #{name}")
|
178
|
+
def delete_client(client)
|
179
|
+
execute("client -d #{client.name}")
|
176
180
|
end
|
177
181
|
|
178
182
|
def trigger_installed?(trigger_command)
|
@@ -180,22 +184,26 @@ module RSCM
|
|
180
184
|
end
|
181
185
|
|
182
186
|
def install_trigger(trigger_command)
|
183
|
-
|
187
|
+
execute_popen("triggers -i", "a+", triggerspec_append(trigger_command))
|
184
188
|
end
|
185
189
|
|
186
190
|
def uninstall_trigger(trigger_command)
|
187
|
-
|
191
|
+
execute_popen("triggers -i", "a+", triggerspec_remove(trigger_command))
|
188
192
|
end
|
189
193
|
|
190
|
-
def
|
194
|
+
def triggerspec_append(trigger_command)
|
191
195
|
new_trigger = " damagecontrol commit //depot/... \"#{trigger_command}\" "
|
192
196
|
triggers + $/ + new_trigger
|
193
197
|
end
|
194
198
|
|
195
|
-
def
|
199
|
+
def triggerspec_remove(trigger_command)
|
196
200
|
triggers.reject {|line| line =~ /#{trigger_command}/}.join
|
197
201
|
end
|
198
202
|
|
203
|
+
def central_exists?
|
204
|
+
execute("info").split.join(" ") !~ /Connect to server failed/
|
205
|
+
end
|
206
|
+
|
199
207
|
def clientspec(name, rootdir)
|
200
208
|
s = StringIO.new
|
201
209
|
s.puts "Client: #{name}"
|
@@ -213,8 +221,8 @@ module RSCM
|
|
213
221
|
execute("triggers -o")
|
214
222
|
end
|
215
223
|
|
216
|
-
def
|
217
|
-
IO.popen(
|
224
|
+
def execute_popen(cmd, mode, input)
|
225
|
+
IO.popen(format_cmd(cmd), mode) do |io|
|
218
226
|
io.puts(input)
|
219
227
|
io.close_write
|
220
228
|
io.each_line {|line| debug(line)}
|
@@ -222,41 +230,38 @@ module RSCM
|
|
222
230
|
end
|
223
231
|
|
224
232
|
def execute(cmd)
|
225
|
-
cmd =
|
226
|
-
puts "> executing: #{cmd}"
|
233
|
+
cmd = format_cmd(cmd)
|
234
|
+
$stderr.puts "> executing: #{cmd}"
|
227
235
|
`#{cmd}`
|
228
236
|
end
|
229
237
|
|
230
|
-
def
|
231
|
-
"
|
238
|
+
def format_cmd(cmd)
|
239
|
+
"p4 -p #{@port} -u '#{@user}' -P '#{@pwd}' #{cmd} 2>&1"
|
232
240
|
end
|
233
241
|
end
|
234
242
|
|
235
243
|
# Understands operations against a client-workspace
|
236
244
|
class P4Client
|
237
245
|
DATE_FORMAT = "%Y/%m/%d:%H:%M:%S"
|
238
|
-
STATUS = { "add" =>
|
239
|
-
PERFORCE_EPOCH = Time.utc(1970, 1, 1, 6, 0, 1) #perforce doesn't like Time.utc(1970)
|
240
|
-
|
241
|
-
attr_accessor :name, :rootdir
|
242
|
-
|
243
|
-
def initialize(name, rootdir)
|
244
|
-
@name = name
|
245
|
-
@rootdir = rootdir
|
246
|
-
end
|
246
|
+
STATUS = { "add" => RevisionFile::ADDED, "edit" => RevisionFile::MODIFIED, "delete" => RevisionFile::DELETED }
|
247
247
|
|
248
|
-
def
|
249
|
-
|
250
|
-
file =~ /^#{@rootdir}/
|
248
|
+
def initialize(checkout_dir, name, port, user, pwd)
|
249
|
+
@checkout_dir, @name, @port, @user, @pwd = checkout_dir, name, port, user, pwd
|
251
250
|
end
|
252
251
|
|
253
252
|
def uptodate?
|
254
253
|
p4("sync -n").empty?
|
255
254
|
end
|
256
255
|
|
257
|
-
def
|
258
|
-
|
259
|
-
|
256
|
+
def revisions(from_identifier, to_identifier)
|
257
|
+
revisions = changelists(from_identifier, to_identifier).collect {|changelist| to_revision(changelist)}
|
258
|
+
# We have to reverse the revisions in order to make them appear in chronological order,
|
259
|
+
# P4 lists the newest ones first.
|
260
|
+
Revisions.new(revisions).reverse
|
261
|
+
end
|
262
|
+
|
263
|
+
def name
|
264
|
+
@name
|
260
265
|
end
|
261
266
|
|
262
267
|
def edit(file)
|
@@ -265,7 +270,7 @@ module RSCM
|
|
265
270
|
end
|
266
271
|
|
267
272
|
def add(relative_path)
|
268
|
-
add_file(
|
273
|
+
add_file(rootdir + "/" + relative_path)
|
269
274
|
end
|
270
275
|
|
271
276
|
def add_all(files)
|
@@ -284,8 +289,8 @@ module RSCM
|
|
284
289
|
cmd = to_identifier.nil? ? "sync" : "sync //...@#{to_identifier}"
|
285
290
|
checked_out_files = []
|
286
291
|
p4(cmd).collect do |output|
|
287
|
-
puts "output: '#{output}'"
|
288
|
-
if(output =~ /.* - (added as|updating|deleted as) #{
|
292
|
+
#puts "output: '#{output}'"
|
293
|
+
if(output =~ /.* - (added as|updating|deleted as) #{rootdir}[\/|\\](.*)/)
|
289
294
|
path = $2.gsub(/\\/, "/")
|
290
295
|
checked_out_files << path
|
291
296
|
yield path if block_given?
|
@@ -294,8 +299,26 @@ module RSCM
|
|
294
299
|
checked_out_files
|
295
300
|
end
|
296
301
|
|
302
|
+
def diff(r)
|
303
|
+
path = File.expand_path(@checkout_dir + "/" + r.path)
|
304
|
+
from = r.previous_native_revision_identifier
|
305
|
+
to = r.native_revision_identifier
|
306
|
+
cmd = p4cmd("diff2 -du #{path}@#{from} #{path}@#{to}")
|
307
|
+
Better.popen(cmd) do |io|
|
308
|
+
return(yield(io))
|
309
|
+
end
|
310
|
+
end
|
311
|
+
|
297
312
|
private
|
298
313
|
|
314
|
+
def rootdir
|
315
|
+
unless @rootdir
|
316
|
+
p4("info") =~ /Client root: (.+)/
|
317
|
+
@rootdir = $1
|
318
|
+
end
|
319
|
+
@rootdir
|
320
|
+
end
|
321
|
+
|
299
322
|
def add_file(absolute_path)
|
300
323
|
absolute_path = PathConverter.filepath_to_nativepath(absolute_path, true)
|
301
324
|
p4("add #{absolute_path}")
|
@@ -310,48 +333,53 @@ module RSCM
|
|
310
333
|
end
|
311
334
|
end
|
312
335
|
|
313
|
-
def
|
336
|
+
def to_revision(changelist)
|
314
337
|
return nil if changelist.nil? # Ugly, but it seems to be nil some times on windows.
|
315
338
|
changes = changelist.files.collect do |filespec|
|
316
|
-
change =
|
339
|
+
change = RevisionFile.new(filespec.path, changelist.developer, changelist.message, filespec.revision, changelist.time)
|
317
340
|
change.status = STATUS[filespec.status]
|
318
|
-
change.
|
341
|
+
change.previous_native_revision_identifier = filespec.revision - 1
|
319
342
|
change
|
320
343
|
end
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
344
|
+
revision = Revision.new(changes)
|
345
|
+
revision.identifier = changelist.number
|
346
|
+
revision.developer = changelist.developer
|
347
|
+
revision.message = changelist.message
|
348
|
+
revision.time = changelist.time
|
349
|
+
revision
|
327
350
|
end
|
328
351
|
|
329
|
-
def
|
330
|
-
|
352
|
+
def p4changes(from_identifier, to_identifier)
|
353
|
+
from = p4timespec(from_identifier, Time.epoch)
|
354
|
+
to = p4timespec(to_identifier, Time.infinity)
|
355
|
+
$stderr.puts "in p4changes translated #{from_identifier},#{to_identifier} to #{from},#{to}"
|
356
|
+
p4("changes //...@#{from},#{to}")
|
331
357
|
end
|
332
358
|
|
333
|
-
def
|
334
|
-
if
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
to = to_identifier.strftime(DATE_FORMAT)
|
339
|
-
p4("changes //...@#{from},#{to}")
|
359
|
+
def p4timespec(identifier, default)
|
360
|
+
identifier = default if identifier.nil?
|
361
|
+
if identifier.is_a?(Time)
|
362
|
+
identifier = Time.epoch if identifier < Time.epoch
|
363
|
+
(identifier+1).strftime(DATE_FORMAT)
|
340
364
|
else
|
341
|
-
|
365
|
+
"#{identifier + 1}"
|
342
366
|
end
|
343
367
|
end
|
344
368
|
|
369
|
+
def p4describe(chnum)
|
370
|
+
p4("describe -s #{chnum}")
|
371
|
+
end
|
372
|
+
|
345
373
|
def p4(cmd)
|
346
374
|
cmd = "#{p4cmd(cmd)}"
|
347
|
-
puts "> executing: #{cmd}"
|
375
|
+
$stderr.puts "> executing: #{cmd}"
|
348
376
|
output = `#{cmd}`
|
349
|
-
puts output
|
377
|
+
#puts output
|
350
378
|
output
|
351
379
|
end
|
352
380
|
|
353
381
|
def p4cmd(cmd)
|
354
|
-
|
382
|
+
"p4 -p #{@port} -c '#{@name}' -u '#{@user}' -P '#{@pwd}' #{cmd}"
|
355
383
|
end
|
356
384
|
|
357
385
|
def submitspec(comment)
|
@@ -377,7 +405,7 @@ module RSCM
|
|
377
405
|
def initialize(log)
|
378
406
|
debug log
|
379
407
|
if(log =~ /^Change (\d+) by (.*) on (.*)$/)
|
380
|
-
|
408
|
+
#@number, @developer, @time = $1.to_i, $2, Time.utc(*ParseDate.parsedate($3)[0..5])
|
381
409
|
@number, @developer, @time = $1.to_i, $2, Time.utc(*ParseDate.parsedate($3))
|
382
410
|
else
|
383
411
|
raise "Bad log format: '#{log}'"
|
@@ -397,6 +425,40 @@ module RSCM
|
|
397
425
|
end
|
398
426
|
end
|
399
427
|
|
428
|
+
class P4Daemon
|
429
|
+
include FileUtils
|
430
|
+
|
431
|
+
def initialize(depotpath)
|
432
|
+
@depotpath = depotpath
|
433
|
+
end
|
434
|
+
|
435
|
+
def start
|
436
|
+
launch
|
437
|
+
assert_running
|
438
|
+
end
|
439
|
+
|
440
|
+
def assert_running
|
441
|
+
raise "p4d did not start properly" if timeout(10) { running? }
|
442
|
+
end
|
443
|
+
|
444
|
+
def launch
|
445
|
+
fork do
|
446
|
+
mkdir_p(@depotpath)
|
447
|
+
cd(@depotpath)
|
448
|
+
debug "starting p4 server"
|
449
|
+
exec("p4d")
|
450
|
+
end
|
451
|
+
at_exit { shutdown }
|
452
|
+
end
|
453
|
+
|
454
|
+
def shutdown
|
455
|
+
`p4 -p 1666 admin stop` if running?
|
456
|
+
end
|
457
|
+
|
458
|
+
def running?
|
459
|
+
`p4 -p 1666 info 2>&1`!~ /Connect to server failed/
|
460
|
+
end
|
461
|
+
end
|
400
462
|
end
|
401
463
|
|
402
464
|
module Kernel
|
@@ -412,7 +474,7 @@ module Kernel
|
|
412
474
|
|
413
475
|
#todo: replace with logger
|
414
476
|
def debug(msg)
|
415
|
-
puts msg
|
477
|
+
#puts msg
|
416
478
|
end
|
417
479
|
|
418
480
|
end
|