sundae 1.0.4 → 1.0.5
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/README.rdoc +27 -4
- data/lib/sundae.rb +99 -89
- data/test/test_sundae.rb +10 -9
- data/version.txt +1 -1
- metadata +46 -38
data/README.rdoc
CHANGED
@@ -67,7 +67,11 @@ this:
|
|
67
67
|
| | |-- real_files_and_dirs
|
68
68
|
| | ` ...
|
69
69
|
| |-- mnt2/
|
70
|
-
|
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 <-- "
|
118
|
-
| |--
|
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
|
-
|
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
|
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
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
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
|
-
|
160
|
-
|
161
|
-
@paths.each do |path|
|
165
|
+
@paths.map do |path|
|
162
166
|
next unless path.exist?
|
163
|
-
|
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.
|
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
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
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
|
268
|
-
# there is currently no file at <em>
|
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
|
273
|
+
# link location and _old_ in a new directory and proceed
|
271
274
|
# recursively.
|
272
275
|
#
|
273
|
-
def self.minimally_create_links(
|
274
|
-
|
275
|
-
|
276
|
+
def self.minimally_create_links(old, new)
|
277
|
+
old = Pathname.new(old)
|
278
|
+
new = Pathname.new(new)
|
276
279
|
|
277
|
-
unless
|
278
|
-
raise "attempt to create links from missing directory: " +
|
280
|
+
unless old.exist?
|
281
|
+
raise "attempt to create links from missing directory: " + old
|
279
282
|
end
|
280
283
|
|
281
|
-
|
282
|
-
next if path ==
|
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.
|
286
|
-
link_name =
|
287
|
-
|
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
|
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(
|
310
|
-
|
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(
|
320
|
+
create_directory_link(old, new)
|
313
321
|
rescue => message
|
314
322
|
puts message
|
315
323
|
end
|
316
|
-
elsif
|
317
|
-
create_file_link(
|
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>
|
329
|
+
# Create a symbolic link to <em>old</em> from <em>new</em>.
|
322
330
|
#
|
323
|
-
def self.create_file_link(
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
|
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
|
-
|
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>
|
340
|
-
# <em>
|
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(
|
344
|
-
|
345
|
-
|
346
|
-
|
347
|
-
|
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
|
356
|
+
case new.ftype
|
350
357
|
when 'file'
|
351
|
-
raise "Could not link #{
|
358
|
+
raise "Could not link #{new} to #{old}: old exists."
|
352
359
|
when 'directory'
|
353
|
-
minimally_create_links(
|
360
|
+
minimally_create_links(old, new)
|
354
361
|
when 'link'
|
355
|
-
case
|
362
|
+
case new.realpath.ftype
|
356
363
|
when 'file'
|
357
|
-
raise "Could not link #{
|
364
|
+
raise "Could not link #{new} to #{old}: another link exists there."
|
358
365
|
when 'directory'
|
359
|
-
combine_directories(
|
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>
|
373
|
+
# <em>old1</em> and <em>old2</em>.
|
367
374
|
#
|
368
|
-
def self.combine_directories(
|
369
|
-
|
370
|
-
|
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
|
-
|
373
|
-
|
374
|
-
minimally_create_links(
|
375
|
-
minimally_create_links(
|
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
|
-
|
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(
|
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
|
-
|
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
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
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.
|
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
|
+
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-
|
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:
|
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.
|
21
|
+
version: 1.6.12
|
22
22
|
type: :runtime
|
23
23
|
prerelease: false
|
24
|
-
version_requirements:
|
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:
|
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.
|
37
|
+
version: 2.9.1
|
33
38
|
type: :runtime
|
34
39
|
prerelease: false
|
35
|
-
version_requirements:
|
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:
|
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:
|
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:
|
64
|
+
requirement: !ruby/object:Gem::Requirement
|
50
65
|
none: false
|
51
66
|
requirements:
|
52
67
|
- - ! '>='
|
53
68
|
- !ruby/object:Gem::Version
|
54
|
-
version: 3.
|
69
|
+
version: 3.8.0
|
55
70
|
type: :development
|
56
71
|
prerelease: false
|
57
|
-
version_requirements:
|
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
|
-
-
|
62
|
-
c3VuZGFl
|
81
|
+
- sundae
|
63
82
|
extensions: []
|
64
83
|
extra_rdoc_files:
|
65
|
-
-
|
66
|
-
|
67
|
-
- !binary |-
|
68
|
-
YmluL3N1bmRhZQ==
|
84
|
+
- README.rdoc
|
85
|
+
- bin/sundae
|
69
86
|
files:
|
70
|
-
-
|
71
|
-
|
72
|
-
-
|
73
|
-
|
74
|
-
-
|
75
|
-
|
76
|
-
-
|
77
|
-
|
78
|
-
-
|
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.
|
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.
|