sundae 1.0.1 → 1.0.2
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/.gitignore +19 -0
- data/README.rdoc +45 -25
- data/lib/sundae.rb +108 -67
- data/test/test_sundae.rb +53 -57
- data/unison/common +17 -0
- data/unison/mt_example.prf +12 -0
- data/version.txt +1 -1
- metadata +16 -10
data/.gitignore
ADDED
data/README.rdoc
CHANGED
|
@@ -38,6 +38,10 @@ works. Like this:
|
|
|
38
38
|
~> ls
|
|
39
39
|
bin Desktop doc etc lib local mnt share src tmp var WualaDrive
|
|
40
40
|
|
|
41
|
+
And that's it. When called, Sundae creates links so that you can
|
|
42
|
+
work on your files from seperate parts of life as if they were side
|
|
43
|
+
by side.
|
|
44
|
+
|
|
41
45
|
== Install
|
|
42
46
|
|
|
43
47
|
sudo gem install sundae
|
|
@@ -66,16 +70,22 @@ this:
|
|
|
66
70
|
`-- collection2/
|
|
67
71
|
` ...
|
|
68
72
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
+
Sundae will act on all of the <em>mnt</em>s--subdirectories of the
|
|
74
|
+
<em>collection</em>s, that is, the sub-subdirectories of the
|
|
75
|
+
<em>path</em>. The "collections" are only there to facilitate
|
|
76
|
+
grouping common files and syncronizing them between computers.
|
|
73
77
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
78
|
+
By default, all of the contents in each of the <em>mnt</em>s are
|
|
79
|
+
placed in the user's home directory. This can be altered by creating
|
|
80
|
+
a file called <tt>.sundae_path</tt> in the top of the <em>mnt</em>;
|
|
81
|
+
the file should contain one line, which is the absolute path to where
|
|
82
|
+
that directory should be "mounted."
|
|
83
|
+
|
|
84
|
+
There's one exception to the "by default everything is placed in the
|
|
85
|
+
home directory" rule. If the mnt directory starts with "dot-" or
|
|
86
|
+
"dot_" then it is placed in the dot folder formed using the rest of
|
|
87
|
+
the name. For example, the files in a "dot-ssh" mnt are placed in
|
|
88
|
+
"~/.ssh" by default.
|
|
79
89
|
|
|
80
90
|
For example, the hierarchy in my <em>path</em>s looks sort of like this:
|
|
81
91
|
|
|
@@ -86,13 +96,13 @@ For example, the hierarchy in my <em>path</em>s looks sort of like this:
|
|
|
86
96
|
| | |-- etc/ (~/etc will point here)
|
|
87
97
|
| | ` ...
|
|
88
98
|
| |-- dot-unison
|
|
89
|
-
| | |-- .sundae_path (says "~/.unison")
|
|
99
|
+
| | |-- .sundae_path (says "~/.unison", but not required)
|
|
90
100
|
| | |-- default.prf (~/.unison/default.prf will point here)
|
|
91
101
|
| | `
|
|
92
102
|
| |
|
|
93
103
|
|-- osx/
|
|
94
|
-
| |-- home_library/
|
|
95
|
-
| | |-- .sundae_path
|
|
104
|
+
| |-- home_library/
|
|
105
|
+
| | |-- .sundae_path (says "~/Library", required)
|
|
96
106
|
| | `-- Library-Keyboard_Layouts/
|
|
97
107
|
| | `-- Keyboard Layouts/
|
|
98
108
|
| | ` Colemak.keylayout
|
|
@@ -112,20 +122,30 @@ For example, the hierarchy in my <em>path</em>s looks sort of like this:
|
|
|
112
122
|
| ` ...
|
|
113
123
|
` ...
|
|
114
124
|
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
By default, all of the contents in each of the <em>mnt</em>s are
|
|
121
|
-
placed in the user's home directory. This can be altered by
|
|
122
|
-
creating a file called <tt>.sundae_path</tt> in the top of the
|
|
123
|
-
<em>mnt</em>; the file should contain one line, which is the
|
|
124
|
-
absolute path to where that directory should be "mounted."
|
|
125
|
+
Why is this double layer "collection" stuff going on? Because while
|
|
126
|
+
most of the time you can share a whole folder between computers,
|
|
127
|
+
sometimes you want to mix your config files into a folder that also
|
|
128
|
+
contains nonsymlinked files.
|
|
125
129
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
130
|
+
For example, your ~/.ssh folder probably has a public and private key
|
|
131
|
+
that you want to stay unique to that machine, but you might want to
|
|
132
|
+
mix in a "config" file that has host aliases that you share between
|
|
133
|
+
machines. You can put the file in "~/mnt/nix/.ssh/config" in the
|
|
134
|
+
above example, and it will get created alongside the other static
|
|
135
|
+
files in the "~/.ssh/" directory.
|
|
136
|
+
|
|
137
|
+
However, every time you run sundae it will check the target locations
|
|
138
|
+
of each file and directory (recursively) in every mnt directory for
|
|
139
|
+
dangling symlinks and other stuff that sundae might have created. If
|
|
140
|
+
you put the the file in "~/mnt/nix/dot-ssh/config", it will be placed
|
|
141
|
+
in the correct place and only "config" will be checked when sundae is
|
|
142
|
+
run (not all of the other files in "~/.ssh/").
|
|
143
|
+
|
|
144
|
+
It obviously doesn't make much of a speed difference in this case, but
|
|
145
|
+
if you're mixing in one file into "~/a/b/c/d/file", and there are lots
|
|
146
|
+
of files beneath "~/a/", then you don't want sundae to look through
|
|
147
|
+
everything every time it runs. Just put it in a mnt directory with a
|
|
148
|
+
<tt>.sundae_path</tt> of "~/a/b/c/d".
|
|
129
149
|
|
|
130
150
|
== Author
|
|
131
151
|
<don@ohspite.net>
|
data/lib/sundae.rb
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
require 'configatron'
|
|
3
3
|
require 'fileutils'
|
|
4
4
|
require 'find'
|
|
5
|
+
require 'pathname'
|
|
5
6
|
|
|
6
7
|
# A collection of methods to mix the contents of several directories
|
|
7
8
|
# together using symbolic links.
|
|
@@ -13,20 +14,21 @@ module Sundae
|
|
|
13
14
|
# :startdoc:
|
|
14
15
|
VERSION = ::File.read(PATH + 'version.txt').strip
|
|
15
16
|
|
|
16
|
-
DEFAULT_CONFIG_FILE =
|
|
17
|
+
DEFAULT_CONFIG_FILE = (Pathname.new(Dir.home) + '.sundae').expand_path
|
|
17
18
|
|
|
18
19
|
@config_file = DEFAULT_CONFIG_FILE
|
|
19
20
|
|
|
20
21
|
# Read configuration from <tt>.sundae</tt>.
|
|
21
22
|
#
|
|
22
23
|
def self.load_config_file(config_file = DEFAULT_CONFIG_FILE)
|
|
23
|
-
config_file ||= DEFAULT_CONFIG_FILE
|
|
24
|
-
config_file =
|
|
24
|
+
config_file ||= DEFAULT_CONFIG_FILE # if nil is passed
|
|
25
|
+
config_file = Pathname.new(config_file).expand_path
|
|
26
|
+
config_file += '.sundae' if config_file.directory?
|
|
25
27
|
|
|
26
|
-
create_template_config_file(config_file) unless
|
|
28
|
+
create_template_config_file(config_file) unless config_file.file?
|
|
27
29
|
|
|
28
30
|
load(config_file)
|
|
29
|
-
configatron.paths.map! { |p|
|
|
31
|
+
configatron.paths.map! { |p| Pathname.new(p).expand_path }
|
|
30
32
|
|
|
31
33
|
# An array which lists the directories where mnts are stored.
|
|
32
34
|
@paths = configatron.paths
|
|
@@ -39,13 +41,14 @@ module Sundae
|
|
|
39
41
|
# asking the user.
|
|
40
42
|
#
|
|
41
43
|
def self.create_template_config_file(config_file)
|
|
44
|
+
config_file = Pathname.new(config_file).expand_path
|
|
42
45
|
loop do
|
|
43
46
|
print "#{config_file} does not exist. Create template there? (y/n): "
|
|
44
47
|
ans = gets.downcase.strip
|
|
45
48
|
if ans == "y" || ans == "yes"
|
|
46
49
|
File.open(config_file, "w") do |f|
|
|
47
50
|
f.puts <<-EOM.gsub(/^ {14}/, '')
|
|
48
|
-
# -*-Ruby-*-
|
|
51
|
+
# -*-Ruby-*-
|
|
49
52
|
|
|
50
53
|
# An array which lists the directories where mnts are stored.
|
|
51
54
|
configatron.paths = ["~/mnt"]
|
|
@@ -76,13 +79,15 @@ module Sundae
|
|
|
76
79
|
# ignored (i.e., no link will be made pointing to it).
|
|
77
80
|
#
|
|
78
81
|
def self.ignore_file?(file) # :doc:
|
|
79
|
-
|
|
80
|
-
|
|
82
|
+
file = Pathname.new(file)
|
|
83
|
+
basename = file.basename.to_s
|
|
84
|
+
return true if basename =~ /^\.\.?$/
|
|
85
|
+
return true if basename == ".sundae_path"
|
|
81
86
|
@ignore_rules.each do |r|
|
|
82
87
|
if r.kind_of? Regexp
|
|
83
|
-
return true if
|
|
88
|
+
return true if basename =~ r
|
|
84
89
|
else
|
|
85
|
-
return true if
|
|
90
|
+
return true if file.fnmatch(r)
|
|
86
91
|
end
|
|
87
92
|
end
|
|
88
93
|
return false
|
|
@@ -92,12 +97,19 @@ module Sundae
|
|
|
92
97
|
# where in the file system links should be created for this mnt.
|
|
93
98
|
#
|
|
94
99
|
def self.install_location(mnt)
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
100
|
+
mnt = Pathname.new(mnt).expand_path
|
|
101
|
+
mnt_config = mnt + '.sundae_path'
|
|
102
|
+
if mnt_config.exist?
|
|
103
|
+
return Pathname.new(mnt_config.readlines[0].strip).expand_path
|
|
98
104
|
end
|
|
99
105
|
|
|
100
|
-
|
|
106
|
+
base = mnt.basename.to_s
|
|
107
|
+
match = (/dot[-_](.*)/).match(base)
|
|
108
|
+
if match
|
|
109
|
+
return Pathname.new(Dir.home) + ('.' + match[1])
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
return Pathname.new(Dir.home)
|
|
101
113
|
end
|
|
102
114
|
|
|
103
115
|
# Return an array of all paths in the file system where links will
|
|
@@ -111,11 +123,12 @@ module Sundae
|
|
|
111
123
|
# as an array.
|
|
112
124
|
#
|
|
113
125
|
def self.mnts_in_path(path)
|
|
126
|
+
Pathname.new(path).expand_path
|
|
114
127
|
mnts = []
|
|
115
|
-
collections =
|
|
128
|
+
collections = path.children(false).delete_if {|c| c.to_s =~ /^\./}
|
|
116
129
|
collections.each do |c|
|
|
117
|
-
collection_mnts =
|
|
118
|
-
collection_mnts.map! { |mnt|
|
|
130
|
+
collection_mnts = (path + c).children(false).delete_if {|c| c.to_s =~ /^\./}
|
|
131
|
+
collection_mnts.map! { |mnt| (c + mnt) }
|
|
119
132
|
mnts |= collection_mnts # |= is the union
|
|
120
133
|
end
|
|
121
134
|
|
|
@@ -128,87 +141,109 @@ module Sundae
|
|
|
128
141
|
mnts = []
|
|
129
142
|
|
|
130
143
|
@paths.each do |path|
|
|
131
|
-
next unless
|
|
132
|
-
mnts |= mnts_in_path(path).map { |mnt|
|
|
144
|
+
next unless path.exist?
|
|
145
|
+
mnts |= mnts_in_path(path).map { |mnt| path + mnt } # |= is the union operator
|
|
133
146
|
end
|
|
134
|
-
|
|
135
147
|
return mnts
|
|
136
148
|
end
|
|
137
149
|
|
|
138
|
-
# Return all subdirectories
|
|
139
|
-
# are the 'mirror' directories that are
|
|
150
|
+
# Return all subdirectories and files in the mnts returned by
|
|
151
|
+
# all_mnts. These are the 'mirror' files and directories that are
|
|
152
|
+
# generated by sundae.
|
|
140
153
|
#
|
|
141
|
-
def self.
|
|
154
|
+
def self.generated_files
|
|
142
155
|
dirs = Array.new
|
|
143
156
|
|
|
144
157
|
all_mnts.each do |mnt|
|
|
145
|
-
mnt_dirs =
|
|
158
|
+
mnt_dirs = mnt.children(false).delete_if { |e| ignore_file?(e) }
|
|
146
159
|
mnt_dirs.each do |dir|
|
|
147
|
-
dirs <<
|
|
160
|
+
dirs << (install_location(mnt) + dir)
|
|
148
161
|
end
|
|
149
162
|
end
|
|
150
163
|
|
|
151
|
-
return dirs.sort.uniq
|
|
164
|
+
return dirs.sort.uniq#.select { |d| d.directory? }
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
# Return all subdirectories of the mnts returned by all_mnts. These
|
|
168
|
+
# are the 'mirror' directories that are generated by sundae.
|
|
169
|
+
#
|
|
170
|
+
def self.generated_directories
|
|
171
|
+
generated_files.select {|f| f.directory?}
|
|
152
172
|
end
|
|
153
173
|
|
|
154
174
|
# Check for symlinks in the base directories that are missing their
|
|
155
175
|
# targets.
|
|
156
176
|
#
|
|
157
177
|
def self.remove_dead_links
|
|
158
|
-
removed_list = []
|
|
159
178
|
install_locations.each do |location|
|
|
160
|
-
next unless
|
|
161
|
-
files =
|
|
179
|
+
next unless location.exist?
|
|
180
|
+
files = location.entries.map { |f| location + f }
|
|
162
181
|
files.each do |file|
|
|
163
|
-
next unless
|
|
164
|
-
next if
|
|
165
|
-
|
|
166
|
-
|
|
182
|
+
next unless file.symlink?
|
|
183
|
+
next if file.readlink.exist?
|
|
184
|
+
next unless root_path(file.readlink)
|
|
185
|
+
file.delete
|
|
167
186
|
end
|
|
168
187
|
end
|
|
169
|
-
return removed_list
|
|
170
188
|
end
|
|
171
189
|
|
|
190
|
+
# Search through _directory_ and return the first static file found,
|
|
191
|
+
# nil otherwise.
|
|
192
|
+
#
|
|
193
|
+
def self.find_static_file(directory)
|
|
194
|
+
directory = Pathname.new(directory).expand_path
|
|
195
|
+
|
|
196
|
+
directory.find do |path|
|
|
197
|
+
return path if path.exist? && path.ftype == 'file'
|
|
198
|
+
end
|
|
199
|
+
return nil
|
|
200
|
+
end
|
|
201
|
+
|
|
172
202
|
# Delete each generated directory if there aren't any real files in
|
|
173
203
|
# them.
|
|
174
204
|
#
|
|
175
205
|
def self.remove_generated_directories
|
|
176
|
-
removed_list = []
|
|
177
206
|
generated_directories.each do |dir|
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
if sf = find_static_file(dir)
|
|
183
|
-
|
|
184
|
-
else
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
end
|
|
207
|
+
# don't get rid of the linked config file
|
|
208
|
+
next if dir.basename.to_s == '.sundae'
|
|
209
|
+
remove_generated_stuff dir
|
|
210
|
+
|
|
211
|
+
# if sf = find_static_file(dir)
|
|
212
|
+
# puts "found static file: #{sf}"
|
|
213
|
+
# else
|
|
214
|
+
# dir.rmtree
|
|
215
|
+
# end
|
|
188
216
|
end
|
|
189
|
-
return removed_list
|
|
190
217
|
end
|
|
191
218
|
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
return path if File.exist?(path) && File.ftype(path) == 'file'
|
|
219
|
+
def self.remove_generated_files
|
|
220
|
+
generated_files.each do |fod|
|
|
221
|
+
# don't get rid of the linked config file
|
|
222
|
+
next if fod.basename.to_s == '.sundae'
|
|
223
|
+
remove_generated_stuff fod
|
|
198
224
|
end
|
|
199
|
-
return nil
|
|
200
225
|
end
|
|
201
226
|
|
|
227
|
+
def self.remove_generated_stuff(fod)
|
|
228
|
+
return unless fod.exist?
|
|
229
|
+
if fod.ftype == 'directory'
|
|
230
|
+
fod.each_child do |c|
|
|
231
|
+
remove_generated_stuff c
|
|
232
|
+
end
|
|
233
|
+
fod.rmdir if fod.children.empty?
|
|
234
|
+
else
|
|
235
|
+
return unless fod.symlink?
|
|
236
|
+
fod.delete if root_path(fod.readlink) # try to only delete sundae links
|
|
237
|
+
end
|
|
238
|
+
end
|
|
239
|
+
|
|
202
240
|
# Call minimally_create_links for each mnt.
|
|
203
241
|
#
|
|
204
242
|
def self.create_filesystem
|
|
205
|
-
mnt_list = []
|
|
206
243
|
all_mnts.each do |mnt|
|
|
207
|
-
|
|
244
|
+
install_location(mnt).expand_path.mkpath
|
|
208
245
|
minimally_create_links(mnt, install_location(mnt))
|
|
209
|
-
mnt_list << mnt
|
|
210
246
|
end
|
|
211
|
-
return mnt_list
|
|
212
247
|
end
|
|
213
248
|
|
|
214
249
|
# For each directory and file in _target_, create a link at <em>link_name</em>. If
|
|
@@ -240,11 +275,15 @@ module Sundae
|
|
|
240
275
|
# Starting at _dir_, walk up the directory hierarchy and return the
|
|
241
276
|
# directory that is contained in _@paths_.
|
|
242
277
|
#
|
|
243
|
-
def self.root_path(
|
|
244
|
-
|
|
278
|
+
def self.root_path(path)
|
|
279
|
+
path = Pathname.new(path).expand_path
|
|
280
|
+
last = path
|
|
281
|
+
path.ascend do |v|
|
|
282
|
+
return last if @paths.include? v
|
|
283
|
+
last = v
|
|
284
|
+
end
|
|
245
285
|
|
|
246
|
-
|
|
247
|
-
return (@paths.include?(parent)) ? dir : root_path(parent)
|
|
286
|
+
return nil
|
|
248
287
|
end
|
|
249
288
|
|
|
250
289
|
# Dispatch calls to create_directory_link and create_file_link.
|
|
@@ -266,7 +305,7 @@ module Sundae
|
|
|
266
305
|
def self.create_file_link(target, link_name)
|
|
267
306
|
raise ArgumentError, "#{target} does not exist" unless File.file?(target)
|
|
268
307
|
if File.exist?(link_name)
|
|
269
|
-
raise ArgumentError, "#{link_name} cannot be overwritten" unless File.symlink?(link_name)
|
|
308
|
+
raise ArgumentError, "#{link_name} cannot be overwritten for #{target}." unless File.symlink?(link_name)
|
|
270
309
|
if (not File.exist?(File.readlink(link_name)))
|
|
271
310
|
FileUtils.ln_sf(target, link_name)
|
|
272
311
|
else
|
|
@@ -285,18 +324,19 @@ module Sundae
|
|
|
285
324
|
#
|
|
286
325
|
def self.create_directory_link(target, link_name)
|
|
287
326
|
raise ArgumentError unless File.directory?(target)
|
|
288
|
-
if (not File.exist?(link_name)) ||
|
|
327
|
+
if (not File.exist?(link_name)) ||
|
|
328
|
+
(File.symlink?(link_name) && (not File.exist?(File.readlink(link_name))))
|
|
289
329
|
FileUtils.ln_sf(target, link_name)
|
|
290
330
|
else
|
|
291
331
|
case File.ftype(link_name)
|
|
292
332
|
when 'file'
|
|
293
|
-
raise "Could not link #{
|
|
333
|
+
raise "Could not link #{link_name} to #{target}: target exists."
|
|
294
334
|
when 'directory'
|
|
295
335
|
minimally_create_links(target, link_name)
|
|
296
336
|
when 'link'
|
|
297
337
|
case File.ftype(File.readlink(link_name))
|
|
298
338
|
when 'file'
|
|
299
|
-
raise "Could not link #{
|
|
339
|
+
raise "Could not link #{link_name} to #{target}: another link exists there."
|
|
300
340
|
when 'directory'
|
|
301
341
|
combine_directories(link_name, target, File.readlink(link_name))
|
|
302
342
|
end
|
|
@@ -308,6 +348,7 @@ module Sundae
|
|
|
308
348
|
# <em>target_path1</em> and <em>target_path2</em>.
|
|
309
349
|
#
|
|
310
350
|
def self.combine_directories(link_name, target_path1, target_path2)
|
|
351
|
+
raise unless File.symlink?(link_name)
|
|
311
352
|
return if target_path1 == target_path2
|
|
312
353
|
|
|
313
354
|
FileUtils.rm(link_name)
|
|
@@ -318,13 +359,13 @@ module Sundae
|
|
|
318
359
|
|
|
319
360
|
def self.update_filesystem
|
|
320
361
|
remove_dead_links
|
|
321
|
-
|
|
362
|
+
remove_generated_files
|
|
322
363
|
create_filesystem
|
|
323
364
|
end
|
|
324
365
|
|
|
325
366
|
def self.remove_filesystem
|
|
326
367
|
remove_dead_links
|
|
327
|
-
|
|
368
|
+
remove_generated_files
|
|
328
369
|
end
|
|
329
370
|
|
|
330
371
|
# Return an array of mnts that are installing to +path+.
|
data/test/test_sundae.rb
CHANGED
|
@@ -3,41 +3,34 @@ require 'test/unit'
|
|
|
3
3
|
$:.unshift File.join(File.dirname(__FILE__), "..", "bin") # add ../bin to the Ruby library path
|
|
4
4
|
$:.unshift File.join(File.dirname(__FILE__), "..", "lib") # ../lib
|
|
5
5
|
require 'sundae'
|
|
6
|
+
require 'pathname'
|
|
6
7
|
|
|
7
8
|
class TestSundae < Test::Unit::TestCase
|
|
8
9
|
|
|
9
|
-
@@testdir =
|
|
10
|
-
@@sandbox
|
|
11
|
-
@@static_dir =
|
|
12
|
-
@@mnts_dir
|
|
10
|
+
@@testdir = Pathname.new(__FILE__).parent.expand_path
|
|
11
|
+
@@sandbox = @@testdir + 'sandbox'
|
|
12
|
+
@@static_dir = @@sandbox + 'static'
|
|
13
|
+
@@mnts_dir = @@sandbox + 'mnts'
|
|
13
14
|
|
|
14
15
|
def setup
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
FileUtils.mkdir_p(File.join(@@mnts_dir, 'c2/d3/d31'))
|
|
26
|
-
File.open(File.join(@@mnts_dir, 'c1/d1/f11'), 'w')
|
|
27
|
-
File.open(File.join(@@mnts_dir, 'c1/d1/f12'), 'w')
|
|
28
|
-
File.open(File.join(@@mnts_dir, 'c1/d2/f21'), 'w')
|
|
29
|
-
File.open(File.join(@@mnts_dir, 'c2/d1/f13'), 'w')
|
|
30
|
-
File.open(File.join(@@mnts_dir, 'c2/d1/f14'), 'w')
|
|
31
|
-
File.open(File.join(@@mnts_dir, 'c2/d3/f31'), 'w')
|
|
32
|
-
['c1/d1', 'c1/d2', 'c2/d1', 'c2/d3'].each do |d|
|
|
33
|
-
File.open(File.join(@@mnts_dir, d, '.sundae_path'), 'w') do |f|
|
|
34
|
-
f.puts @@sandbox
|
|
35
|
-
end
|
|
16
|
+
@@sandbox.mkpath
|
|
17
|
+
@@static_dir.mkpath
|
|
18
|
+
|
|
19
|
+
(@@static_dir + 'static').open('w')
|
|
20
|
+
%w(c1 c2 c1/d1 c1/d2 c2/d1 c2/d3 c2/d3/d31).each do |x|
|
|
21
|
+
(@@mnts_dir + x).mkpath
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
%w(c1/d1/f11 c1/d1/f12 c1/d2/f21 c2/d1/f13 c2/d1/f14 c2/d3/f31).each do |x|
|
|
25
|
+
(@@mnts_dir + x).open('w')
|
|
36
26
|
end
|
|
37
27
|
|
|
38
|
-
|
|
28
|
+
%w(c1/d1 c1/d2 c2/d1 c2/d3).each do |d|
|
|
29
|
+
(@@mnts_dir + d + '.sundae_path').open('w') {|f| f.puts @@sandbox}
|
|
30
|
+
end
|
|
39
31
|
|
|
40
|
-
@@
|
|
32
|
+
@@path1 = @@sandbox + 'mnts'
|
|
33
|
+
@@config_file = @@sandbox + '.sundae'
|
|
41
34
|
File.open(@@config_file, 'w+') do |f|
|
|
42
35
|
f.puts "configatron.paths = [\"#{@@path1}\"]"
|
|
43
36
|
f.puts "configatron.ignore_rules = %w("
|
|
@@ -49,24 +42,24 @@ class TestSundae < Test::Unit::TestCase
|
|
|
49
42
|
end
|
|
50
43
|
|
|
51
44
|
def teardown
|
|
52
|
-
|
|
45
|
+
@@sandbox.rmtree
|
|
53
46
|
end
|
|
54
47
|
|
|
55
48
|
def test_class_all_mnts
|
|
56
49
|
all_mnts = Sundae.all_mnts
|
|
57
50
|
mnts = Sundae.mnts_in_path(@@path1)
|
|
58
51
|
mnts.each do |m|
|
|
59
|
-
assert all_mnts.include?(
|
|
52
|
+
assert all_mnts.include?(@@path1 + m)
|
|
60
53
|
end
|
|
61
54
|
end
|
|
62
55
|
|
|
63
56
|
def test_class_combine_directories
|
|
64
|
-
d1
|
|
65
|
-
d2
|
|
66
|
-
link =
|
|
57
|
+
d1 = @@mnts_dir + 'c1/d1'
|
|
58
|
+
d2 = @@mnts_dir + 'c1/d2'
|
|
59
|
+
link = @@sandbox + 'link'
|
|
67
60
|
FileUtils.ln_s(d1, link)
|
|
68
61
|
Sundae.combine_directories(link, d1, d2)
|
|
69
|
-
assert File.symlink?(
|
|
62
|
+
assert File.symlink?(link + 'f11')
|
|
70
63
|
end
|
|
71
64
|
|
|
72
65
|
def test_class_create_directory_link
|
|
@@ -125,6 +118,12 @@ class TestSundae < Test::Unit::TestCase
|
|
|
125
118
|
assert_equal 1, Sundae.generated_directories.size
|
|
126
119
|
end
|
|
127
120
|
|
|
121
|
+
def test_class_generated_files
|
|
122
|
+
Sundae.create_filesystem
|
|
123
|
+
# assert Sundae.generated_files.include?(File.join(@@sandbox, 'f11'))
|
|
124
|
+
assert_equal 7, Sundae.generated_files.size
|
|
125
|
+
end
|
|
126
|
+
|
|
128
127
|
def test_class_ignore_file_eh
|
|
129
128
|
assert Sundae.ignore_file?('.sundae_path')
|
|
130
129
|
assert Sundae.ignore_file?('..')
|
|
@@ -135,45 +134,45 @@ class TestSundae < Test::Unit::TestCase
|
|
|
135
134
|
end
|
|
136
135
|
|
|
137
136
|
def test_class_install_location
|
|
138
|
-
assert_equal Sundae.install_location('/')
|
|
139
|
-
assert_equal Sundae.install_location(
|
|
137
|
+
assert_equal Pathname.new(Dir.home), Sundae.install_location('/')
|
|
138
|
+
assert_equal @@sandbox, Sundae.install_location(@@mnts_dir + 'c1/d1')
|
|
140
139
|
end
|
|
141
140
|
|
|
142
141
|
def test_class_install_locations
|
|
143
|
-
assert_equal
|
|
142
|
+
assert_equal [@@sandbox], Sundae.install_locations
|
|
144
143
|
end
|
|
145
144
|
|
|
146
145
|
def test_class_load_config_file
|
|
147
146
|
sundae_paths = Sundae.instance_variable_get(:@paths)
|
|
148
|
-
assert_equal sundae_paths[0],
|
|
147
|
+
assert_equal sundae_paths[0], Pathname.new(@@path1).expand_path
|
|
149
148
|
end
|
|
150
149
|
|
|
151
150
|
def test_class_minimally_create_links
|
|
152
151
|
c1 = File.join(@@mnts_dir, 'c1')
|
|
153
152
|
c2 = File.join(@@mnts_dir, 'c2')
|
|
154
153
|
Sundae.minimally_create_links(c1, @@sandbox)
|
|
155
|
-
assert
|
|
156
|
-
assert
|
|
154
|
+
assert((@@sandbox + 'd1').symlink?)
|
|
155
|
+
assert((@@sandbox + 'd2').symlink?)
|
|
157
156
|
Sundae.minimally_create_links(c2, @@sandbox)
|
|
158
|
-
assert
|
|
159
|
-
assert
|
|
160
|
-
assert
|
|
161
|
-
assert
|
|
162
|
-
assert
|
|
157
|
+
assert((@@sandbox + 'd1').directory?)
|
|
158
|
+
assert((@@sandbox + 'd1/f11').symlink?)
|
|
159
|
+
assert((@@sandbox + 'd1/f14').symlink?)
|
|
160
|
+
assert((@@sandbox + 'd2').symlink?)
|
|
161
|
+
assert((@@sandbox + 'd3').symlink?)
|
|
163
162
|
end
|
|
164
163
|
|
|
165
164
|
def test_class_mnts_in_path
|
|
166
|
-
assert_equal
|
|
165
|
+
assert_equal ['c1/d1', 'c1/d2', 'c2/d1', 'c2/d3'].map {|x| Pathname.new(x)},
|
|
166
|
+
Sundae.mnts_in_path(@@path1)
|
|
167
167
|
end
|
|
168
168
|
|
|
169
169
|
def test_class_remove_dead_links
|
|
170
|
-
|
|
171
|
-
|
|
170
|
+
(@@sandbox + 'temp_file').open('w')
|
|
171
|
+
(@@sandbox + 'perm_file').open('w')
|
|
172
172
|
FileUtils.ln_s(File.join(@@sandbox, 'temp_file'), File.join(@@sandbox, 'link'))
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
assert
|
|
176
|
-
assert File.exist?(File.join(@@sandbox, 'perm_file'))
|
|
173
|
+
(@@sandbox + 'temp_file').delete
|
|
174
|
+
assert ! (@@sandbox + 'link').exist?
|
|
175
|
+
assert (@@sandbox + 'perm_file').exist?
|
|
177
176
|
end
|
|
178
177
|
|
|
179
178
|
def test_class_remove_generated_directories
|
|
@@ -185,12 +184,9 @@ class TestSundae < Test::Unit::TestCase
|
|
|
185
184
|
end
|
|
186
185
|
|
|
187
186
|
def test_class_root_path
|
|
188
|
-
assert_equal
|
|
189
|
-
assert_equal
|
|
190
|
-
|
|
191
|
-
assert_raise ArgumentError do
|
|
192
|
-
Sundae.root_path('/')
|
|
193
|
-
end
|
|
187
|
+
assert_equal @@mnts_dir +'c1', Sundae.root_path(@@mnts_dir + 'c1')
|
|
188
|
+
assert_equal @@mnts_dir + 'c1', Sundae.root_path(@@mnts_dir + 'c1/d1')
|
|
189
|
+
assert_equal nil, Sundae.root_path('/')
|
|
194
190
|
end
|
|
195
191
|
|
|
196
192
|
def test_class_create_link
|
data/unison/common
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
fastcheck = true
|
|
2
|
+
|
|
3
|
+
# Roots of the synchronization
|
|
4
|
+
include local_mnt_path
|
|
5
|
+
|
|
6
|
+
ui = text
|
|
7
|
+
log = false
|
|
8
|
+
auto = true
|
|
9
|
+
|
|
10
|
+
# Names and paths to ignore:
|
|
11
|
+
ignore = Name temp.*
|
|
12
|
+
ignore = Name *~
|
|
13
|
+
ignore = Name .*~
|
|
14
|
+
ignore = Name *.o
|
|
15
|
+
ignore = Name *.tmp
|
|
16
|
+
ignore = Name .emacs_autosaves
|
|
17
|
+
ignore = Name .emacs_backups
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
include common
|
|
2
|
+
|
|
3
|
+
root = ssh://donmarch.org//home/14129/users/don%donmarch.org/var/unison/mnts
|
|
4
|
+
sshargs = "-l don%donmarch.org"
|
|
5
|
+
|
|
6
|
+
path = linux
|
|
7
|
+
path = nix
|
|
8
|
+
path = personal
|
|
9
|
+
path = personal_private
|
|
10
|
+
path = proprietorship
|
|
11
|
+
path = personal_archive
|
|
12
|
+
path = reference
|
data/version.txt
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
1.0.
|
|
1
|
+
1.0.2
|
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.2
|
|
5
5
|
prerelease:
|
|
6
6
|
platform: ruby
|
|
7
7
|
authors:
|
|
@@ -9,11 +9,11 @@ authors:
|
|
|
9
9
|
autorequire:
|
|
10
10
|
bindir: bin
|
|
11
11
|
cert_chain: []
|
|
12
|
-
date: 2012-02-
|
|
12
|
+
date: 2012-02-28 00:00:00.000000000 Z
|
|
13
13
|
dependencies:
|
|
14
14
|
- !ruby/object:Gem::Dependency
|
|
15
15
|
name: highline
|
|
16
|
-
requirement: &
|
|
16
|
+
requirement: &79306580 !ruby/object:Gem::Requirement
|
|
17
17
|
none: false
|
|
18
18
|
requirements:
|
|
19
19
|
- - ! '>='
|
|
@@ -21,10 +21,10 @@ dependencies:
|
|
|
21
21
|
version: 1.6.11
|
|
22
22
|
type: :runtime
|
|
23
23
|
prerelease: false
|
|
24
|
-
version_requirements: *
|
|
24
|
+
version_requirements: *79306580
|
|
25
25
|
- !ruby/object:Gem::Dependency
|
|
26
26
|
name: configatron
|
|
27
|
-
requirement: &
|
|
27
|
+
requirement: &79306020 !ruby/object:Gem::Requirement
|
|
28
28
|
none: false
|
|
29
29
|
requirements:
|
|
30
30
|
- - ! '>='
|
|
@@ -32,10 +32,10 @@ dependencies:
|
|
|
32
32
|
version: 2.9.0
|
|
33
33
|
type: :runtime
|
|
34
34
|
prerelease: false
|
|
35
|
-
version_requirements: *
|
|
35
|
+
version_requirements: *79306020
|
|
36
36
|
- !ruby/object:Gem::Dependency
|
|
37
37
|
name: rdoc
|
|
38
|
-
requirement: &
|
|
38
|
+
requirement: &79305190 !ruby/object:Gem::Requirement
|
|
39
39
|
none: false
|
|
40
40
|
requirements:
|
|
41
41
|
- - ! '>='
|
|
@@ -43,10 +43,10 @@ dependencies:
|
|
|
43
43
|
version: '3.12'
|
|
44
44
|
type: :runtime
|
|
45
45
|
prerelease: false
|
|
46
|
-
version_requirements: *
|
|
46
|
+
version_requirements: *79305190
|
|
47
47
|
- !ruby/object:Gem::Dependency
|
|
48
48
|
name: bones
|
|
49
|
-
requirement: &
|
|
49
|
+
requirement: &79303240 !ruby/object:Gem::Requirement
|
|
50
50
|
none: false
|
|
51
51
|
requirements:
|
|
52
52
|
- - ! '>='
|
|
@@ -54,7 +54,7 @@ dependencies:
|
|
|
54
54
|
version: 3.7.3
|
|
55
55
|
type: :development
|
|
56
56
|
prerelease: false
|
|
57
|
-
version_requirements: *
|
|
57
|
+
version_requirements: *79303240
|
|
58
58
|
description: Mix collections of files while maintaining complete separation.
|
|
59
59
|
email: don@ohspite.net
|
|
60
60
|
executables:
|
|
@@ -67,6 +67,8 @@ extra_rdoc_files:
|
|
|
67
67
|
- !binary |-
|
|
68
68
|
YmluL3N1bmRhZQ==
|
|
69
69
|
files:
|
|
70
|
+
- !binary |-
|
|
71
|
+
LmdpdGlnbm9yZQ==
|
|
70
72
|
- !binary |-
|
|
71
73
|
Q0hBTkdFTE9H
|
|
72
74
|
- !binary |-
|
|
@@ -81,6 +83,10 @@ files:
|
|
|
81
83
|
bGliL3N1bmRhZS5yYg==
|
|
82
84
|
- !binary |-
|
|
83
85
|
dGVzdC90ZXN0X3N1bmRhZS5yYg==
|
|
86
|
+
- !binary |-
|
|
87
|
+
dW5pc29uL2NvbW1vbg==
|
|
88
|
+
- !binary |-
|
|
89
|
+
dW5pc29uL210X2V4YW1wbGUucHJm
|
|
84
90
|
- !binary |-
|
|
85
91
|
dmVyc2lvbi50eHQ=
|
|
86
92
|
homepage: https://github.com/ohspite/sundae
|