sundae 0.9.2 → 1.0.0
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/{History.txt → CHANGELOG} +8 -0
- data/README.rdoc +155 -0
- data/Rakefile +27 -15
- data/bin/sundae +94 -21
- data/lib/sundae.rb +111 -49
- data/test/test_sundae.rb +17 -38
- data/version.txt +1 -0
- metadata +96 -65
- data/Manifest.txt +0 -9
- data/README.txt +0 -108
- data/setup.rb +0 -1599
- /data/{Copying.txt → COPYING} +0 -0
data/.gitignore
ADDED
data/{History.txt → CHANGELOG}
RENAMED
@@ -1,3 +1,11 @@
|
|
1
|
+
=== 1.0.0 / 2012-02-21
|
2
|
+
|
3
|
+
* Backwards incompatible: use Ruby for config file (not YAML)
|
4
|
+
* minor enhancements:
|
5
|
+
* support globs or regexp for ignore_paths
|
6
|
+
* better documentation
|
7
|
+
* switched to bones for gem config
|
8
|
+
|
1
9
|
=== 0.9.2 / 2009-04-28
|
2
10
|
|
3
11
|
* 1 minor enhancement
|
data/README.rdoc
ADDED
@@ -0,0 +1,155 @@
|
|
1
|
+
= Sundae
|
2
|
+
|
3
|
+
== Synopsis
|
4
|
+
|
5
|
+
(Re)generates directories by mixing the file hierarchies contained in
|
6
|
+
various 'mounted' directories. The generated directories contain
|
7
|
+
symbolic links to the mounted files. Combined with other tools (to
|
8
|
+
sync files), this scheme allows you to create separate collections of
|
9
|
+
files (work, personal, reference, linux, osx, etc.), choose which of
|
10
|
+
these you want to mount on each of your computers, and then build a
|
11
|
+
hierarchy that allows you to work on them side by side.
|
12
|
+
|
13
|
+
For example, let's take your bash config files. You want to separate
|
14
|
+
startup commands that you use on all unix computers from those that
|
15
|
+
you only need on Linux or OS X. Plus maybe you have some aliases that
|
16
|
+
you use only at work and some that you need only at home.
|
17
|
+
|
18
|
+
Rewrite your .bashrc to load everything in ~/etc/bash. Store that
|
19
|
+
file and your other bash config files in a folder with just general
|
20
|
+
*nix bash stuff. Then use Sundae to create links in ~/etc/bash to all
|
21
|
+
of the things that you need for your particular computer (general unix
|
22
|
+
stuff + either linux or OS X stuff + work aliases + ...). The files
|
23
|
+
are together in one folder so your script knows to read them, but they
|
24
|
+
can be version controlled and/or synced across all of your computers
|
25
|
+
in separate bundles (one for *nix, one for ubuntu, one for OS X,
|
26
|
+
etc.).
|
27
|
+
|
28
|
+
You have to figure out how to use this model. It's not for everyone.
|
29
|
+
It requires rewriting config files, making sure certain files kept in
|
30
|
+
different folders don't have the same name, etc. But it's worth it
|
31
|
+
when you sit down at a new computer and say "I only want to use my
|
32
|
+
*nix and linux config files, my work files, and music" and it all just
|
33
|
+
works. Like this:
|
34
|
+
|
35
|
+
~> ls
|
36
|
+
Desktop local mnt src WualaDrive
|
37
|
+
~> sundae
|
38
|
+
~> ls
|
39
|
+
bin Desktop doc etc lib local mnt share src tmp var WualaDrive
|
40
|
+
|
41
|
+
== Install
|
42
|
+
|
43
|
+
sudo gem install sundae
|
44
|
+
|
45
|
+
== Usage
|
46
|
+
|
47
|
+
The first time you run Sundae, it will create a template config file
|
48
|
+
in your home directory. This file, <tt>.sundae</tt>, needs to be
|
49
|
+
customized. It is just a Ruby file that defines the following:
|
50
|
+
|
51
|
+
[+configatron.paths+]
|
52
|
+
array; where the collections are stored
|
53
|
+
[+configatron.ignore_rules+]
|
54
|
+
array; each element is a string or Regexp and becomes a rule that prevents
|
55
|
+
links to files or directories that match the Regexp. Globs in strings are expanded.
|
56
|
+
|
57
|
+
The hierarchy in <em>path</em> should look something like
|
58
|
+
this:
|
59
|
+
|
60
|
+
path/
|
61
|
+
|-- collection1/
|
62
|
+
| |-- mnt1/
|
63
|
+
| | |-- real_files_and_dirs
|
64
|
+
| | ` ...
|
65
|
+
| |-- mnt2/
|
66
|
+
`-- collection2/
|
67
|
+
` ...
|
68
|
+
|
69
|
+
Why is this double layer "collection" stuff going on? Because while
|
70
|
+
most of the time you can share a whole folder between computers,
|
71
|
+
sometimes you want to mix your config files into a folder that also
|
72
|
+
contains nonsymlinked files.
|
73
|
+
|
74
|
+
For example, your ~/.ssh folder probably has a public and private key
|
75
|
+
that you want to stay unique to that machine, but you might want to
|
76
|
+
mix in a "config" file that has host aliases that you share between
|
77
|
+
machines. This is how you do that. I do it with my .unison, .mocp,
|
78
|
+
.ssh, and .lftp folders.
|
79
|
+
|
80
|
+
For example, the hierarchy in my <em>path</em>s looks sort of like this:
|
81
|
+
|
82
|
+
~/mnt/git/ <-- "path"
|
83
|
+
|-- nix/ <-- "collection"
|
84
|
+
| |-- home/ <-- "mnt"
|
85
|
+
| | |-- .emacs.d/ (~/.emacs.d will point here)
|
86
|
+
| | |-- etc/ (~/etc will point here)
|
87
|
+
| | ` ...
|
88
|
+
| |-- dot-unison
|
89
|
+
| | |-- .sundae_path (says "~/.unison")
|
90
|
+
| | |-- default.prf (~/.unison/default.prf will point here)
|
91
|
+
| | `
|
92
|
+
| |
|
93
|
+
|-- osx/
|
94
|
+
| |-- home_library/ (says "~/Library")
|
95
|
+
| | |-- .sundae_path
|
96
|
+
| | `-- Library-Keyboard_Layouts/
|
97
|
+
| | `-- Keyboard Layouts/
|
98
|
+
| | ` Colemak.keylayout
|
99
|
+
| |
|
100
|
+
|-- personal
|
101
|
+
| `-- home/
|
102
|
+
| |-- doc/
|
103
|
+
| | ` ...
|
104
|
+
| ` ...
|
105
|
+
` ...
|
106
|
+
~/mnt/sync/ <-- "path"
|
107
|
+
|-- reference <-- "collection"
|
108
|
+
| |-- home/ <-- "mnt"
|
109
|
+
| ` ...
|
110
|
+
|-- music
|
111
|
+
| |-- home/
|
112
|
+
| ` ...
|
113
|
+
` ...
|
114
|
+
|
115
|
+
Sundae will act on all of the <em>mnt</em>s--subdirectories of the
|
116
|
+
<em>collection</em>s, that is, the sub-subdirectories of the
|
117
|
+
<em>path</em>. The "collections" are only there to facilitate
|
118
|
+
grouping common files and syncronizing them between computers.
|
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
|
+
|
126
|
+
And that's it. When called, Sundae creates links so that you can
|
127
|
+
work on your files from seperate parts of life as if they were side
|
128
|
+
by side.
|
129
|
+
|
130
|
+
== Author
|
131
|
+
<don@ohspite.net>
|
132
|
+
|
133
|
+
== Copyright
|
134
|
+
Copyright (c) 2011, 2008 <don@ohspite.net>.
|
135
|
+
Licensed under the MIT License.
|
136
|
+
|
137
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
138
|
+
a copy of this software and associated documentation files (the
|
139
|
+
'Software'), to deal in the Software without restriction, including
|
140
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
141
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
142
|
+
permit persons to whom the Software is furnished to do so, subject to
|
143
|
+
the following conditions:
|
144
|
+
|
145
|
+
The above copyright notice and this permission notice shall be
|
146
|
+
included in all copies or substantial portions of the Software.
|
147
|
+
|
148
|
+
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
149
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
150
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
151
|
+
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
152
|
+
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
153
|
+
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
154
|
+
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
155
|
+
|
data/Rakefile
CHANGED
@@ -1,18 +1,30 @@
|
|
1
|
-
|
1
|
+
begin
|
2
|
+
require 'bones'
|
3
|
+
rescue LoadError
|
4
|
+
abort '### please install the "bones" gem ###'
|
5
|
+
end
|
2
6
|
|
3
|
-
|
4
|
-
|
5
|
-
require './lib/sundae.rb'
|
7
|
+
task :default => 'test:run'
|
8
|
+
task 'gem:release' => 'test:run'
|
6
9
|
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
10
|
+
Bones do
|
11
|
+
name 'sundae'
|
12
|
+
authors 'Don'
|
13
|
+
email 'don@ohspite.net'
|
14
|
+
url 'https://github.com/ohspite/sundae'
|
15
|
+
summary 'Mix collections of files while maintaining complete separation.'
|
16
|
+
description 'Mix collections of files while maintaining complete separation.'
|
17
|
+
history_file 'CHANGELOG'
|
18
|
+
manifest_file 'Manifest'
|
19
|
+
readme_file 'README.rdoc'
|
20
|
+
rdoc.main 'README.rdoc'
|
17
21
|
|
18
|
-
|
22
|
+
ignore_file '.gitignore'
|
23
|
+
exclude %w(tmp$ bak$ ~$ CVS \.svn/ \.git/ \.bzr/ \.bzrignore ^pkg/)
|
24
|
+
rdoc.include %w(README ^lib/ ^bin/ ^ext/ \.txt$ \.rdoc$)
|
25
|
+
depend_on 'highline'
|
26
|
+
depend_on 'configatron'
|
27
|
+
depend_on 'rdoc'
|
28
|
+
|
29
|
+
# spec.opts << '--color'
|
30
|
+
end
|
data/bin/sundae
CHANGED
@@ -7,7 +7,7 @@
|
|
7
7
|
#
|
8
8
|
# == Usage
|
9
9
|
#
|
10
|
-
# sundae [
|
10
|
+
# sundae [options] [commands]
|
11
11
|
#
|
12
12
|
# For command line details see
|
13
13
|
# sundae --help
|
@@ -16,25 +16,84 @@
|
|
16
16
|
# <don@ohspite.net>
|
17
17
|
#
|
18
18
|
# == Copyright
|
19
|
-
# Copyright (c) 2008 <don@ohspite.net>.
|
19
|
+
# Copyright (c) 2012, 2008 <don@ohspite.net>.
|
20
20
|
# Licensed under the MIT License.
|
21
21
|
|
22
|
-
require 'rdoc/usage'
|
23
22
|
require 'optparse'
|
23
|
+
require 'highline/import'
|
24
24
|
|
25
25
|
$:.unshift File.join(File.dirname(__FILE__), "../lib")
|
26
26
|
|
27
27
|
require 'sundae'
|
28
28
|
|
29
29
|
class App # :nodoc:
|
30
|
+
|
31
|
+
COMMAND_LIST = %w{run
|
32
|
+
source
|
33
|
+
move
|
34
|
+
}
|
35
|
+
|
30
36
|
def initialize
|
31
37
|
parse_commandline(ARGV)
|
32
38
|
|
33
39
|
Sundae.load_config_file(@options[:config_path])
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
40
|
+
|
41
|
+
case @commands[0]
|
42
|
+
when :run
|
43
|
+
Sundae.update_filesystem
|
44
|
+
when :remove
|
45
|
+
Sundae.remove_filesystem
|
46
|
+
when :sources
|
47
|
+
ARGV << "." if ARGV.empty?
|
48
|
+
Process.abort "#{ARGV[0]} is not a directory." unless File.directory?(ARGV[0])
|
49
|
+
path = File.expand_path(ARGV[0])
|
50
|
+
mnts = Sundae.find_source_directories(path)
|
51
|
+
mnts.each do |mnt|
|
52
|
+
install_location = Sundae.install_location(mnt)
|
53
|
+
relative = path.sub(install_location, '')
|
54
|
+
puts mnt
|
55
|
+
Dir.entries(File.join(mnt, relative)).sort.each do |e|
|
56
|
+
next if e =~ /^..?$/
|
57
|
+
line_end = File.directory?(e) ? "/" : ""
|
58
|
+
puts " " + e + line_end
|
59
|
+
end
|
60
|
+
puts
|
61
|
+
end
|
62
|
+
when :move
|
63
|
+
Process.abort "The 'move' command requires a file or directory as an argument." if ARGV.empty?
|
64
|
+
Process.abort "#{ARGV[0]} is not a file or directory." unless File.exist?(ARGV[0])
|
65
|
+
|
66
|
+
if ARGV.size == 1
|
67
|
+
path = File.expand_path(ARGV[0])
|
68
|
+
|
69
|
+
current_mnt = nil
|
70
|
+
Sundae.all_mnts.map do |mnt|
|
71
|
+
current_mnt = mnt if path =~ Regexp.new(mnt)
|
72
|
+
end
|
73
|
+
choices = if current_mnt
|
74
|
+
Sundae.all_mnts
|
75
|
+
else
|
76
|
+
Sundae.find_source_directories(File.dirname(path))
|
77
|
+
end
|
78
|
+
choices.push "--Cancel?--"
|
79
|
+
choose do |menu|
|
80
|
+
menu.prompt = "move to: "
|
81
|
+
menu.choices(*choices) do |new_path|
|
82
|
+
if new_path == "--Cancel?--"
|
83
|
+
Process.abort("No move performed.")
|
84
|
+
else
|
85
|
+
Sundae.move_to_mnt(path, new_path)
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
else
|
90
|
+
relative_path = ARGV.pop
|
91
|
+
ARGV.each do |path|
|
92
|
+
path = File.expand_path(path)
|
93
|
+
Sundae.move_to_relative_path(path, relative_path)
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
38
97
|
end
|
39
98
|
|
40
99
|
private
|
@@ -42,12 +101,18 @@ class App # :nodoc:
|
|
42
101
|
def parse_commandline(option_line)
|
43
102
|
options = {:verbose => false}
|
44
103
|
option_parser = OptionParser.new do |opts|
|
45
|
-
opts.banner = "Usage: #{File.basename(__FILE__)} [options] "
|
104
|
+
opts.banner = "Usage: #{File.basename(__FILE__)} [options] [command]"
|
105
|
+
opts.separator ""
|
106
|
+
opts.separator "Available commands (can be abbreviated):"
|
107
|
+
opts.separator ' run create the filesystem from the mounts; the default command'
|
108
|
+
opts.separator ' rm remove generated directories and symlinks'
|
109
|
+
opts.separator ' move PATH moves the resource at \'path\' (or pointed to by \'path\' if it is a link) to another mount collection'
|
110
|
+
opts.separator ' sources DIR=./ print the mounts that have resources in \'dir\' and what comes from each'
|
46
111
|
opts.separator ""
|
47
112
|
opts.separator "Specific options:"
|
48
113
|
opts.on('-c',
|
49
114
|
'--config-path PATH',
|
50
|
-
'specify the path to the \'.sundae\' directory (default is \'~/.sundae\')') do |path|
|
115
|
+
'specify the path to the \'.sundae\' directory (default is \'~/.sundae\'); used with the regular \'run\' command') do |path|
|
51
116
|
options[:config_path] = File.expand_path(path)
|
52
117
|
end
|
53
118
|
# opts.on('-v',
|
@@ -71,23 +136,31 @@ class App # :nodoc:
|
|
71
136
|
end
|
72
137
|
|
73
138
|
argv = Array.new
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
139
|
+
commands = Array.new
|
140
|
+
if option_line.empty? then option_line = ['run'] end
|
141
|
+
option_parser.order!(option_line) do |input|
|
142
|
+
action = case input
|
143
|
+
when nil then :run
|
144
|
+
when /^ru?n?$/ then :run
|
145
|
+
when /^re?m?o?v?e?$/ then :remove
|
146
|
+
when /^so?u?r?c?e?s?$/ then :sources
|
147
|
+
when /^mo?v?e?$/ then :move
|
148
|
+
else nil
|
149
|
+
end
|
150
|
+
if action.nil?
|
151
|
+
argv << input
|
152
|
+
else
|
153
|
+
commands << action
|
82
154
|
end
|
83
|
-
rescue
|
84
|
-
RDoc::usage('usage')
|
85
155
|
end
|
86
156
|
argv.each { |a| option_line << a }
|
87
|
-
|
157
|
+
|
158
|
+
if commands.empty? then Process.abort "No command unambiguously specified." end
|
159
|
+
if commands.size > 1 then Process.abort "More than one command specified." end
|
160
|
+
|
88
161
|
@options = options
|
162
|
+
@commands = commands
|
89
163
|
end
|
90
164
|
end
|
91
165
|
|
92
|
-
|
93
166
|
App.new
|
data/lib/sundae.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
require 'rubygems'
|
1
|
+
# require 'rubygems'
|
2
2
|
require 'configatron'
|
3
3
|
require 'fileutils'
|
4
4
|
require 'find'
|
@@ -7,7 +7,11 @@ require 'find'
|
|
7
7
|
# together using symbolic links.
|
8
8
|
#
|
9
9
|
module Sundae
|
10
|
-
|
10
|
+
# :stopdoc:
|
11
|
+
LIBPATH = ::File.expand_path(::File.dirname(__FILE__)) + ::File::SEPARATOR
|
12
|
+
PATH = ::File.dirname(LIBPATH) + ::File::SEPARATOR
|
13
|
+
# :startdoc:
|
14
|
+
VERSION = ::File.read(PATH + 'version.txt').strip
|
11
15
|
|
12
16
|
DEFAULT_CONFIG_FILE = File.expand_path(File.join(ENV['HOME'], '.sundae'))
|
13
17
|
|
@@ -17,25 +21,18 @@ module Sundae
|
|
17
21
|
#
|
18
22
|
def self.load_config_file(config_file = DEFAULT_CONFIG_FILE)
|
19
23
|
config_file ||= DEFAULT_CONFIG_FILE
|
20
|
-
config_file = File.join(config_file, '.sundae')
|
24
|
+
config_file = File.join(config_file, '.sundae') if File.directory?(config_file)
|
21
25
|
|
22
26
|
create_template_config_file(config_file) unless File.file?(config_file)
|
23
27
|
|
24
|
-
|
25
|
-
configatron.set_default(:collection_link_prefix, '_')
|
26
|
-
|
27
|
-
configatron.configure_from_yaml(config_file)
|
28
|
+
load(config_file)
|
28
29
|
configatron.paths.map! { |p| File.expand_path(p) }
|
29
|
-
configatron.ignore_rules.map! { |a| Regexp.new(a) }
|
30
30
|
|
31
31
|
# An array which lists the directories where mnts are stored.
|
32
32
|
@paths = configatron.paths
|
33
33
|
# These are the rules that are checked to see if a file in a mnt
|
34
34
|
# should be ignored.
|
35
35
|
@ignore_rules = configatron.ignore_rules
|
36
|
-
|
37
|
-
@collection_links = configatron.collection_links
|
38
|
-
@collection_link_prefix = configatron.collection_link_prefix
|
39
36
|
end
|
40
37
|
|
41
38
|
# Create a template configuration file at <em>config_file</em> after
|
@@ -47,16 +44,23 @@ module Sundae
|
|
47
44
|
ans = gets.downcase.strip
|
48
45
|
if ans == "y" || ans == "yes"
|
49
46
|
File.open(config_file, "w") do |f|
|
50
|
-
f.puts
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
47
|
+
f.puts <<-EOM.gsub(/^ {14}/, '')
|
48
|
+
# -*-Ruby-*-
|
49
|
+
|
50
|
+
# An array which lists the directories where mnts are stored.
|
51
|
+
configatron.paths = ["~/mnt"]
|
52
|
+
|
53
|
+
# These are the rules that are checked to see if a file in a mnt
|
54
|
+
# should be ignored.
|
55
|
+
#
|
56
|
+
# For `ignore_rules', use either strings (can be globs)
|
57
|
+
# or Ruby regexps. You can mix both in the same array.
|
58
|
+
# Globs are matched using the method File.fnmatch.
|
59
|
+
configatron.ignore_rules = %w(.git,
|
60
|
+
.bzr,
|
61
|
+
.svn,
|
62
|
+
.DS_Store)
|
63
|
+
EOM
|
60
64
|
end
|
61
65
|
puts
|
62
66
|
puts "Okay then."
|
@@ -74,7 +78,13 @@ module Sundae
|
|
74
78
|
def self.ignore_file?(file) # :doc:
|
75
79
|
return true if File.basename(file) =~ /^\.\.?$/
|
76
80
|
return true if File.basename(file) == ".sundae_path"
|
77
|
-
@ignore_rules.each
|
81
|
+
@ignore_rules.each do |r|
|
82
|
+
if r.kind_of? Regexp
|
83
|
+
return true if File.basename(file) =~ r
|
84
|
+
else
|
85
|
+
return true if File.fnmatch(r, file)
|
86
|
+
end
|
87
|
+
end
|
78
88
|
return false
|
79
89
|
end
|
80
90
|
|
@@ -94,12 +104,7 @@ module Sundae
|
|
94
104
|
# be created.
|
95
105
|
#
|
96
106
|
def self.install_locations
|
97
|
-
|
98
|
-
|
99
|
-
all_mnts.each do |mnt|
|
100
|
-
locations << install_location(mnt)
|
101
|
-
end
|
102
|
-
return locations.sort.uniq
|
107
|
+
all_mnts.map { |m| install_location(m) }.sort.uniq
|
103
108
|
end
|
104
109
|
|
105
110
|
# Given _path_, return all mnts (i.e., directories two levels down)
|
@@ -111,7 +116,7 @@ module Sundae
|
|
111
116
|
collections.each do |c|
|
112
117
|
collection_mnts = Dir.entries(File.join(path, c)).delete_if {|a| a=~/^\./}
|
113
118
|
collection_mnts.map! { |mnt| File.join(c, mnt) }
|
114
|
-
mnts |= collection_mnts
|
119
|
+
mnts |= collection_mnts # |= is the union
|
115
120
|
end
|
116
121
|
|
117
122
|
return mnts.sort.uniq
|
@@ -124,7 +129,7 @@ module Sundae
|
|
124
129
|
|
125
130
|
@paths.each do |path|
|
126
131
|
next unless File.exist?(path)
|
127
|
-
mnts |= mnts_in_path(path).map { |mnt| File.join(path, mnt) }
|
132
|
+
mnts |= mnts_in_path(path).map { |mnt| File.join(path, mnt) } # |= is the union operator
|
128
133
|
end
|
129
134
|
|
130
135
|
return mnts
|
@@ -143,7 +148,7 @@ module Sundae
|
|
143
148
|
end
|
144
149
|
end
|
145
150
|
|
146
|
-
return dirs.sort.uniq
|
151
|
+
return dirs.sort.uniq.select { |d| File.directory?(d) }
|
147
152
|
end
|
148
153
|
|
149
154
|
# Check for symlinks in the base directories that are missing their
|
@@ -172,7 +177,7 @@ module Sundae
|
|
172
177
|
generated_directories.each do |dir|
|
173
178
|
next if File.basename(dir) == ('.sundae')
|
174
179
|
|
175
|
-
# Do a
|
180
|
+
# Do a search to make sure no non-symlink file is being
|
176
181
|
# deleted. That would suck.
|
177
182
|
if sf = find_static_file(dir)
|
178
183
|
puts "found static file: #{sf}"
|
@@ -229,18 +234,6 @@ module Sundae
|
|
229
234
|
|
230
235
|
Find.prune if File.directory?(path)
|
231
236
|
end
|
232
|
-
create_collection_links(target, link_path)
|
233
|
-
end
|
234
|
-
|
235
|
-
# Create links in a generated mirror directory to the analogous
|
236
|
-
# location in the mounted directories.
|
237
|
-
#
|
238
|
-
def self.create_collection_links(target, link_name)
|
239
|
-
return unless @collection_links
|
240
|
-
|
241
|
-
collection_name = File.basename(root_path(target))
|
242
|
-
collection_link = File.join(link_name, @collection_link_prefix + collection_name)
|
243
|
-
create_link(target, collection_link) unless File.exist? collection_link
|
244
237
|
end
|
245
238
|
|
246
239
|
# Starting at _dir_, walk up the directory hierarchy and return the
|
@@ -250,11 +243,7 @@ module Sundae
|
|
250
243
|
raise ArgumentError if dir == '/'
|
251
244
|
|
252
245
|
parent = File.expand_path(File.join(dir, '..'))
|
253
|
-
|
254
|
-
return dir
|
255
|
-
else
|
256
|
-
root_path parent
|
257
|
-
end
|
246
|
+
return (@paths.include?(parent)) ? dir : root_path(parent)
|
258
247
|
end
|
259
248
|
|
260
249
|
# Dispatch calls to create_directory_link and create_file_link.
|
@@ -326,5 +315,78 @@ module Sundae
|
|
326
315
|
minimally_create_links(target_path2, link_name)
|
327
316
|
end
|
328
317
|
|
318
|
+
def self.update_filesystem
|
319
|
+
remove_dead_links
|
320
|
+
remove_generated_directories
|
321
|
+
create_filesystem
|
322
|
+
end
|
323
|
+
|
324
|
+
def self.remove_filesystem
|
325
|
+
remove_dead_links
|
326
|
+
remove_generated_directories
|
327
|
+
end
|
328
|
+
|
329
|
+
# Return an array of mnts that are installing to +path+.
|
330
|
+
#
|
331
|
+
def self.find_source_directories(path)
|
332
|
+
sources = Array.new
|
333
|
+
all_mnts.each do |mnt|
|
334
|
+
install_location = File.expand_path(install_location(mnt))
|
335
|
+
if path.include?(install_location)
|
336
|
+
relative_path = path.sub(Regexp.new(install_location), "")
|
337
|
+
sources << mnt if File.exist?(File.join(mnt, relative_path))
|
338
|
+
end
|
339
|
+
end
|
340
|
+
return sources
|
341
|
+
end
|
342
|
+
|
343
|
+
# Move the file at +path+ (or its target in the case of a link) to
|
344
|
+
# +mnt+ preserving relative path.
|
345
|
+
#
|
346
|
+
def self.move_to_mnt(path, mnt)
|
347
|
+
if File.symlink?(path)
|
348
|
+
to_move = File.readlink(path)
|
349
|
+
current = Sundae.find_source_directories(path)[0]
|
350
|
+
relative_path = to_move.sub(Regexp.new(current), "")
|
351
|
+
FileUtils.mv(to_move, mnt + relative_path) unless current == mnt
|
352
|
+
FileUtils.ln_sf(mnt + relative_path, path)
|
353
|
+
else
|
354
|
+
location = Sundae.install_location(mnt)
|
355
|
+
relative_path = path.sub(Regexp.new(location), "")
|
356
|
+
FileUtils.mv(path, mnt + relative_path) unless path == mnt + relative_path
|
357
|
+
FileUtils.ln_s(mnt + relative_path, path)
|
358
|
+
end
|
359
|
+
end
|
360
|
+
|
361
|
+
# Move the target at +link+ according to +relative_path+.
|
362
|
+
#
|
363
|
+
def self.move_to_relative_path(link, relative_path)
|
364
|
+
raise ArgumentError, "#{link} is not a link." unless File.symlink?(link)
|
365
|
+
|
366
|
+
target = File.readlink(link)
|
367
|
+
|
368
|
+
pwd = FileUtils.pwd
|
369
|
+
mnt = Sundae.find_source_directories(link)[0]
|
370
|
+
mnt_pwd = File.join(mnt, pwd.sub(Regexp.new(install_location(mnt)), ""))
|
371
|
+
|
372
|
+
if File.directory?(relative_path)
|
373
|
+
new_target_path = File.join(mnt_pwd, relative_path, File.basename(link))
|
374
|
+
new_link_path = File.join(pwd, relative_path, File.basename(link))
|
375
|
+
else
|
376
|
+
new_target_path = File.join(mnt_pwd, relative_path)
|
377
|
+
new_link_path = File.join(pwd, relative_path)
|
378
|
+
end
|
379
|
+
|
380
|
+
target = File.expand_path(target)
|
381
|
+
new_target_path = File.expand_path(new_target_path)
|
382
|
+
new_link_path = File.expand_path(new_link_path)
|
383
|
+
|
384
|
+
raise ArgumentError, "#{link} and #{new_target_path} are the same file" if target == new_target_path
|
385
|
+
FileUtils.mkdir_p(File.dirname(new_target_path))
|
386
|
+
FileUtils.mv(target, new_target_path)
|
387
|
+
FileUtils.rm(link)
|
388
|
+
FileUtils.ln_s(new_target_path, new_link_path)
|
389
|
+
end
|
390
|
+
|
329
391
|
end
|
330
392
|
|