svn_wc 0.0.2 → 0.0.3
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/ChangeLog +13 -2
- data/README.rdoc +2 -2
- data/lib/svn_wc.rb +230 -176
- data/test/svn_wc_test.rb +159 -53
- metadata +2 -2
data/ChangeLog
CHANGED
@@ -1,2 +1,13 @@
|
|
1
|
-
version 0.0.
|
2
|
-
*
|
1
|
+
version 0.0.3
|
2
|
+
* add all possible arg options to 'add' (from client.rb)
|
3
|
+
* enable propset (ignore) only
|
4
|
+
* 'exposed the abstraction' introduced Delegation if we don't define a method pass it on to the ruby bindings.
|
5
|
+
* (code refactoring/cleanup)
|
6
|
+
|
7
|
+
version 0.0.2
|
8
|
+
* changes for backwards compatibility to subversion-ruby bindings 1.4.2
|
9
|
+
(tests failed for (Centos 5.4))
|
10
|
+
* minor Readme update
|
11
|
+
|
12
|
+
version 0.0.1
|
13
|
+
* initial release
|
data/README.rdoc
CHANGED
@@ -5,7 +5,7 @@ Operate on the working copy of a (remote) Subversion (svn) repository.
|
|
5
5
|
|
6
6
|
== VERSION:
|
7
7
|
|
8
|
-
Version 0.0.
|
8
|
+
Version 0.0.3
|
9
9
|
|
10
10
|
|
11
11
|
== SYNOPSIS:
|
@@ -265,7 +265,7 @@ See the ChangeLog file for details.
|
|
265
265
|
Copyright 2009 David Wright (david_v_wright@yahoo.com), all rights reserved.
|
266
266
|
|
267
267
|
|
268
|
-
SvnWc::RepoAccess 0.0.
|
268
|
+
SvnWc::RepoAccess 0.0.3 is released under the LGPL license.
|
269
269
|
|
270
270
|
|
271
271
|
== AUTHOR:
|
data/lib/svn_wc.rb
CHANGED
@@ -44,6 +44,8 @@ require 'svn/error'
|
|
44
44
|
# * add
|
45
45
|
# * revert
|
46
46
|
# * delete
|
47
|
+
# * log info
|
48
|
+
# * propset (ignore only)
|
47
49
|
# * svn+ssh is our primary connection use case, however can connect to, and operate on a (local) file:/// URI as well
|
48
50
|
#
|
49
51
|
# Is built on top of the SVN (SWIG) (Subversion) Ruby Bindings and requires that they be installed.
|
@@ -99,41 +101,38 @@ require 'svn/error'
|
|
99
101
|
# Author:: David V. Wright <david_v_wright@yahoo.com>
|
100
102
|
# License:: LGPL License
|
101
103
|
#
|
102
|
-
#
|
103
104
|
#--
|
104
105
|
# TODO make sure args are what is expected for all methods
|
105
|
-
# TODO
|
106
|
+
# TODO propset/propget,
|
106
107
|
# look into:
|
107
108
|
# #wc_status = infos.assoc(@wc_path).last
|
108
109
|
# #assert(wc_status.text_normal?)
|
109
110
|
# #assert(wc_status.entry.dir?)
|
110
111
|
# #assert(wc_status.entry.normal?)
|
111
112
|
# #ctx.prop_set(Svn::Core::PROP_IGNORE, file2, dir_path)
|
113
|
+
#
|
114
|
+
# currently, propset IGNORE is enabled
|
115
|
+
#
|
116
|
+
# TODO/Think About Delegation: (do we want to do this?)
|
117
|
+
# Inherit from or mixin the svn bindings directly, so method calls
|
118
|
+
# not defined here explicitly can be run againt the bindings directly
|
119
|
+
# (i.e. begin ; send(svn ruby binding method signature) ; rescue)
|
112
120
|
#++
|
113
|
-
#module Svn
|
114
|
-
# class Error
|
115
|
-
# #WC_NOT_DIRECTORY # 1.4.2
|
116
|
-
# class WcNotDirectory # 1.6.6
|
117
|
-
# raise StandardError.new(
|
118
|
-
# #WC_NOT_DIRECTORY # 1.4.2
|
119
|
-
# end
|
120
|
-
# class AuthnNoProvider
|
121
|
-
# raise StandardError
|
122
|
-
# end
|
123
|
-
# end
|
124
|
-
#end
|
125
|
-
|
126
121
|
module SvnWc
|
127
122
|
|
128
123
|
# (general) exception class raised on all errors
|
129
124
|
class RepoAccessError < RuntimeError ; end
|
130
125
|
|
126
|
+
#
|
127
|
+
# class that provides API to (common) svn operations (working copy of a repo)
|
128
|
+
# also exposes the svn ruby bindings directly
|
129
|
+
#
|
130
|
+
# It aims to provide (simple) client CLI type behavior,
|
131
|
+
# for working directory repository management. in an API
|
132
|
+
#
|
131
133
|
class RepoAccess
|
132
134
|
|
133
|
-
VERSION = '0.0.
|
134
|
-
|
135
|
-
DEFAULT_CONF_FILE = File.join(File.dirname(File.dirname(\
|
136
|
-
File.expand_path(__FILE__))), 'svn_wc_conf.yaml')
|
135
|
+
VERSION = '0.0.3'
|
137
136
|
|
138
137
|
# initialization
|
139
138
|
# three optional parameters
|
@@ -143,13 +142,24 @@ module SvnWc
|
|
143
142
|
# 3. Force. Overwrite anything that may be preventing a checkout
|
144
143
|
|
145
144
|
def initialize(conf=nil, checkout=false, force=false)
|
146
|
-
set_conf(conf)
|
145
|
+
set_conf(conf) if conf
|
147
146
|
do_checkout(force) if checkout == true
|
148
147
|
|
149
148
|
# instance var of out open repo session
|
150
149
|
@ctx = svn_session
|
151
150
|
end
|
152
151
|
|
152
|
+
#
|
153
|
+
# 'expose the abstraction'
|
154
|
+
# introduce Delegation, if we don't define the method pass it on to the
|
155
|
+
# ruby bindings.
|
156
|
+
#
|
157
|
+
# (yup, this is probably asking for trouble)
|
158
|
+
#
|
159
|
+
def method_missing(sym, *args, &block)
|
160
|
+
@ctx.send sym, *args, &block
|
161
|
+
end
|
162
|
+
|
153
163
|
#--
|
154
164
|
# TODO revist these
|
155
165
|
#++
|
@@ -157,19 +167,9 @@ module SvnWc
|
|
157
167
|
:svn_repo_working_copy, :cur_file
|
158
168
|
attr_reader :ctx, :repos
|
159
169
|
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
end
|
164
|
-
## do checkout if not exists at specified local path
|
165
|
-
if File.directory? @svn_repo_working_copy and not force
|
166
|
-
raise RepoAccessError, 'target local directory ' << \
|
167
|
-
"[#{@svn_repo_working_copy}] exists, please remove" << \
|
168
|
-
'or specify another directory'
|
169
|
-
end
|
170
|
-
checkout
|
171
|
-
end
|
172
|
-
|
170
|
+
#
|
171
|
+
# set config file with abs path
|
172
|
+
#
|
173
173
|
def set_conf(conf)
|
174
174
|
begin
|
175
175
|
conf = load_conf(conf)
|
@@ -184,6 +184,35 @@ module SvnWc
|
|
184
184
|
end
|
185
185
|
end
|
186
186
|
|
187
|
+
|
188
|
+
def do_checkout(force=false)
|
189
|
+
if @svn_repo_working_copy.nil?
|
190
|
+
raise RepoAccessError, 'conf file not loaded! - Fatal Error'
|
191
|
+
end
|
192
|
+
## do checkout if not exists at specified local path
|
193
|
+
|
194
|
+
if force
|
195
|
+
begin
|
196
|
+
#FileUtils.rm_rf @svn_repo_working_copy
|
197
|
+
FileUtils.mkdir_p @svn_repo_working_copy, :force => true
|
198
|
+
rescue
|
199
|
+
end
|
200
|
+
else
|
201
|
+
if File.directory? @svn_repo_working_copy
|
202
|
+
raise RepoAccessError, 'target local directory ' << \
|
203
|
+
"[#{@svn_repo_working_copy}] exists, please remove" << \
|
204
|
+
'or specify another directory'
|
205
|
+
end
|
206
|
+
begin
|
207
|
+
FileUtils.mkdir_p @svn_repo_working_copy
|
208
|
+
rescue Errno::EACCES => err
|
209
|
+
raise RepoAccessError, err.message
|
210
|
+
end
|
211
|
+
end
|
212
|
+
|
213
|
+
checkout
|
214
|
+
end
|
215
|
+
|
187
216
|
# checkout
|
188
217
|
#
|
189
218
|
# create a local working copy of a remote svn repo (creates dir if not
|
@@ -192,23 +221,15 @@ module SvnWc
|
|
192
221
|
#
|
193
222
|
|
194
223
|
def checkout
|
195
|
-
if not File.directory? @svn_repo_working_copy
|
196
|
-
begin
|
197
|
-
FileUtils.mkdir_p @svn_repo_working_copy
|
198
|
-
rescue Errno::EACCES => e
|
199
|
-
raise RepoAccessError, e.message
|
200
|
-
end
|
201
|
-
end
|
202
|
-
|
203
224
|
begin
|
204
|
-
svn_session()
|
205
|
-
ctx.checkout(@svn_repo_master, @svn_repo_working_copy)
|
206
|
-
|
225
|
+
svn_session() do |ctx|
|
226
|
+
ctx.checkout(@svn_repo_master, @svn_repo_working_copy)
|
227
|
+
end
|
207
228
|
#rescue Svn::Error::RaLocalReposOpenFailed,
|
208
229
|
# Svn::Error::FsAlreadyExists,
|
209
|
-
#
|
210
|
-
rescue Exception =>
|
211
|
-
raise RepoAccessError,
|
230
|
+
#rescue Errno::EACCES => e
|
231
|
+
rescue Exception => err
|
232
|
+
raise RepoAccessError, err.message
|
212
233
|
end
|
213
234
|
end
|
214
235
|
alias_method :co, :checkout
|
@@ -216,8 +237,7 @@ module SvnWc
|
|
216
237
|
#
|
217
238
|
# load conf file (yaml)
|
218
239
|
#
|
219
|
-
# takes a path to a yaml config file, loads values.
|
220
|
-
# nothing passed
|
240
|
+
# takes a path to a yaml config file, loads values.
|
221
241
|
# raises RepoAccessError if something goes wrong
|
222
242
|
#
|
223
243
|
# private
|
@@ -226,7 +246,7 @@ module SvnWc
|
|
226
246
|
def load_conf(cnf) # :nodoc:
|
227
247
|
|
228
248
|
if cnf.nil? or cnf.empty?
|
229
|
-
|
249
|
+
raise RepoAccessError, 'No config file provided!'
|
230
250
|
elsif cnf and cnf.class == String and File.exists? cnf
|
231
251
|
cnf = IO.read(cnf)
|
232
252
|
end
|
@@ -247,23 +267,29 @@ module SvnWc
|
|
247
267
|
#
|
248
268
|
# raises RepoAccessError if something goes wrong
|
249
269
|
#
|
270
|
+
#--
|
271
|
+
# "svn/client.rb" Svn::Client
|
272
|
+
# def add(path, recurse=true, force=false, no_ignore=false)
|
273
|
+
# Client.add3(path, recurse, force, no_ignore, self)
|
274
|
+
# end
|
275
|
+
#++
|
250
276
|
|
251
|
-
def add(files=[])
|
277
|
+
def add(files=[], recurse=true, force=false, no_ignore=false)
|
252
278
|
|
253
279
|
# TODO make sure args are what is expected for all methods
|
254
280
|
raise ArgumentError, 'files is empty' unless files
|
255
281
|
|
256
282
|
svn_session() do |svn|
|
257
283
|
begin
|
258
|
-
files.each
|
259
|
-
svn.add(ef,
|
260
|
-
|
284
|
+
files.each do |ef|
|
285
|
+
svn.add(ef, recurse, force, no_ignore)
|
286
|
+
end
|
261
287
|
#rescue Svn::Error::ENTRY_EXISTS,
|
262
288
|
# Svn::Error::AuthnNoProvider,
|
263
289
|
# #Svn::Error::WcNotDirectory,
|
264
290
|
# Svn::Error::SvnError => e
|
265
|
-
rescue Exception =>
|
266
|
-
raise RepoAccessError, "Add Failed: #{
|
291
|
+
rescue Exception => excp
|
292
|
+
raise RepoAccessError, "Add Failed: #{excp.message}"
|
267
293
|
end
|
268
294
|
end
|
269
295
|
end
|
@@ -277,7 +303,7 @@ module SvnWc
|
|
277
303
|
# raises RepoAccessError if something goes wrong
|
278
304
|
#
|
279
305
|
|
280
|
-
def delete(files=[], recurs=
|
306
|
+
def delete(files=[], recurs=false)
|
281
307
|
svn_session() do |svn|
|
282
308
|
begin
|
283
309
|
svn.delete(files)
|
@@ -285,8 +311,8 @@ module SvnWc
|
|
285
311
|
# #Svn::Error::WcNotDirectory,
|
286
312
|
# Svn::Error::ClientModified,
|
287
313
|
# Svn::Error::SvnError => e
|
288
|
-
rescue Exception =>
|
289
|
-
raise RepoAccessError, "Delete Failed: #{
|
314
|
+
rescue Exception => err
|
315
|
+
raise RepoAccessError, "Delete Failed: #{err.message}"
|
290
316
|
end
|
291
317
|
end
|
292
318
|
end
|
@@ -316,8 +342,8 @@ module SvnWc
|
|
316
342
|
# Svn::Error::IllegalTarget,
|
317
343
|
# #Svn::Error::EntryNotFound => e
|
318
344
|
# Exception => e
|
319
|
-
rescue Exception =>
|
320
|
-
raise RepoAccessError, "Commit Failed: #{
|
345
|
+
rescue Exception => err
|
346
|
+
raise RepoAccessError, "Commit Failed: #{err.message}"
|
321
347
|
end
|
322
348
|
end
|
323
349
|
rev
|
@@ -336,33 +362,17 @@ module SvnWc
|
|
336
362
|
# raises RepoAccessError if something goes wrong
|
337
363
|
#
|
338
364
|
# alias up
|
339
|
-
#--
|
340
|
-
# XXX refactor this (too long)
|
341
|
-
#++
|
342
365
|
def update(paths=[])
|
343
366
|
|
344
367
|
if paths.empty? then paths = self.svn_repo_working_copy end
|
345
368
|
#XXX update is a bummer, just returns the rev num, not affected files
|
346
369
|
#(svn command line up, also returns altered/new files - mimic that)
|
347
|
-
# hence our inplace hack
|
370
|
+
# hence our inplace hack (_pre/_post update_entries)
|
348
371
|
#
|
349
372
|
# unfortunetly, we cant use 'Repos', only works on local filesystem repo
|
350
373
|
# (NOT remote)
|
351
374
|
#p Svn::Repos.open(@svn_repo_master) # Svn::Repos.open('/tmp/svnrepo')
|
352
|
-
|
353
|
-
pre_up_entries = Array.new
|
354
|
-
modified_entries = Array.new
|
355
|
-
list_entries.each { |ent|
|
356
|
-
##puts "#{ent[:status]} | #{ent[:repo_rev]} | #{ent[:entry_name]}"
|
357
|
-
pre_up_entries.push ent[:entry_name]
|
358
|
-
## how does it handle deletes?
|
359
|
-
#if info()[:rev] != ent[:repo_rev]
|
360
|
-
# puts "changed file: #{File.join(paths, ent[:entry_name])} | #{ent[:status]} "
|
361
|
-
#end
|
362
|
-
if ent[:status] == 'M'
|
363
|
-
modified_entries.push "#{ent[:status]}\t#{ent[:entry_name]}"
|
364
|
-
end
|
365
|
-
}
|
375
|
+
_pre_update_entries
|
366
376
|
|
367
377
|
rev = String.new
|
368
378
|
svn_session() do |svn|
|
@@ -374,30 +384,60 @@ module SvnWc
|
|
374
384
|
# #Svn::Error::WcNotDirectory,
|
375
385
|
# #Svn::Error::EntryNotFound => e
|
376
386
|
# Exception => e
|
377
|
-
rescue Exception =>
|
378
|
-
raise RepoAccessError, "Update Failed: #{
|
387
|
+
rescue Exception => err
|
388
|
+
raise RepoAccessError, "Update Failed: #{err.message}"
|
379
389
|
end
|
380
390
|
end
|
381
391
|
|
392
|
+
_post_update_entries
|
393
|
+
|
394
|
+
return rev, @modified_entries
|
395
|
+
|
396
|
+
end
|
397
|
+
alias_method :up, :update
|
398
|
+
|
399
|
+
#
|
400
|
+
# get list of entries before doing an update
|
401
|
+
#
|
402
|
+
def _pre_update_entries #:nodoc:
|
403
|
+
@pre_up_entries = Array.new
|
404
|
+
@modified_entries = Array.new
|
405
|
+
list_entries.each do |ent|
|
406
|
+
##puts "#{ent[:status]} | #{ent[:repo_rev]} | #{ent[:entry_name]}"
|
407
|
+
e_name = ent[:entry_name]
|
408
|
+
stat = ent[:status]
|
409
|
+
@pre_up_entries.push e_name
|
410
|
+
## how does it handle deletes?
|
411
|
+
#if info()[:rev] != ent[:repo_rev]
|
412
|
+
# puts "changed file: #{File.join(paths, ent[:entry_name])} | #{ent[:status]} "
|
413
|
+
#end
|
414
|
+
if stat == 'M' then @modified_entries.push "#{stat}\t#{e_name}" end
|
415
|
+
end
|
416
|
+
end
|
417
|
+
private :_pre_update_entries
|
418
|
+
|
419
|
+
#
|
420
|
+
# get list of entries after doing an update
|
421
|
+
#
|
422
|
+
def _post_update_entries #:nodoc:
|
382
423
|
post_up_entries = Array.new
|
383
424
|
list_entries.each { |ent| post_up_entries.push ent[:entry_name] }
|
384
425
|
|
385
|
-
added
|
386
|
-
removed = pre_up_entries - post_up_entries
|
426
|
+
added = post_up_entries - @pre_up_entries
|
427
|
+
removed = @pre_up_entries - post_up_entries
|
387
428
|
|
388
|
-
if added.length > 0
|
389
|
-
added.each {|
|
429
|
+
if added.length > 0
|
430
|
+
added.each {|e_add| @modified_entries.push "A\t#{e_add}" }
|
390
431
|
end
|
391
432
|
|
392
433
|
if removed.length > 0
|
393
|
-
removed.each {|
|
434
|
+
removed.each {|e_rm| @modified_entries.push "D\t#{e_rm}" }
|
394
435
|
end
|
395
436
|
|
396
|
-
return rev, modified_entries
|
397
|
-
|
398
437
|
end
|
399
|
-
|
400
|
-
|
438
|
+
private :_post_update_entries
|
439
|
+
|
440
|
+
|
401
441
|
#
|
402
442
|
# get status on dir/file path.
|
403
443
|
#
|
@@ -469,21 +509,31 @@ module SvnWc
|
|
469
509
|
end
|
470
510
|
end
|
471
511
|
|
512
|
+
_file_list infos
|
513
|
+
|
514
|
+
end
|
515
|
+
private :do_status
|
516
|
+
|
517
|
+
|
518
|
+
#
|
519
|
+
# create and return list of anon hashes
|
520
|
+
# set hashes to contain :path and :status
|
521
|
+
#
|
522
|
+
def _file_list(info_list) # :nodoc:
|
472
523
|
files = Array.new
|
473
|
-
|
524
|
+
info_list.each {|r|
|
474
525
|
#p r.inspect
|
475
526
|
# file is not modified, we don't want to see it (this is 'status')
|
476
|
-
|
527
|
+
txt_stat = r[1].text_status
|
528
|
+
next if ' ' == status_codes(txt_stat)
|
477
529
|
f_rec = Hash.new
|
478
530
|
f_rec[:path] = r[0]
|
479
|
-
f_rec[:status] = status_codes(
|
531
|
+
f_rec[:status] = status_codes(txt_stat)
|
480
532
|
files.push f_rec
|
481
533
|
}
|
482
|
-
|
483
534
|
files
|
484
|
-
|
485
535
|
end
|
486
|
-
private :
|
536
|
+
private :_file_list
|
487
537
|
|
488
538
|
#
|
489
539
|
# list (ls)
|
@@ -562,24 +612,26 @@ module SvnWc
|
|
562
612
|
#
|
563
613
|
|
564
614
|
def list_entries(dir=self.svn_repo_working_copy, file=nil, verbose=false)
|
565
|
-
@entry_list = []
|
566
|
-
show = true
|
615
|
+
@entry_list, @show, @verbose = [], true, verbose
|
567
616
|
Svn::Wc::AdmAccess.open(nil, dir, false, 5) do |adm|
|
617
|
+
@adm = adm
|
568
618
|
if file.nil?
|
569
619
|
#also see walk_entries (in svn bindings) has callback
|
570
620
|
adm.read_entries.keys.sort.each { |ef|
|
571
621
|
next unless ef.length >= 1 # why this check and not file.exists?
|
572
622
|
f_path = File.join(dir, ef)
|
573
623
|
if File.file? f_path
|
574
|
-
_collect_get_entry_info(f_path
|
624
|
+
_collect_get_entry_info(f_path)
|
575
625
|
elsif File.directory? f_path
|
576
|
-
_walk_entries(f_path
|
626
|
+
_walk_entries(f_path)
|
577
627
|
end
|
578
628
|
}
|
579
629
|
else
|
580
|
-
_collect_get_entry_info(file
|
630
|
+
_collect_get_entry_info(file)
|
581
631
|
end
|
582
632
|
end
|
633
|
+
#XXX do we want nil or empty on no entries, choosing empty for now
|
634
|
+
#@entry_list unless @entry_list.empty?
|
583
635
|
@entry_list
|
584
636
|
end
|
585
637
|
|
@@ -589,11 +641,11 @@ module SvnWc
|
|
589
641
|
# given a dir, iterate each entry, getting detailed file entry info
|
590
642
|
#
|
591
643
|
|
592
|
-
def _walk_entries(f_path
|
644
|
+
def _walk_entries(f_path) #:nodoc:
|
593
645
|
Dir.entries(f_path).each do |de|
|
594
646
|
next if de == '..' or de == '.' or de == '.svn'
|
595
647
|
fp_path = File.join(f_path, de)
|
596
|
-
_collect_get_entry_info(fp_path
|
648
|
+
_collect_get_entry_info(fp_path)
|
597
649
|
end
|
598
650
|
end
|
599
651
|
private :_walk_entries
|
@@ -608,10 +660,10 @@ module SvnWc
|
|
608
660
|
# requested
|
609
661
|
#
|
610
662
|
|
611
|
-
def _collect_get_entry_info(abs_path_file
|
612
|
-
@status_info =
|
613
|
-
_get_entry_info(abs_path_file
|
614
|
-
@entry_list.push @status_info
|
663
|
+
def _collect_get_entry_info(abs_path_file) #:nodoc:
|
664
|
+
@status_info = Hash.new
|
665
|
+
_get_entry_info(abs_path_file)
|
666
|
+
@entry_list.push @status_info unless @status_info.empty?
|
615
667
|
end
|
616
668
|
private :_collect_get_entry_info
|
617
669
|
|
@@ -628,63 +680,65 @@ module SvnWc
|
|
628
680
|
# TODO - document all the params available from this command
|
629
681
|
#++
|
630
682
|
|
631
|
-
def _get_entry_info(abs_path_file
|
683
|
+
def _get_entry_info(abs_path_file) # :nodoc:
|
632
684
|
wc = self.svn_repo_working_copy
|
633
685
|
entry_repo_location = abs_path_file[(wc.length+1)..-1]
|
634
686
|
|
635
|
-
entry = Svn::Wc::Entry.new(abs_path_file, adm, show)
|
636
|
-
|
687
|
+
entry = Svn::Wc::Entry.new(abs_path_file, @adm, @show)
|
688
|
+
#@status_info[:entry_name] = entry_repo_location
|
637
689
|
|
638
|
-
status = adm.status(abs_path_file)
|
690
|
+
status = @adm.status(abs_path_file)
|
639
691
|
return if status.entry.nil?
|
640
692
|
|
641
|
-
@status_info[:
|
642
|
-
@status_info[:
|
643
|
-
@status_info[:
|
693
|
+
@status_info[:entry_name] = entry_repo_location
|
694
|
+
@status_info[:status] = status_codes(status.text_status)
|
695
|
+
@status_info[:repo_rev] = status.entry.revision
|
696
|
+
@status_info[:kind] = status.entry.kind
|
644
697
|
|
645
698
|
if @status_info[:kind] == 2
|
646
699
|
# remove the repo root abs path, give dirs relative to repo root
|
647
700
|
@status_info[:dir_name] = entry_repo_location
|
648
701
|
# XXX hmmm, this is a little like a goto, revisit this
|
649
|
-
_walk_entries(abs_path_file
|
702
|
+
_walk_entries(abs_path_file)
|
650
703
|
end
|
651
|
-
return if verbose == false
|
704
|
+
return if @verbose == false
|
652
705
|
# only on demand ; i.e. verbose = true
|
653
|
-
|
654
|
-
@status_info[:entry_conflict]
|
655
|
-
@status_info[:
|
656
|
-
@status_info[:
|
657
|
-
@status_info[:
|
658
|
-
@status_info[:
|
659
|
-
@status_info[:
|
660
|
-
@status_info[:
|
661
|
-
@status_info[:
|
662
|
-
@status_info[:
|
663
|
-
@status_info[:
|
664
|
-
@status_info[:
|
665
|
-
@status_info[:
|
666
|
-
@status_info[:
|
667
|
-
@status_info[:
|
668
|
-
@status_info[:
|
669
|
-
@status_info[:
|
670
|
-
@status_info[:
|
671
|
-
@status_info[:
|
672
|
-
@status_info[:
|
673
|
-
@status_info[:
|
674
|
-
@status_info[:
|
675
|
-
@status_info[:
|
676
|
-
@status_info[:
|
677
|
-
@status_info[:
|
678
|
-
@status_info[:
|
679
|
-
@status_info[:
|
680
|
-
@status_info[:
|
681
|
-
@status_info[:
|
682
|
-
@status_info[:
|
683
|
-
@status_info[:
|
684
|
-
@status_info[:
|
685
|
-
@status_info[:
|
686
|
-
@status_info[:
|
687
|
-
@status_info[:
|
706
|
+
s = status.entry
|
707
|
+
@status_info[:entry_conflict] = entry.conflicted?(abs_path_file)
|
708
|
+
@status_info[:lock_creation_date] = s.lock_creation_date
|
709
|
+
@status_info[:present_props] = s.present_props
|
710
|
+
@status_info[:has_prop_mods] = s.has_prop_mods
|
711
|
+
@status_info[:copyfrom_url] = s.copyfrom_url
|
712
|
+
@status_info[:conflict_old] = s.conflict_old
|
713
|
+
@status_info[:conflict_new] = s.conflict_new
|
714
|
+
@status_info[:lock_comment] = s.lock_comment
|
715
|
+
@status_info[:copyfrom_rev] = s.copyfrom_rev
|
716
|
+
@status_info[:working_size] = s.working_size
|
717
|
+
@status_info[:conflict_wrk] = s.conflict_wrk
|
718
|
+
@status_info[:cmt_author] = s.cmt_author
|
719
|
+
@status_info[:changelist] = s.changelist
|
720
|
+
@status_info[:lock_token] = s.lock_token
|
721
|
+
@status_info[:keep_local] = s.keep_local
|
722
|
+
@status_info[:lock_owner] = s.lock_owner
|
723
|
+
@status_info[:prop_time] = s.prop_time
|
724
|
+
@status_info[:has_props] = s.has_props
|
725
|
+
@status_info[:schedule] = s.schedule
|
726
|
+
@status_info[:text_time] = s.text_time
|
727
|
+
@status_info[:revision] = s.revision
|
728
|
+
@status_info[:checksum] = s.checksum
|
729
|
+
@status_info[:cmt_date] = s.cmt_date
|
730
|
+
@status_info[:prejfile] = s.prejfile
|
731
|
+
@status_info[:is_file] = s.file?
|
732
|
+
@status_info[:normal?] = s.normal?
|
733
|
+
@status_info[:cmt_rev] = s.cmt_rev
|
734
|
+
@status_info[:deleted] = s.deleted
|
735
|
+
@status_info[:absent] = s.absent
|
736
|
+
@status_info[:is_add] = s.add?
|
737
|
+
@status_info[:is_dir] = s.dir?
|
738
|
+
@status_info[:repos] = s.repos
|
739
|
+
@status_info[:depth] = s.depth
|
740
|
+
@status_info[:uuid] = s.uuid
|
741
|
+
@status_info[:url] = s.url
|
688
742
|
end
|
689
743
|
private :_get_entry_info
|
690
744
|
|
@@ -701,7 +755,7 @@ module SvnWc
|
|
701
755
|
wc_path = self.svn_repo_working_copy
|
702
756
|
end
|
703
757
|
|
704
|
-
r_info =
|
758
|
+
r_info = Hash.new
|
705
759
|
begin
|
706
760
|
@ctx.info(wc_path) do |path, type|
|
707
761
|
r_info[:last_changed_author] = type.last_changed_author
|
@@ -718,20 +772,14 @@ module SvnWc
|
|
718
772
|
r_info[:conflict_new] = type.conflict_new
|
719
773
|
r_info[:has_wc_info] = type.has_wc_info
|
720
774
|
r_info[:repos_UUID] = type.repos_UUID
|
721
|
-
#r_info[:changelist] = type.changelist
|
722
|
-
r_info[:prop_time] = type.prop_time
|
723
|
-
r_info[:text_time] = type.text_time
|
724
775
|
r_info[:checksum] = type.checksum
|
725
|
-
r_info[:
|
726
|
-
r_info[:schedule]
|
727
|
-
r_info[:taguri]
|
728
|
-
|
729
|
-
r_info[:
|
730
|
-
#r_info[:
|
731
|
-
r_info[:
|
732
|
-
r_info[:dup] = type.dup
|
733
|
-
r_info[:URL] = type.URL
|
734
|
-
r_info[:rev] = type.rev
|
776
|
+
r_info[:prop_time], r_info[:text_time] = type.prop_time, type.text_time
|
777
|
+
r_info[:prejfile], r_info[:schedule] = type.prejfile, type.schedule
|
778
|
+
r_info[:taguri], r_info[:lock] = type.taguri, type.lock
|
779
|
+
r_info[:rev], r_info[:dup] = type.rev, type.dup
|
780
|
+
r_info[:url], r_info[:URL] = type.url, type.URL
|
781
|
+
#r_info[:changelist] = type.changelist
|
782
|
+
#r_info[:depth], r_info[:size] = type.depth, type.size
|
735
783
|
end
|
736
784
|
#rescue Svn::Error::WcNotDirectory => e
|
737
785
|
# #Svn::Error::RaIllegalUrl,
|
@@ -814,6 +862,23 @@ module SvnWc
|
|
814
862
|
out_file.readlines
|
815
863
|
end
|
816
864
|
|
865
|
+
# currently supports type='ignore' only
|
866
|
+
#--
|
867
|
+
# TODO support other propset's ; also propget
|
868
|
+
#++
|
869
|
+
def propset(type, file, dir_path)
|
870
|
+
raise RepoAccessError, '"ignore" is only supported propset' \
|
871
|
+
unless type == 'ignore'
|
872
|
+
|
873
|
+
svn_session() do |svn|
|
874
|
+
begin
|
875
|
+
svn.propset(Svn::Core::PROP_IGNORE, file, dir_path)
|
876
|
+
rescue Exception => e #Svn::Error::EntryNotFound => e
|
877
|
+
raise RepoAccessError, "Propset (Ignore) Failed: #{e.message}"
|
878
|
+
end
|
879
|
+
end
|
880
|
+
end
|
881
|
+
|
817
882
|
# svn session set up
|
818
883
|
#--
|
819
884
|
# from
|
@@ -858,14 +923,3 @@ module SvnWc
|
|
858
923
|
end
|
859
924
|
|
860
925
|
end
|
861
|
-
|
862
|
-
if __FILE__ == $0
|
863
|
-
|
864
|
-
svn = SvnWc::RepoAccess.new
|
865
|
-
p svn
|
866
|
-
#n = '/tmp/NEW'
|
867
|
-
#svn.add n
|
868
|
-
#svn.commit n
|
869
|
-
|
870
|
-
end
|
871
|
-
|
data/test/svn_wc_test.rb
CHANGED
@@ -11,9 +11,6 @@
|
|
11
11
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
12
12
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
13
13
|
# Lesser General Public License for more details.
|
14
|
-
#$LOAD_PATH.unshift '..'
|
15
|
-
#$LOAD_PATH.unshift File.join('..', 'lib')
|
16
|
-
#$LOAD_PATH.unshift File.join('lib')
|
17
14
|
|
18
15
|
require 'yaml'
|
19
16
|
require File.join(File.dirname(__FILE__), "..", "lib", 'svn_wc')
|
@@ -34,6 +31,8 @@ require 'pp'
|
|
34
31
|
# svn status
|
35
32
|
# svn delete
|
36
33
|
# svn diff
|
34
|
+
# propset ignore
|
35
|
+
# log
|
37
36
|
|
38
37
|
# NOTE
|
39
38
|
# svn+ssh is our primary use case, however
|
@@ -409,27 +408,33 @@ class TestSvnWc < Test::Unit::TestCase
|
|
409
408
|
assert_equal Array.new, svn.diff(f)
|
410
409
|
end
|
411
410
|
|
412
|
-
## TODO
|
411
|
+
## TODO not sure if we actually want this
|
413
412
|
#def test_add_does_recursive_nested_dirs
|
414
|
-
# svn = SvnWc::RepoAccess.new(
|
415
|
-
|
416
|
-
#
|
417
|
-
#
|
418
|
-
# FileUtils.mkdir_p @conf['svn_repo_working_copy'] + "/d1/d2/d3"
|
419
|
-
# nested = @conf['svn_repo_working_copy'] +
|
420
|
-
# "/d1/d2/d3/test_#{Time.now.usec.to_s}.txt"
|
413
|
+
# svn = SvnWc::RepoAccess.new(YAML::dump(@conf), true, true)
|
414
|
+
# repo_wc = @conf['svn_repo_working_copy']
|
415
|
+
# FileUtils.mkdir_p File.join(repo_wc, 'd1','d2','d3')
|
416
|
+
# nested = File.join(repo_wc, 'd1','d2','d3',"test_#{Time.now.usec.to_s}.txt")
|
421
417
|
# FileUtils.touch nested
|
418
|
+
# # TODO ability to add recursive nested dirs
|
422
419
|
# svn.add nested
|
423
|
-
|
424
|
-
#
|
425
|
-
#
|
426
|
-
#
|
427
|
-
#
|
428
|
-
# }
|
429
|
-
#
|
430
|
-
#
|
431
|
-
|
432
|
-
#
|
420
|
+
|
421
|
+
# ## add 1 new file in nested heirerarcy
|
422
|
+
# ## TODO ability to add recursive nested dirs
|
423
|
+
# #FileUtils.mkdir_p @conf['svn_repo_working_copy'] + "/d1/d2/d3"
|
424
|
+
# #nested = @conf['svn_repo_working_copy'] +
|
425
|
+
# # "/d1/d2/d3/test_#{Time.now.usec.to_s}.txt"
|
426
|
+
# #FileUtils.touch nested
|
427
|
+
# #svn.add nested
|
428
|
+
|
429
|
+
# #svn.status.each { |ef|
|
430
|
+
# # next unless ef[:entry_name].match /test_.*/
|
431
|
+
# # assert_equal 'A', ef[:status]
|
432
|
+
# # assert_equal nested, File.join(@conf['svn_repo_working_copy'], ef[:entry_name])
|
433
|
+
# #}
|
434
|
+
# #svn.revert
|
435
|
+
# #assert_equal 1, svn.status.length
|
436
|
+
# #assert_equal File.basename(@conf['svn_repo_working_copy']),
|
437
|
+
# # svn.status[0][:entry_name]
|
433
438
|
#end
|
434
439
|
|
435
440
|
def test_update_acts_on_whole_repo_by_default_knows_a_m_d
|
@@ -474,25 +479,20 @@ class TestSvnWc < Test::Unit::TestCase
|
|
474
479
|
|
475
480
|
end
|
476
481
|
|
477
|
-
|
478
|
-
|
479
|
-
|
480
|
-
|
482
|
+
def test_add_exception_on_already_added_file
|
483
|
+
svn = SvnWc::RepoAccess.new(YAML::dump(@conf), true, true)
|
484
|
+
this_wc_rev = 0
|
485
|
+
assert_equal [this_wc_rev, []], svn.update
|
481
486
|
|
482
|
-
|
487
|
+
rev, f_name = check_out_new_working_copy_add_and_commit_new_entries
|
483
488
|
|
484
|
-
|
489
|
+
assert_equal [rev, ["A\t#{File.basename(f_name.to_s)}"]], svn.update
|
485
490
|
|
486
|
-
|
487
|
-
|
488
|
-
|
489
|
-
|
490
|
-
|
491
|
-
# start_rev = svn.commit f
|
492
|
-
# #p svn.status(f)
|
493
|
-
# #assert_equal 'M', svn.status(f)[0][:status]
|
494
|
-
# #assert_equal start_rev, svn.info(f)[:rev]
|
495
|
-
#end
|
491
|
+
(rev, f) = modify_file_and_commit_into_another_working_repo
|
492
|
+
File.open(f, 'w') {|fl| fl.write('adding text to file.')}
|
493
|
+
#already under version control
|
494
|
+
assert_raise(SvnWc::RepoAccessError) { svn.add f }
|
495
|
+
end
|
496
496
|
|
497
497
|
def test_list_recursive
|
498
498
|
FileUtils.rm_rf @conf['svn_repo_working_copy']
|
@@ -603,19 +603,125 @@ class TestSvnWc < Test::Unit::TestCase
|
|
603
603
|
assert fails
|
604
604
|
end
|
605
605
|
|
606
|
-
|
607
|
-
|
608
|
-
#for this one, we will have to create another working copy, modify a file
|
609
|
-
# and commit from there, then to an update in this working copy
|
610
|
-
#end
|
606
|
+
def test_list_entries_verbose
|
607
|
+
svn = SvnWc::RepoAccess.new(YAML::dump(@conf), true, true)
|
611
608
|
|
612
|
-
|
613
|
-
|
614
|
-
|
615
|
-
|
609
|
+
repo_wc = @conf['svn_repo_working_copy']
|
610
|
+
|
611
|
+
dir_ent = Dir.mktmpdir('P', repo_wc)
|
612
|
+
file = 'file.txt'
|
613
|
+
file = File.join dir_ent, file
|
614
|
+
File.open(file, "w") {|f| f.print('contents.')}
|
615
|
+
file2 = new_unique_file_at_path dir_ent
|
616
|
+
|
617
|
+
svn.add dir_ent, recurse=true, force=true
|
618
|
+
rev = svn.commit repo_wc
|
619
|
+
|
620
|
+
entries = svn.list_entries
|
621
|
+
|
622
|
+
assert_equal File.basename(entries[0][:entry_name]),
|
623
|
+
File.basename(file)
|
624
|
+
assert_equal File.basename(entries[1][:entry_name]),
|
625
|
+
File.basename(file2)
|
626
|
+
assert_equal entries.size, 2
|
627
|
+
assert_nil entries[2]
|
628
|
+
# verbose info from list_entries
|
629
|
+
#p svn.list_entries(repo_wc, file, verbose=true)
|
630
|
+
f_entry = File.join(File.basename(dir_ent), File.basename(file))
|
631
|
+
svn.list_entries(repo_wc, file, verbose=true).each do |info|
|
632
|
+
# bools
|
633
|
+
assert ! info[:absent]
|
634
|
+
assert ! info[:entry_conflict]
|
635
|
+
assert ! info[:is_add]
|
636
|
+
assert ! info[:is_dir]
|
637
|
+
assert ! info[:has_props]
|
638
|
+
assert ! info[:deleted]
|
639
|
+
assert ! info[:keep_local]
|
640
|
+
assert ! info[:has_prop_mods]
|
641
|
+
assert info[:normal?]
|
642
|
+
assert info[:is_file]
|
643
|
+
|
644
|
+
assert_nil info[:copyfrom_url]
|
645
|
+
assert_nil info[:conflict_old]
|
646
|
+
assert_nil info[:conflict_new]
|
647
|
+
assert_nil info[:conflict_wrk]
|
648
|
+
assert_nil info[:lock_comment]
|
649
|
+
assert_nil info[:lock_owner]
|
650
|
+
assert_nil info[:present_props]
|
651
|
+
assert_nil info[:lock_token]
|
652
|
+
assert_nil info[:changelist]
|
653
|
+
assert_nil info[:prejfile]
|
654
|
+
|
655
|
+
#assert_equal info[:cmt_author], `id`
|
656
|
+
assert_equal info[:revision], rev
|
657
|
+
assert_equal info[:repo_rev], rev
|
658
|
+
assert_equal info[:cmt_rev] , rev
|
659
|
+
#assert_equal info[:cmt_date] , rev
|
660
|
+
#:checksum=>"bb9c00f6fc03c2213ac1f0278853dc32", :working_size=>9,
|
661
|
+
assert_equal info[:working_size] , 9
|
662
|
+
assert_equal info[:schedule], 0
|
663
|
+
assert_equal info[:lock_creation_date], 0
|
664
|
+
assert_equal info[:copyfrom_rev], -1
|
665
|
+
assert_equal info[:prop_time], 0
|
666
|
+
assert_equal info[:kind], 1 # i.e. is file
|
667
|
+
assert_equal info[:depth], 3
|
668
|
+
assert_equal info[:status] , ' '
|
669
|
+
assert_equal info[:entry_name], f_entry
|
670
|
+
assert_equal info[:url], "#{File.join(@conf['svn_repo_master'],f_entry)}"
|
671
|
+
assert_equal info[:repos], @conf['svn_repo_master']
|
672
|
+
end
|
673
|
+
|
674
|
+
end
|
675
|
+
|
676
|
+
def test_propset_ignore_file
|
677
|
+
svn = SvnWc::RepoAccess.new(YAML::dump(@conf), true, true)
|
678
|
+
|
679
|
+
repo_wc = @conf['svn_repo_working_copy']
|
680
|
+
|
681
|
+
dir_ent = Dir.mktmpdir('P', repo_wc)
|
682
|
+
file = 'file_to_ignore.txt'
|
683
|
+
|
684
|
+
svn.add dir_ent, recurse=false
|
685
|
+
svn.propset('ignore', file, dir_ent)
|
686
|
+
svn.commit repo_wc
|
687
|
+
|
688
|
+
file = File.join dir_ent, file
|
689
|
+
# create file we have already ignored, above
|
690
|
+
File.open(file, "w") {|f| f.print('testing propset ignore file.')}
|
691
|
+
|
692
|
+
file2 = new_unique_file_at_path dir_ent
|
693
|
+
|
694
|
+
svn.add dir_ent, recurse=true, force=true
|
695
|
+
svn.commit repo_wc
|
696
|
+
|
697
|
+
assert_raise(SvnWc::RepoAccessError) { svn.info file }
|
698
|
+
assert_equal File.basename(svn.list_entries[0][:entry_name]),
|
699
|
+
File.basename(file2)
|
700
|
+
assert_equal svn.list_entries.size, 1
|
701
|
+
assert_nil svn.list_entries[1]
|
702
|
+
|
703
|
+
end
|
704
|
+
|
705
|
+
# TODO
|
706
|
+
# from client.rb
|
707
|
+
#def log(paths, start_rev, end_rev, limit,
|
708
|
+
# discover_changed_paths, strict_node_history,
|
709
|
+
# peg_rev=nil)
|
710
|
+
def test_commit_with_message
|
711
|
+
log_mess = 'added new file'
|
712
|
+
|
713
|
+
svn = SvnWc::RepoAccess.new(YAML::dump(@conf), true, true)
|
714
|
+
file = new_unique_file_at_path
|
715
|
+
svn.add file
|
716
|
+
o_rev = svn.commit file, log_mess
|
717
|
+
assert o_rev >= 1
|
718
|
+
args = [file, 0, "HEAD", 0, true, nil]
|
719
|
+
svn.log(*args) do |changed_paths, rev, author, date, message|
|
720
|
+
assert_equal rev, o_rev
|
721
|
+
assert_equal message, log_mess
|
722
|
+
end
|
723
|
+
end
|
616
724
|
|
617
|
-
#def test_delete
|
618
|
-
#end
|
619
725
|
|
620
726
|
#
|
621
727
|
# methods used by the tests below here
|
@@ -662,14 +768,14 @@ class TestSvnWc < Test::Unit::TestCase
|
|
662
768
|
return rev, ff
|
663
769
|
end
|
664
770
|
|
665
|
-
def modify_file_and_commit_into_another_working_repo
|
666
|
-
raise ArgumentError, "path arg is empty" unless f and not f.empty?
|
771
|
+
def modify_file_and_commit_into_another_working_repo
|
667
772
|
svn = _working_copy_repo_at_path
|
668
|
-
|
773
|
+
f = new_unique_file_at_path(svn.svn_repo_working_copy)
|
774
|
+
File.open(f, 'w') {|fl| fl.write('this is the original content of file.')}
|
775
|
+
svn.add f
|
669
776
|
rev = svn.commit f
|
670
|
-
raise 'cant get status' unless ' ' == svn.status(f)[0][:status]
|
671
777
|
raise 'cant get revision' unless rev == svn.info(f)[:rev]
|
672
|
-
rev
|
778
|
+
return rev, f
|
673
779
|
end
|
674
780
|
|
675
781
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: svn_wc
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- David Wright
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2010-02-
|
12
|
+
date: 2010-02-20 00:00:00 -08:00
|
13
13
|
default_executable:
|
14
14
|
dependencies: []
|
15
15
|
|