svn_wc 0.0.2 → 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
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