scm 0.1.0.pre1
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/.document +3 -0
- data/.gitignore +2 -0
- data/.rspec +1 -0
- data/.yardopts +1 -0
- data/ChangeLog.md +4 -0
- data/LICENSE.txt +20 -0
- data/README.md +46 -0
- data/Rakefile +40 -0
- data/gemspec.yml +16 -0
- data/lib/scm/commits/commit.rb +64 -0
- data/lib/scm/commits/git.rb +62 -0
- data/lib/scm/commits/hg.rb +69 -0
- data/lib/scm/commits/svn.rb +12 -0
- data/lib/scm/git.rb +500 -0
- data/lib/scm/hg.rb +469 -0
- data/lib/scm/repository.rb +355 -0
- data/lib/scm/scm.rb +36 -0
- data/lib/scm/svn.rb +497 -0
- data/lib/scm/util.rb +65 -0
- data/lib/scm/version.rb +4 -0
- data/lib/scm.rb +4 -0
- data/scm.gemspec +131 -0
- data/spec/git_spec.rb +26 -0
- data/spec/helpers/scm.rb +19 -0
- data/spec/scm_spec.rb +8 -0
- data/spec/spec_helper.rb +13 -0
- metadata +107 -0
data/lib/scm/hg.rb
ADDED
@@ -0,0 +1,469 @@
|
|
1
|
+
require 'scm/repository'
|
2
|
+
require 'scm/commits/hg'
|
3
|
+
|
4
|
+
require 'uri'
|
5
|
+
|
6
|
+
module SCM
|
7
|
+
#
|
8
|
+
# Interacts with Mercurial (Hg) repositories.
|
9
|
+
#
|
10
|
+
class Hg < Repository
|
11
|
+
|
12
|
+
# Hg status codes
|
13
|
+
STATUSES = {
|
14
|
+
'M' => :modified,
|
15
|
+
'A' => :added,
|
16
|
+
'R' => :removed,
|
17
|
+
'C' => :clean,
|
18
|
+
'!' => :missing,
|
19
|
+
'?' => :untracked,
|
20
|
+
'I' => :ignored,
|
21
|
+
' ' => :origin
|
22
|
+
}
|
23
|
+
|
24
|
+
#
|
25
|
+
# Creates a Hg repository.
|
26
|
+
#
|
27
|
+
# @param [String] path
|
28
|
+
# The path to the repository.
|
29
|
+
#
|
30
|
+
# @return [Hg, URI::Generic]
|
31
|
+
# The initialized local Hg repository or the URI to the remote
|
32
|
+
# repository.
|
33
|
+
#
|
34
|
+
# @raise [RuntimeError]
|
35
|
+
# Could not initialize the Hg repository.
|
36
|
+
#
|
37
|
+
def self.create(path,options={})
|
38
|
+
unless path.start_with?('ssh://')
|
39
|
+
FileUtils.mkdir_p(path)
|
40
|
+
end
|
41
|
+
|
42
|
+
unless (result = system('hg','init',path))
|
43
|
+
raise("unable to initialize Hg repository #{path.dump}")
|
44
|
+
end
|
45
|
+
|
46
|
+
if path.start_with?('ssh://')
|
47
|
+
return URI(path)
|
48
|
+
else
|
49
|
+
return new(path)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
#
|
54
|
+
# Clones a remote Hg repository.
|
55
|
+
#
|
56
|
+
# @param [URI, String] uri
|
57
|
+
# The URI of the remote repository.
|
58
|
+
#
|
59
|
+
# @param [Hash] options
|
60
|
+
# Additional options.
|
61
|
+
#
|
62
|
+
# @option options [String, Integer] :commits
|
63
|
+
# The commits to include.
|
64
|
+
#
|
65
|
+
# @option options [String, Symbol] :branch
|
66
|
+
# The branch to specifically clone.
|
67
|
+
#
|
68
|
+
# @option options [String] :dest
|
69
|
+
# The destination directory to clone into.
|
70
|
+
#
|
71
|
+
# @return [Boolean]
|
72
|
+
# Specifies whether the clone was successful.
|
73
|
+
#
|
74
|
+
def self.clone(uri,options={})
|
75
|
+
arguments = []
|
76
|
+
|
77
|
+
if options[:commits]
|
78
|
+
arguments << '--rev' << options[:commits]
|
79
|
+
end
|
80
|
+
|
81
|
+
if options[:branch]
|
82
|
+
arguments << '--branch' << options[:branch]
|
83
|
+
end
|
84
|
+
|
85
|
+
arguments << uri
|
86
|
+
arguments << options[:dest] if options[:dest]
|
87
|
+
|
88
|
+
system('hg','clone',*arguments)
|
89
|
+
end
|
90
|
+
|
91
|
+
#
|
92
|
+
# Queries the status of the repository.
|
93
|
+
#
|
94
|
+
# @param [Array] paths
|
95
|
+
# Optional paths to query the statuses of.
|
96
|
+
#
|
97
|
+
# @return [Hash{String => Symbol}]
|
98
|
+
# The paths and their repsective statuses.
|
99
|
+
#
|
100
|
+
def status(*paths)
|
101
|
+
statuses = {}
|
102
|
+
|
103
|
+
popen('hg status',*paths) do |line|
|
104
|
+
status, path = line.split(' ',2)
|
105
|
+
|
106
|
+
statuses[path] = STATUSES[status]
|
107
|
+
end
|
108
|
+
|
109
|
+
return statuses
|
110
|
+
end
|
111
|
+
|
112
|
+
#
|
113
|
+
# Adds paths to the repository.
|
114
|
+
#
|
115
|
+
# @param [Array] paths
|
116
|
+
# The paths to add to the repository.
|
117
|
+
#
|
118
|
+
def add(*paths)
|
119
|
+
hg(:add,*paths)
|
120
|
+
end
|
121
|
+
|
122
|
+
#
|
123
|
+
# Moves a file or directory.
|
124
|
+
#
|
125
|
+
# @param [String] source
|
126
|
+
# The path of the source file/directory.
|
127
|
+
#
|
128
|
+
# @param [String] dest
|
129
|
+
# The new destination path.
|
130
|
+
#
|
131
|
+
# @param [Boolean] force
|
132
|
+
# Specifies whether to force the move.
|
133
|
+
#
|
134
|
+
def move(source,dest,force=false)
|
135
|
+
arguments = []
|
136
|
+
|
137
|
+
arguments << '--force' if force
|
138
|
+
arguments << source << dest
|
139
|
+
|
140
|
+
svn(:mv,*arguments)
|
141
|
+
end
|
142
|
+
|
143
|
+
#
|
144
|
+
# Removes files or directories.
|
145
|
+
#
|
146
|
+
# @param [String, Array] paths
|
147
|
+
# The path(s) to remove.
|
148
|
+
#
|
149
|
+
# @param [Hash] options
|
150
|
+
# Additional options.
|
151
|
+
#
|
152
|
+
# @option options [Boolean] :force (false)
|
153
|
+
# Specifies whether to forcibly remove the files/directories.
|
154
|
+
#
|
155
|
+
# @note
|
156
|
+
# {#remove} does not respond to the `:recursive` option.
|
157
|
+
# Hg removes directories recursively by default.
|
158
|
+
#
|
159
|
+
def remove(paths,options={})
|
160
|
+
arguments = []
|
161
|
+
|
162
|
+
arguments << '--force' if options[:force]
|
163
|
+
arguments += ['--', *paths]
|
164
|
+
|
165
|
+
hg(:rm,*arguments)
|
166
|
+
end
|
167
|
+
|
168
|
+
#
|
169
|
+
# Makes a Hg commit.
|
170
|
+
#
|
171
|
+
# @param [String] message
|
172
|
+
# The message for the commit.
|
173
|
+
#
|
174
|
+
# @param [Hash] options
|
175
|
+
# Commit options.
|
176
|
+
#
|
177
|
+
# @option options [String] :paths
|
178
|
+
# The path of the file to commit.
|
179
|
+
#
|
180
|
+
# @return [Boolean]
|
181
|
+
# Specifies whether the commit was successfully made.
|
182
|
+
#
|
183
|
+
def commit(message=nil,options={})
|
184
|
+
arguments = []
|
185
|
+
|
186
|
+
if message
|
187
|
+
arguments << '-m' << message
|
188
|
+
end
|
189
|
+
|
190
|
+
if options[:paths]
|
191
|
+
arguments += [*options[:paths]]
|
192
|
+
end
|
193
|
+
|
194
|
+
hg(:commit,*arguments)
|
195
|
+
end
|
196
|
+
|
197
|
+
#
|
198
|
+
# Lists branches in the SVN repository.
|
199
|
+
#
|
200
|
+
# @return [Array<String>]
|
201
|
+
# The branch names.
|
202
|
+
#
|
203
|
+
def branches
|
204
|
+
branches = []
|
205
|
+
|
206
|
+
popen('hg branches') do |line|
|
207
|
+
branches << line[2..-1]
|
208
|
+
end
|
209
|
+
|
210
|
+
return branches
|
211
|
+
end
|
212
|
+
|
213
|
+
#
|
214
|
+
# The current branch.
|
215
|
+
#
|
216
|
+
# @return [String]
|
217
|
+
# The name of the current branch.
|
218
|
+
#
|
219
|
+
def branch
|
220
|
+
popen('hg branch').chomp
|
221
|
+
end
|
222
|
+
|
223
|
+
#
|
224
|
+
# Swtiches to another Hg branch.
|
225
|
+
#
|
226
|
+
# @param [String, Symbol] name
|
227
|
+
# The name of the branch to switch to.
|
228
|
+
#
|
229
|
+
# @return [Boolean]
|
230
|
+
# Specifies whether the branch was successfully switched.
|
231
|
+
#
|
232
|
+
def switch_branch(name)
|
233
|
+
hg(:update,name)
|
234
|
+
end
|
235
|
+
|
236
|
+
#
|
237
|
+
# Deletes a branch.
|
238
|
+
#
|
239
|
+
# @param [String] name
|
240
|
+
# The name of the branch to delete.
|
241
|
+
#
|
242
|
+
# @return [Boolean]
|
243
|
+
# Specifies whether the branch was successfully deleted.
|
244
|
+
#
|
245
|
+
def delete_branch(name)
|
246
|
+
hg(:commit,'--close-branch','-m',"Closing #{name}")
|
247
|
+
end
|
248
|
+
|
249
|
+
#
|
250
|
+
# Lists Hg tags.
|
251
|
+
#
|
252
|
+
# @return [Array<String>]
|
253
|
+
# The tag names.
|
254
|
+
#
|
255
|
+
def tags
|
256
|
+
tags = []
|
257
|
+
|
258
|
+
popen('hg tags') do |line|
|
259
|
+
tags << line[2..-1]
|
260
|
+
end
|
261
|
+
|
262
|
+
return tags
|
263
|
+
end
|
264
|
+
|
265
|
+
#
|
266
|
+
# Creates a Hg tag.
|
267
|
+
#
|
268
|
+
# @param [String] name
|
269
|
+
# The name for the tag.
|
270
|
+
#
|
271
|
+
# @param [String] commit
|
272
|
+
# The commit to create the tag at.
|
273
|
+
#
|
274
|
+
# @return [Boolean]
|
275
|
+
# Specifies whether the tag was successfully created.
|
276
|
+
#
|
277
|
+
def tag(name,commit=nil)
|
278
|
+
arguments = []
|
279
|
+
|
280
|
+
if commit
|
281
|
+
arguments << '-r' << commit
|
282
|
+
end
|
283
|
+
|
284
|
+
hg(:tag,name,*arguments)
|
285
|
+
end
|
286
|
+
|
287
|
+
#
|
288
|
+
# Deletes a Hg tag.
|
289
|
+
#
|
290
|
+
# @param [String] name
|
291
|
+
# The name of the tag.
|
292
|
+
#
|
293
|
+
# @return [Boolean]
|
294
|
+
# Specifies whether the tag was successfully deleted.
|
295
|
+
#
|
296
|
+
def delete_tag(name)
|
297
|
+
hg(:tag,'--remove',name)
|
298
|
+
end
|
299
|
+
|
300
|
+
#
|
301
|
+
# Prints the Hg log.
|
302
|
+
#
|
303
|
+
# @param [String] :commit
|
304
|
+
# Commit to begin the log at.
|
305
|
+
#
|
306
|
+
# @param [String] :paths
|
307
|
+
# File to list commits for.
|
308
|
+
#
|
309
|
+
def log(options={})
|
310
|
+
arguments = []
|
311
|
+
|
312
|
+
if options[:commit]
|
313
|
+
arguments << '-r' << options[:commit]
|
314
|
+
end
|
315
|
+
|
316
|
+
if options[:paths]
|
317
|
+
arguments += [*options[:paths]]
|
318
|
+
end
|
319
|
+
|
320
|
+
hg(:log,*arguments)
|
321
|
+
end
|
322
|
+
|
323
|
+
#
|
324
|
+
# Pushes changes to the remote Hg repository.
|
325
|
+
#
|
326
|
+
# @param [Hash] options
|
327
|
+
# Additional options.
|
328
|
+
#
|
329
|
+
# @option options [Boolean] :force
|
330
|
+
# Specifies whether to force pushing the changes.
|
331
|
+
#
|
332
|
+
# @option options [String, Symbol] :repository
|
333
|
+
# The remote repository to push to.
|
334
|
+
#
|
335
|
+
# @return [Boolean]
|
336
|
+
# Specifies whether the changes were successfully pushed.
|
337
|
+
#
|
338
|
+
def push(options={})
|
339
|
+
arguments = []
|
340
|
+
|
341
|
+
arguments << '-f' if options[:force]
|
342
|
+
arguments << options[:repository] if options[:repository]
|
343
|
+
|
344
|
+
hg(:push,*arguments)
|
345
|
+
end
|
346
|
+
|
347
|
+
#
|
348
|
+
# Pulls changes from the remote Hg repository.
|
349
|
+
#
|
350
|
+
# @param [Hash] options
|
351
|
+
# Additional options.
|
352
|
+
#
|
353
|
+
# @option options [Boolean] :force
|
354
|
+
# Specifies whether to force pushing the changes.
|
355
|
+
#
|
356
|
+
# @option options [String, Symbol] :repository
|
357
|
+
# The remote repository to push to.
|
358
|
+
#
|
359
|
+
# @return [Boolean]
|
360
|
+
# Specifies whether the changes were successfully pulled.
|
361
|
+
#
|
362
|
+
def pull(options={})
|
363
|
+
arguments = []
|
364
|
+
|
365
|
+
arguments << '-f' if options[:force]
|
366
|
+
arguments << options[:repository] if options[:repository]
|
367
|
+
|
368
|
+
hg(:pull,*arguments)
|
369
|
+
end
|
370
|
+
|
371
|
+
#
|
372
|
+
# Lists the commits in the Hg repository.
|
373
|
+
#
|
374
|
+
# @param [Hash] options
|
375
|
+
# Additional options.
|
376
|
+
#
|
377
|
+
# @option options [String] :commit
|
378
|
+
# Commit to start at.
|
379
|
+
#
|
380
|
+
# @option options [Symbol, String] :branch
|
381
|
+
# The branch to list commits within.
|
382
|
+
#
|
383
|
+
# @option options [Integer] :limit
|
384
|
+
# The number of commits to list.
|
385
|
+
#
|
386
|
+
# @option options [String, Array<String>] :paths
|
387
|
+
# The path(s) to list commits for.
|
388
|
+
#
|
389
|
+
# @yield [commit]
|
390
|
+
# The given block will be passed each commit.
|
391
|
+
#
|
392
|
+
# @yieldparam [Commits::Hg] commit
|
393
|
+
# A commit from the repository.
|
394
|
+
#
|
395
|
+
# @return [Enumerator<Commits::Hg>]
|
396
|
+
# The commits in the repository.
|
397
|
+
#
|
398
|
+
def commits(options={})
|
399
|
+
return enum_for(:commits,options) unless block_given?
|
400
|
+
|
401
|
+
arguments = []
|
402
|
+
|
403
|
+
if options[:commit]
|
404
|
+
arguments << '--rev' << options[:commit]
|
405
|
+
end
|
406
|
+
|
407
|
+
if options[:branch]
|
408
|
+
arguments << '--branch' << options[:branch]
|
409
|
+
end
|
410
|
+
|
411
|
+
if options[:limit]
|
412
|
+
arguments << '--limit' << options[:limit]
|
413
|
+
end
|
414
|
+
|
415
|
+
if options[:paths]
|
416
|
+
arguments.push(*options[:paths])
|
417
|
+
end
|
418
|
+
|
419
|
+
revision = nil
|
420
|
+
hash = nil
|
421
|
+
branch = nil
|
422
|
+
user = nil
|
423
|
+
date = nil
|
424
|
+
summary = nil
|
425
|
+
|
426
|
+
popen('hg log',*arguments) do |line|
|
427
|
+
if line.empty?
|
428
|
+
yield Commits::Hg.new(revision,hash,branch,user,date,summary)
|
429
|
+
|
430
|
+
revision = hash = branch = user = date = summary = nil
|
431
|
+
else
|
432
|
+
key, value = line.split(' ',2)
|
433
|
+
|
434
|
+
case key
|
435
|
+
when 'changeset:'
|
436
|
+
revision, hash = value.split(':',2)
|
437
|
+
when 'branch:'
|
438
|
+
branch = value
|
439
|
+
when 'user:'
|
440
|
+
user = value
|
441
|
+
when 'date:'
|
442
|
+
date = Time.parse(value)
|
443
|
+
when 'summary:'
|
444
|
+
summary = value
|
445
|
+
end
|
446
|
+
end
|
447
|
+
end
|
448
|
+
end
|
449
|
+
|
450
|
+
protected
|
451
|
+
|
452
|
+
#
|
453
|
+
# Runs a Hg command.
|
454
|
+
#
|
455
|
+
# @param [Symbol] command
|
456
|
+
# The Hg command to run.
|
457
|
+
#
|
458
|
+
# @param [Array] arguments
|
459
|
+
# Additional arguments to pass to the Hg command.
|
460
|
+
#
|
461
|
+
# @return [Boolean]
|
462
|
+
# Specifies whether the Hg command exited successfully.
|
463
|
+
#
|
464
|
+
def hg(command,*arguments)
|
465
|
+
run(:hg,command,*arguments)
|
466
|
+
end
|
467
|
+
|
468
|
+
end
|
469
|
+
end
|