sundae 1.0.4 → 1.0.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (5) hide show
  1. data/README.rdoc +27 -4
  2. data/lib/sundae.rb +99 -89
  3. data/test/test_sundae.rb +10 -9
  4. data/version.txt +1 -1
  5. metadata +46 -38
data/README.rdoc CHANGED
@@ -67,7 +67,11 @@ this:
67
67
  | | |-- real_files_and_dirs
68
68
  | | ` ...
69
69
  | |-- mnt2/
70
- `-- collection2/
70
+ |-- collection2_really_a_mnt/
71
+ | |-- .sundae_path <--- empty
72
+ | |-- real_files_and_dirs
73
+ | | ` ...
74
+ `-- collection3/
71
75
  ` ...
72
76
 
73
77
  Sundae will act on all of the <em>mnt</em>s--subdirectories of the
@@ -75,6 +79,19 @@ Sundae will act on all of the <em>mnt</em>s--subdirectories of the
75
79
  <em>path</em>. The "collections" are only there to facilitate
76
80
  grouping common files and syncronizing them between computers.
77
81
 
82
+ This sub-subdirectory business is there so you can, for example, throw
83
+ all of your linux files under version control but have some of them
84
+ inserted into your home directory and some of them go somewhere else.
85
+
86
+ If you have one collection of files that you syncronize across
87
+ computers that all get deposited into the same path, you don't need a
88
+ collection of mnts. You can make can make the top level
89
+ directory--that would normally be treated as a collection--be treated
90
+ as a mnt by including a .sundae_path file in that folder (even if it's
91
+ empty). Like in the 'collection2_really_a_mnt' example above. It
92
+ seems complicated to have both options, but it's really not. I
93
+ promise.
94
+
78
95
  By default, all of the contents in each of the <em>mnt</em>s are
79
96
  placed in the user's home directory. This can be altered by creating
80
97
  a file called <tt>.sundae_path</tt> in the top of the <em>mnt</em>;
@@ -114,8 +131,11 @@ For example, the hierarchy in my <em>path</em>s looks sort of like this:
114
131
  | ` ...
115
132
  ` ...
116
133
  ~/mnt/sync/ <-- "path"
117
- |-- reference <-- "collection"
118
- | |-- home/ <-- "mnt"
134
+ |-- reference <-- "mnt"
135
+ | |-- .sundae_path (empty)
136
+ | |-- doc/
137
+ | ` ...
138
+ | |-- share/
119
139
  | ` ...
120
140
  |-- music
121
141
  | |-- home/
@@ -127,7 +147,7 @@ most of the time you can share a whole folder between computers,
127
147
  sometimes you want to mix your config files into a folder that also
128
148
  contains nonsymlinked files.
129
149
 
130
- For example, your ~/.ssh folder probably has a public and private key
150
+ For example, your "~/.ssh" folder probably has a public and private key
131
151
  that you want to stay unique to that machine, but you might want to
132
152
  mix in a "config" file that has host aliases that you share between
133
153
  machines. You can put the file in "~/mnt/nix/.ssh/config" in the
@@ -147,6 +167,9 @@ of files beneath "~/a/", then you don't want sundae to look through
147
167
  everything every time it runs. Just put it in a mnt directory with a
148
168
  <tt>.sundae_path</tt> of "~/a/b/c/d".
149
169
 
170
+ Again, if you want the first-level subdirectories of a "path" treated
171
+ as a mnt instead of a collection of mnts, just add a .sundae_path file.
172
+
150
173
  == Author
151
174
  <don@ohspite.net>
152
175
 
data/lib/sundae.rb CHANGED
@@ -115,8 +115,12 @@ module Sundae
115
115
  def self.install_location(mnt)
116
116
  mnt = Pathname.new(mnt).expand_path
117
117
  mnt_config = mnt + '.sundae_path'
118
+
118
119
  if mnt_config.exist?
119
- return Pathname.new(mnt_config.readlines[0].strip).expand_path
120
+ line = mnt_config.readlines[0]
121
+ if line then
122
+ return Pathname.new(line.strip).expand_path
123
+ end
120
124
  end
121
125
 
122
126
  base = mnt.basename.to_s
@@ -141,28 +145,27 @@ module Sundae
141
145
  def self.mnts_in_path(path)
142
146
  Pathname.new(path).expand_path
143
147
  mnts = []
144
- collections = path.children(false).delete_if {|c| c.to_s =~ /^\./}
145
-
146
- collections.each do |c|
147
- collection_mnts = (path + c).children(false).delete_if {|kid| kid.to_s =~ /^\./}
148
- collection_mnts.map! { |mnt| (c + mnt) }
148
+ collections = path.children.delete_if {|c| c.basename.to_s =~ /^\./}
149
149
 
150
- mnts |= collection_mnts # |= is the union
151
- end
152
-
153
- return mnts.sort.uniq
150
+ return collections.map do |c|
151
+ if c.children(false).include? Pathname.new('.sundae_path')
152
+ c
153
+ else
154
+ collection_mnts = c.children.delete_if {|kid| kid.basename.to_s =~ /^\./}
155
+ # collection_mnts.keep_if { |k| (path + c + k).directory? }
156
+ collection_mnts.reject! { |k| ! (path + c + k).directory? }
157
+ collection_mnts.map! { |mnt| (c + mnt) }
158
+ end
159
+ end.flatten.sort.uniq
154
160
  end
155
161
 
156
162
  # Return all mnts for every path as an array.
157
163
  #
158
164
  def self.all_mnts
159
- mnts = []
160
-
161
- @paths.each do |path|
165
+ @paths.map do |path|
162
166
  next unless path.exist?
163
- mnts |= mnts_in_path(path).map { |mnt| path + mnt } # |= is the union operator
164
- end
165
- return mnts
167
+ mnts_in_path(path)
168
+ end.compact.flatten
166
169
  end
167
170
 
168
171
  # Return all subdirectories and files in the mnts returned by
@@ -198,7 +201,7 @@ module Sundae
198
201
  files = location.entries.map { |f| location + f }
199
202
  files.each do |file|
200
203
  next unless file.symlink?
201
- next if file.readlink.exist?
204
+ next if file.exist?
202
205
  next unless root_path(file.readlink)
203
206
  file.delete
204
207
  end
@@ -217,22 +220,22 @@ module Sundae
217
220
  return nil
218
221
  end
219
222
 
220
- # Delete each generated directory if there aren't any real files in
221
- # them.
222
- #
223
- def self.remove_generated_directories
224
- generated_directories.each do |dir|
225
- # don't get rid of the linked config file
226
- next if dir.basename.to_s == '.sundae'
227
- remove_generated_stuff dir
228
-
229
- # if sf = find_static_file(dir)
230
- # puts "found static file: #{sf}"
231
- # else
232
- # dir.rmtree
233
- # end
234
- end
235
- end
223
+ # # Delete each generated directory if there aren't any real files in
224
+ # # them.
225
+ # #
226
+ # def self.remove_generated_directories
227
+ # generated_directories.each do |dir|
228
+ # # don't get rid of the linked config file
229
+ # next if dir.basename.to_s == '.sundae'
230
+ # remove_generated_stuff dir
231
+
232
+ # # if sf = find_static_file(dir)
233
+ # # puts "found static file: #{sf}"
234
+ # # else
235
+ # # dir.rmtree
236
+ # # end
237
+ # end
238
+ # end
236
239
 
237
240
  def self.remove_generated_files
238
241
  generated_files.each do |fod|
@@ -243,7 +246,7 @@ module Sundae
243
246
  end
244
247
 
245
248
  def self.remove_generated_stuff(fod)
246
- return unless fod.exist?
249
+ return unless fod.exist? || fod.symlink?
247
250
  if fod.ftype == 'directory'
248
251
  fod.each_child do |c|
249
252
  remove_generated_stuff c
@@ -264,29 +267,31 @@ module Sundae
264
267
  end
265
268
  end
266
269
 
267
- # For each directory and file in _target_, create a link at <em>link_name</em>. If
268
- # there is currently no file at <em>link_path</em>, create a symbolic link there.
270
+ # For each directory and file in _old_, create a link at <em>link_name</em>. If
271
+ # there is currently no file at <em>new</em>, create a symbolic link there.
269
272
  # If there is currently a symbolic link, combine the contents at the
270
- # link location and _target_ in a new directory and proceed
273
+ # link location and _old_ in a new directory and proceed
271
274
  # recursively.
272
275
  #
273
- def self.minimally_create_links(target, link_path)
274
- target = File.expand_path(target)
275
- link_path = File.expand_path(link_path)
276
+ def self.minimally_create_links(old, new)
277
+ old = Pathname.new(old)
278
+ new = Pathname.new(new)
276
279
 
277
- unless File.exist?(target)
278
- raise "attempt to create links from missing directory: " + target
280
+ unless old.exist?
281
+ raise "attempt to create links from missing directory: " + old
279
282
  end
280
283
 
281
- Find.find(target) do |path|
282
- next if path == target
284
+ old.realpath.find do |path|
285
+ next if path == old.realpath
283
286
  Find.prune if ignore_file?(File.basename(path))
284
287
 
285
- rel_path = path.gsub(target, '')
286
- link_name = File.join(link_path, rel_path)
287
- create_link(path, link_name)
288
+ rel_path = path.relative_path_from(old.realpath)
289
+ link_name = new + rel_path
290
+
291
+ # puts "#{link_name} -> #{old + rel_path}"
292
+ create_link(old + rel_path, link_name)
288
293
 
289
- Find.prune if File.directory?(path)
294
+ Find.prune if path.directory?
290
295
  end
291
296
  end
292
297
 
@@ -306,78 +311,83 @@ module Sundae
306
311
 
307
312
  # Dispatch calls to create_directory_link and create_file_link.
308
313
  #
309
- def self.create_link(target, link_name)
310
- if File.directory?(target)
314
+ def self.create_link(old, new)
315
+ old = Pathname.new(old)
316
+ new = Pathname.new(new)
317
+
318
+ if old.directory?
311
319
  begin
312
- create_directory_link(target, link_name)
320
+ create_directory_link(old, new)
313
321
  rescue => message
314
322
  puts message
315
323
  end
316
- elsif File.file?(target)
317
- create_file_link(target, link_name)
324
+ elsif old.file?
325
+ create_file_link(old, new)
318
326
  end
319
327
  end
320
328
 
321
- # Create a symbolic link to <em>target</em> from <em>link_name</em>.
329
+ # Create a symbolic link to <em>old</em> from <em>new</em>.
322
330
  #
323
- def self.create_file_link(target, link_name)
324
- raise ArgumentError, "#{target} does not exist" unless File.file?(target)
325
- if File.exist?(link_name)
326
- raise ArgumentError, "#{link_name} cannot be overwritten for #{target}." unless File.symlink?(link_name)
327
- if (not File.exist?(File.readlink(link_name)))
328
- FileUtils.ln_sf(target, link_name)
329
- else
330
- unless (File.expand_path(File.readlink(link_name)) == File.expand_path(target))
331
- raise ArgumentError, "#{link_name} points to #{File.readlink(link_name)}, not #{target}" unless File.symlink?(link_name)
332
- end
333
- end
331
+ def self.create_file_link(old, new)
332
+ old = Pathname.new(old)
333
+ new = Pathname.new(new)
334
+
335
+ raise ArgumentError, "#{old} does not exist" unless old.file? || old.symlink?
336
+ if new.symlink?
337
+ raise ArgumentError, "#{new.to_s} cannot be overwritten for #{old}: points to #{new.readlink.to_s}" unless new.readlink.to_s == old.to_s
334
338
  else
335
- FileUtils.ln_s(target, link_name)
339
+ raise ArgumentError, "#{new} cannot be overwritten for #{old}." if new.exist?
340
+ new.make_symlink(old)
336
341
  end
337
342
  end
338
343
 
339
- # Create a symbolic link to the directory at <em>target</em> from
340
- # <em>link_name</em>, unless <em>link_name</em> already exists. In that case,
344
+ # Create a symbolic link to the directory at <em>old</em> from
345
+ # <em>new</em>, unless <em>new</em> already exists. In that case,
341
346
  # create a directory and recursively run minimally_create_links.
342
347
  #
343
- def self.create_directory_link(target, link_name)
344
- raise ArgumentError unless File.directory?(target)
345
- if (not File.exist?(link_name)) ||
346
- (File.symlink?(link_name) && (not File.exist?(File.readlink(link_name))))
347
- FileUtils.ln_sf(target, link_name)
348
+ def self.create_directory_link(old, new)
349
+ old = Pathname.new(old)
350
+ new = Pathname.new(new)
351
+
352
+ raise ArgumentError unless old.directory?
353
+ if not new.exist? || new.symlink?
354
+ new.make_symlink(old)
348
355
  else
349
- case File.ftype(link_name)
356
+ case new.ftype
350
357
  when 'file'
351
- raise "Could not link #{link_name} to #{target}: target exists."
358
+ raise "Could not link #{new} to #{old}: old exists."
352
359
  when 'directory'
353
- minimally_create_links(target, link_name)
360
+ minimally_create_links(old, new)
354
361
  when 'link'
355
- case File.ftype(File.readlink(link_name))
362
+ case new.realpath.ftype
356
363
  when 'file'
357
- raise "Could not link #{link_name} to #{target}: another link exists there."
364
+ raise "Could not link #{new} to #{old}: another link exists there."
358
365
  when 'directory'
359
- combine_directories(link_name, target, File.readlink(link_name))
366
+ combine_directories(old, new.readlink, new)
360
367
  end
361
368
  end
362
369
  end
363
370
  end
364
371
 
365
372
  # Create a directory and create links in it pointing to
366
- # <em>target_path1</em> and <em>target_path2</em>.
373
+ # <em>old1</em> and <em>old2</em>.
367
374
  #
368
- def self.combine_directories(link_name, target_path1, target_path2)
369
- raise unless File.symlink?(link_name)
370
- return if target_path1 == target_path2
375
+ def self.combine_directories(old1, old2, new)
376
+ new = Pathname.new(new)
377
+ old1 = Pathname.new(old1).expand_path
378
+ old2 = Pathname.new(old2).expand_path
379
+
380
+ raise "combine_directories in #{new}" unless new.symlink?
381
+ return if old1 == old2
371
382
 
372
- FileUtils.rm(link_name)
373
- FileUtils.mkdir_p(link_name)
374
- minimally_create_links(target_path1, link_name)
375
- minimally_create_links(target_path2, link_name)
383
+ new.delete
384
+ new.mkpath
385
+ minimally_create_links(old1, new)
386
+ minimally_create_links(old2, new)
376
387
  end
377
388
 
378
389
  def self.update_filesystem
379
- remove_dead_links
380
- remove_generated_files
390
+ remove_filesystem
381
391
  create_filesystem
382
392
  end
383
393
 
data/test/test_sundae.rb CHANGED
@@ -58,7 +58,7 @@ class TestSundae < Test::Unit::TestCase
58
58
  d2 = @@mnts_dir + 'c1/d2'
59
59
  link = @@sandbox + 'link'
60
60
  FileUtils.ln_s(d1, link)
61
- Sundae.combine_directories(link, d1, d2)
61
+ Sundae.combine_directories(d1, d2, link)
62
62
  assert File.symlink?(link + 'f11')
63
63
  end
64
64
 
@@ -162,7 +162,8 @@ class TestSundae < Test::Unit::TestCase
162
162
  end
163
163
 
164
164
  def test_class_mnts_in_path
165
- assert_equal ['c1/d1', 'c1/d2', 'c2/d1', 'c2/d3'].map {|x| Pathname.new(x)},
165
+ md = Pathname.new(@@mnts_dir)
166
+ assert_equal ['c1/d1', 'c1/d2', 'c2/d1', 'c2/d3'].map {|x| (md + x).expand_path},
166
167
  Sundae.mnts_in_path(@@path1)
167
168
  end
168
169
 
@@ -175,13 +176,13 @@ class TestSundae < Test::Unit::TestCase
175
176
  assert (@@sandbox + 'perm_file').exist?
176
177
  end
177
178
 
178
- def test_class_remove_generated_directories
179
- Sundae.generated_directories.each { |d| FileUtils.mkdir_p(d) }
180
- Sundae.remove_generated_directories
181
- Sundae.generated_directories.each do |d|
182
- assert ! File.exist?(d)
183
- end
184
- end
179
+ # def test_class_remove_generated_directories
180
+ # Sundae.generated_directories.each { |d| FileUtils.mkdir_p(d) }
181
+ # Sundae.remove_generated_directories
182
+ # Sundae.generated_directories.each do |d|
183
+ # assert ! File.exist?(d)
184
+ # end
185
+ # end
185
186
 
186
187
  def test_class_root_path
187
188
  assert_equal @@mnts_dir +'c1', Sundae.root_path(@@mnts_dir + 'c1')
data/version.txt CHANGED
@@ -1 +1 @@
1
- 1.0.4
1
+ 1.0.5
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sundae
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.4
4
+ version: 1.0.5
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,33 +9,43 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-04-13 00:00:00.000000000 Z
12
+ date: 2012-11-21 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: highline
16
- requirement: &82655870 !ruby/object:Gem::Requirement
16
+ requirement: !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ! '>='
20
20
  - !ruby/object:Gem::Version
21
- version: 1.6.11
21
+ version: 1.6.12
22
22
  type: :runtime
23
23
  prerelease: false
24
- version_requirements: *82655870
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: 1.6.12
25
30
  - !ruby/object:Gem::Dependency
26
31
  name: configatron
27
- requirement: &82654320 !ruby/object:Gem::Requirement
32
+ requirement: !ruby/object:Gem::Requirement
28
33
  none: false
29
34
  requirements:
30
35
  - - ! '>='
31
36
  - !ruby/object:Gem::Version
32
- version: 2.9.0
37
+ version: 2.9.1
33
38
  type: :runtime
34
39
  prerelease: false
35
- version_requirements: *82654320
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: 2.9.1
36
46
  - !ruby/object:Gem::Dependency
37
47
  name: rdoc
38
- requirement: &82653700 !ruby/object:Gem::Requirement
48
+ requirement: !ruby/object:Gem::Requirement
39
49
  none: false
40
50
  requirements:
41
51
  - - ! '>='
@@ -43,48 +53,46 @@ dependencies:
43
53
  version: '3.12'
44
54
  type: :runtime
45
55
  prerelease: false
46
- version_requirements: *82653700
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ! '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '3.12'
47
62
  - !ruby/object:Gem::Dependency
48
63
  name: bones
49
- requirement: &82653190 !ruby/object:Gem::Requirement
64
+ requirement: !ruby/object:Gem::Requirement
50
65
  none: false
51
66
  requirements:
52
67
  - - ! '>='
53
68
  - !ruby/object:Gem::Version
54
- version: 3.7.3
69
+ version: 3.8.0
55
70
  type: :development
56
71
  prerelease: false
57
- version_requirements: *82653190
72
+ version_requirements: !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ! '>='
76
+ - !ruby/object:Gem::Version
77
+ version: 3.8.0
58
78
  description: Mix collections of files while maintaining complete separation.
59
79
  email: don@ohspite.net
60
80
  executables:
61
- - !binary |-
62
- c3VuZGFl
81
+ - sundae
63
82
  extensions: []
64
83
  extra_rdoc_files:
65
- - !binary |-
66
- UkVBRE1FLnJkb2M=
67
- - !binary |-
68
- YmluL3N1bmRhZQ==
84
+ - README.rdoc
85
+ - bin/sundae
69
86
  files:
70
- - !binary |-
71
- LmdpdGlnbm9yZQ==
72
- - !binary |-
73
- Q0hBTkdFTE9H
74
- - !binary |-
75
- Q09QWUlORw==
76
- - !binary |-
77
- UkVBRE1FLnJkb2M=
78
- - !binary |-
79
- UmFrZWZpbGU=
80
- - !binary |-
81
- YmluL3N1bmRhZQ==
82
- - !binary |-
83
- bGliL3N1bmRhZS5yYg==
84
- - !binary |-
85
- dGVzdC90ZXN0X3N1bmRhZS5yYg==
86
- - !binary |-
87
- dmVyc2lvbi50eHQ=
87
+ - .gitignore
88
+ - CHANGELOG
89
+ - COPYING
90
+ - README.rdoc
91
+ - Rakefile
92
+ - bin/sundae
93
+ - lib/sundae.rb
94
+ - test/test_sundae.rb
95
+ - version.txt
88
96
  homepage: https://github.com/ohspite/sundae
89
97
  licenses: []
90
98
  post_install_message:
@@ -107,7 +115,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
107
115
  version: '0'
108
116
  requirements: []
109
117
  rubyforge_project: sundae
110
- rubygems_version: 1.8.15
118
+ rubygems_version: 1.8.24
111
119
  signing_key:
112
120
  specification_version: 3
113
121
  summary: Mix collections of files while maintaining complete separation.