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.
Files changed (5) hide show
  1. data/ChangeLog +13 -2
  2. data/README.rdoc +2 -2
  3. data/lib/svn_wc.rb +230 -176
  4. data/test/svn_wc_test.rb +159 -53
  5. metadata +2 -2
data/ChangeLog CHANGED
@@ -1,2 +1,13 @@
1
- version 0.0.1
2
- * initial checkin
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.2
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.2 is released under the LGPL license.
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 props
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.2'
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
- def do_checkout(force=false)
161
- if @svn_repo_working_copy.nil?
162
- raise RepoAccessError, 'conf file not loaded! - Fatal Error'
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() { |ctx|
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
- # Exception => e
210
- rescue Exception => e
211
- raise RepoAccessError, e.message
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. uses default if
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
- cnf = IO.read(DEFAULT_CONF_FILE)
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 { |ef|
259
- svn.add(ef, true)
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 => e
266
- raise RepoAccessError, "Add Failed: #{e.message}"
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=nil)
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 => e
289
- raise RepoAccessError, "Delete Failed: #{e.message}"
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 => e
320
- raise RepoAccessError, "Commit Failed: #{e.message}"
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 => e
378
- raise RepoAccessError, "Update Failed: #{e.message}"
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 = post_up_entries - pre_up_entries
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 {|e| modified_entries.push "A\t#{e}" }
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 {|e| modified_entries.push "D\t#{e}" }
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
- alias_method :up, :update
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
- infos.each {|r|
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
- next if ' ' == status_codes(r[1].text_status)
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(r[1].text_status)
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 :do_status
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, adm, show, verbose)
624
+ _collect_get_entry_info(f_path)
575
625
  elsif File.directory? f_path
576
- _walk_entries(f_path, adm, show, verbose)
626
+ _walk_entries(f_path)
577
627
  end
578
628
  }
579
629
  else
580
- _collect_get_entry_info(file, adm, show, verbose)
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, adm, show, verbose)#:nodoc:
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, adm, show, verbose)
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, adm, show, verbose=false)#:nodoc:
612
- @status_info = {}
613
- _get_entry_info(abs_path_file, adm, show, verbose)
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, adm, show, verbose=false) # :nodoc:
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
- @status_info[:entry_name] = entry_repo_location
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[:status] = status_codes(status.text_status)
642
- @status_info[:repo_rev] = status.entry.revision
643
- @status_info[:kind] = status.entry.kind
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, adm, show, verbose)
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
- @status_info[:lock_creation_date] = status.entry.lock_creation_date
654
- @status_info[:entry_conflict] = entry.conflicted?(abs_path_file)
655
- @status_info[:present_props] = status.entry.present_props
656
- @status_info[:has_prop_mods] = status.entry.has_prop_mods
657
- @status_info[:copyfrom_url] = status.entry.copyfrom_url
658
- @status_info[:conflict_old] = status.entry.conflict_old
659
- @status_info[:conflict_new] = status.entry.conflict_new
660
- @status_info[:lock_comment] = status.entry.lock_comment
661
- @status_info[:copyfrom_rev] = status.entry.copyfrom_rev
662
- @status_info[:working_size] = status.entry.working_size
663
- @status_info[:conflict_wrk] = status.entry.conflict_wrk
664
- @status_info[:cmt_author] = status.entry.cmt_author
665
- @status_info[:changelist] = status.entry.changelist
666
- @status_info[:lock_token] = status.entry.lock_token
667
- @status_info[:keep_local] = status.entry.keep_local
668
- @status_info[:lock_owner] = status.entry.lock_owner
669
- @status_info[:prop_time] = status.entry.prop_time
670
- @status_info[:has_props] = status.entry.has_props
671
- @status_info[:schedule] = status.entry.schedule
672
- @status_info[:text_time] = status.entry.text_time
673
- @status_info[:revision] = status.entry.revision
674
- @status_info[:checksum] = status.entry.checksum
675
- @status_info[:cmt_date] = status.entry.cmt_date
676
- @status_info[:prejfile] = status.entry.prejfile
677
- @status_info[:is_file] = status.entry.file?
678
- @status_info[:normal?] = status.entry.normal?
679
- @status_info[:cmt_rev] = status.entry.cmt_rev
680
- @status_info[:deleted] = status.entry.deleted
681
- @status_info[:absent] = status.entry.absent
682
- @status_info[:is_add] = status.entry.add?
683
- @status_info[:is_dir] = status.entry.dir?
684
- @status_info[:repos] = status.entry.repos
685
- @status_info[:depth] = status.entry.depth
686
- @status_info[:uuid] = status.entry.uuid
687
- @status_info[:url] = status.entry.url
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[:prejfile] = type.prejfile
726
- r_info[:schedule] = type.schedule
727
- r_info[:taguri] = type.taguri
728
- #r_info[:depth] = type.depth
729
- r_info[:lock] = type.lock
730
- #r_info[:size] = type.size
731
- r_info[:url] = type.url
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(nil, true)
415
-
416
- # # add 1 new file in nested heirerarcy
417
- # # TODO ability to add recursive nested dirs
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
- # svn.status.each { |ef|
425
- # next unless ef[:entry_name].match /test_.*/
426
- # assert_equal 'A', ef[:status]
427
- # assert_equal nested, File.join(@conf['svn_repo_working_copy'], ef[:entry_name])
428
- # }
429
- # svn.revert
430
- # assert_equal 1, svn.status.length
431
- # assert_equal File.basename(@conf['svn_repo_working_copy']),
432
- # svn.status[0][:entry_name]
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
- #def test_update_reports_collision
478
- # svn = SvnWc::RepoAccess.new(YAML::dump(@conf), true, true)
479
-
480
- # assert_equal '', svn.update
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
- # rev, f_name = check_out_new_working_copy_add_and_commit_new_entries
487
+ rev, f_name = check_out_new_working_copy_add_and_commit_new_entries
483
488
 
484
- # assert_equal " #{f_name}", svn.update
489
+ assert_equal [rev, ["A\t#{File.basename(f_name.to_s)}"]], svn.update
485
490
 
486
- # f = new_unique_file_at_path
487
- # modify_file_and_commit_into_another_working_repo(f)
488
- # File.open(f, 'a') {|fl| fl.write('adding text to file.')}
489
- # # XXX no update done, so this file should clash with
490
- # # what is already in the repo
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
- #def test_update
607
- # svn = SvnWc::RepoAccess.new(YAML::dump(@conf), true)
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
- #def test_update_a_locally_modified_file_raises_exception
613
- #for this one, we will have to create another working copy, modify a file
614
- # and commit from there, then to an update in this working copy
615
- #end
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(f)
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
- File.open(f, 'a') {|fl| fl.write('adding this to file.')}
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.2
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-17 00:00:00 -08:00
12
+ date: 2010-02-20 00:00:00 -08:00
13
13
  default_executable:
14
14
  dependencies: []
15
15