homesync 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/Gemfile ADDED
@@ -0,0 +1,11 @@
1
+ source "http://rubygems.org"
2
+
3
+ gemspec
4
+
5
+ group :development do
6
+ gem 'rake'
7
+ if RUBY_PLATFORM =~ /darwin/
8
+ gem 'rb-fsevent'
9
+ gem 'growl_notify'
10
+ end
11
+ end
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2011 László Bácsi
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,114 @@
1
+ **Note**: This project is being developed following the
2
+ [RDD](http://tom.preston-werner.com/2010/08/23/readme-driven-development.html)
3
+ model. Not all of the functionality described in this README have been
4
+ implemented yet. Missing pieces are noted in the Usage section.
5
+
6
+ # HomeSync
7
+
8
+ HomeSync makes it easy to synchronize any file under your home directory
9
+ with other machines through Dropbox by providing a simple commandline
10
+ interface for adding and removing symlinks to your files. Furthermore,
11
+ it knows how to handle several key directories correctly and how to
12
+ synchronize application preferences and data.
13
+
14
+ ## Installation
15
+
16
+ $ gem install homesync
17
+ $ homesync setup [-p ~/path/to/dropbox/homesync]
18
+
19
+ ## How it works
20
+
21
+ HomeSync uses a directory in your dropbox (`~/Dropbox/HomeSync` by
22
+ default) to store the files and directories you want to be synchronized.
23
+ When you add a file to HomeSync it moves the original file to this
24
+ location and creates a symbolic link in its original place.
25
+
26
+ Files are always stored in HomeSync with the same relative path they had
27
+ in your home directory. For example, if you have a file in
28
+ `~/Code/script.rb` and you have it synchronized by HomeSync, it will be
29
+ moved to `~/Dropbox/HomeSync/Code/script.rb` and `~/Code/script.rb` will
30
+ be a symbolic link pointing to this new path.
31
+
32
+ HomeSync handles `plist` files in `~/Library/Preferences/` a bit
33
+ differently. These files are usually overwritten when their application
34
+ exits. HomeSync uses a launch agent to watch this directory and the
35
+ corresponding HomeSync directory for changes. When a file that needs to
36
+ be synced is changed in either of these directories, it would be copied
37
+ to the other folder.
38
+
39
+ ## Usage
40
+
41
+ $ homesync setup [-p ~/path/to/dropbox/homesync]
42
+
43
+ Creates a launch agent to monitor changes of preferences files. The `-p`
44
+ option tells HomeSync where to put synchronized files (defaults to
45
+ `~/Dropbox/HomeSync`). This will be stored in the `~/.homesync`
46
+ configuration file, but all the other commands accept this option too.
47
+
48
+ $ homesync sync [--overwrite-local | --overwrite-homesync] ~/path/to/file_or_dir
49
+
50
+ Tells HomeSync to synchronize the file. This is the default command
51
+ meaning that the command name may be omitted. The outcome of this
52
+ command depends on whether the file exists and whether there's a file
53
+ with the same relative path in HomeSync:
54
+
55
+ * original file doesn't exist
56
+ * and homesync file doesn't exist: error
57
+ * and homesync file exists: create symbolic link to the homesync file
58
+ * original file is a symbolic link
59
+ * to its homesync file: nothing to do
60
+ * to somewhere else: error (homesync doesn't handle this case)
61
+ * original file is a regular file or directory
62
+ * and homesync file doesn't exist: move it to homesync and create
63
+ symbolic link to it
64
+ * and homesync file exists: asks whether to overwrite the current
65
+ local file and sync what's in HomeSync (`--overwrite-local` to do
66
+ this without aking) or update HomeSync with the current local file
67
+ in and sync that instead (`--overwrite-homesync` to do this without
68
+ asking)
69
+
70
+ $ homesync unsync [-r] ~/path/to/file_or_directory
71
+
72
+ *Not implemented yet.* Given that the argument is a symbolic link to an
73
+ existing file or directory in HomeSync, copies this file to its original
74
+ place overwriting the symbolic link. Use the `-r` option to remove the
75
+ file from homesync afterwards.
76
+
77
+ ### Custom behaviors (*none of it implemented yet*)
78
+
79
+ $ homesync sync:pref Application
80
+ $ homesync unsync:pref Application
81
+
82
+ Syncs or unsyncs the preferences file of the application (e.g. for
83
+ TextMate this would be
84
+ `~/Library/Preferences/com.macromates.textmate.plist`). Symlinking
85
+ wouldn't work because of overwrites, so this works by using a launch
86
+ agent to monitor changes to this file.
87
+
88
+ $ homesync sync:appsupport Application
89
+ $ homesync unsync:appsupport Application
90
+
91
+ Syncs or unsyncs the application support directory of the application
92
+ (e.g. for TextMate this would be `~/Library/Application
93
+ Support/TextMate`).
94
+
95
+ $ homesync sync:app Application
96
+ $ homesync unsync:app Application
97
+
98
+ Syncs or unsyncs both the application's preferences file and its
99
+ application support directory.
100
+
101
+ ## Note on Patches/Pull Requests
102
+
103
+ * Fork the project.
104
+ * Make your feature addition or bug fix.
105
+ * Add tests for it. This is important so I don't break it in a future
106
+ version unintentionally.
107
+ * Commit, do not mess with rakefile, version, or history. (if you want
108
+ to have your own version, that is fine but bump version in a commit by
109
+ itself I can ignore when I pull)
110
+ * Send me a pull request. Bonus points for topic branches.
111
+
112
+ ## Copyright
113
+
114
+ Copyright (c) 2011 László Bácsi. See LICENSE for details.
data/bin/homesync ADDED
@@ -0,0 +1,17 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ begin
4
+ require 'homesync/version'
5
+ rescue LoadError
6
+ $:.unshift(File.expand_path("../lib", File.dirname(__FILE__)))
7
+ require 'homesync/version'
8
+ end
9
+
10
+ if %w(--version -v).include? ARGV.first
11
+ puts "HomeSync #{HomeSync::VERSION}"
12
+ exit(0)
13
+ end
14
+
15
+ require 'homesync/cli'
16
+
17
+ HomeSync::CLI.start
data/lib/homesync.rb ADDED
@@ -0,0 +1,5 @@
1
+ require 'homesync/version'
2
+
3
+ module HomeSync
4
+ autoload :CLI, "homesync/cli"
5
+ end
@@ -0,0 +1,164 @@
1
+ require 'thor'
2
+ require 'pathname'
3
+ require 'yaml'
4
+
5
+ module HomeSync
6
+ class CLI < Thor
7
+
8
+ class_option :homesync_path, :aliases => "-p"
9
+
10
+ default_task :sync
11
+
12
+ desc "setup", "Create the launch agent and configure HomeSync"
13
+ long_desc <<-EOH
14
+ Create a launch agent to monitor changes of preferences files
15
+ Store homesync path configuration (-p option) in ~/.homesync
16
+ EOH
17
+ def setup
18
+ update_homesync_config if options[:homesync_path]
19
+ update_launch_agent
20
+ end
21
+
22
+ desc "sync FILE", "Setup syncing for file or directory"
23
+ long_desc <<-EOH
24
+ Move the file to the HomeSync directory and create a symbolic link in its
25
+ place. Or setup a symbolic link in this location if the file doesn't exist
26
+ but a matching file in HomeSync does.
27
+
28
+ When both files exist you will be asked what to do. Alternatively you could
29
+ tell HomeSync which road to go using one of the options of this command.
30
+ EOH
31
+ method_options :overwrite_local => :boolean, :overwrite_homesync => :boolean
32
+ def sync(path)
33
+ if options[:overwrite_local] and options[:overwrite_homesync]
34
+ error "--overwrite-local and --overwrite-homesync cannot be used together"
35
+ end
36
+
37
+ path = Pathname.new(path).expand_path
38
+ relative_from_home = path.relative_path_from(home_path)
39
+
40
+ if relative_from_home.to_s =~ %r{^../}
41
+ error "#{path} is not inside your home directory"
42
+ end
43
+
44
+ sync_path = homesync_path.join(relative_from_home)
45
+
46
+ if path.symlink?
47
+ target = path.readlink
48
+ target = path.dirname.realpath.join(target) if target.relative?
49
+ if target == sync_path
50
+ error "#{path} is already syncing"
51
+ else
52
+ error "#{path} is a symlink pointing somewhere else than its place in #{homesync_path}"
53
+ end
54
+ end
55
+
56
+ if path.exist?
57
+ if sync_path.exist?
58
+ if options[:overwrite_local] or (not options[:overwrite_homesync] and shell.file_collision(path))
59
+ if path.file? then path.unlink else path.rmtree end
60
+ path.make_symlink(sync_path.to_s)
61
+ say "Replaced #{path} with symlink to #{sync_path}"
62
+ elsif options[:overwrite_homesync] or shell.file_collision(sync_path)
63
+ if sync_path.file? then sync_path.unlink else sync_path.rmtree end
64
+ path.rename(sync_path)
65
+ path.make_symlink(sync_path.to_s)
66
+ say "Replaced #{sync_path} with local version and created symlink to it"
67
+ else
68
+ say "Kept both versions, syncing has been cancelled"
69
+ end
70
+ else
71
+ sync_path.dirname.mkpath
72
+ path.rename(sync_path)
73
+ path.make_symlink(sync_path.to_s)
74
+ say "Moved #{path} to HomeSync and created a symlink to it"
75
+ end
76
+ else
77
+ if sync_path.exist?
78
+ path.make_symlink(sync_path.to_s)
79
+ say "Created link to #{sync_path}"
80
+ else
81
+ error "#{path} doesn't exist"
82
+ end
83
+ end
84
+ end
85
+
86
+ private
87
+
88
+ def error(message)
89
+ raise Thor::Error, message
90
+ end
91
+
92
+ def home_path
93
+ Pathname.new(ENV['HOME'])
94
+ end
95
+
96
+ def homesync_path
97
+ Pathname.new(
98
+ options[:homesync_path] ||
99
+ homesync_config['homesync_path'] ||
100
+ "~/Dropbox/HomeSync"
101
+ ).expand_path
102
+ end
103
+
104
+ def config_file
105
+ home_path.join(".homesync")
106
+ end
107
+
108
+ def homesync_config
109
+ @homesync_config ||= config_file.exist? ? YAML.load_file(config_file) : {}
110
+ end
111
+
112
+ def update_homesync_config
113
+ relative_homesync_path = "~/" + homesync_path.relative_path_from(home_path).to_s
114
+ if homesync_config['homesync_path'] != relative_homesync_path
115
+ homesync_config['homesync_path'] = relative_homesync_path
116
+ config_file.open("w") { |f| f.write(homesync_config.to_yaml) }
117
+ puts "Configuration written to #{config_file}"
118
+ end
119
+ end
120
+
121
+ def update_launch_agent
122
+ launch_agent_path = home_path.join("Library/LaunchAgents/com.icanscale.homesync.plist")
123
+ executable_path = File.expand_path($0 =~ %r{/} ? $0 : %x{which #{$0}})
124
+ launch_agent = <<-EOF
125
+ <?xml version="1.0" encoding="UTF-8"?>
126
+ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
127
+ <plist version="1.0">
128
+ <dict>
129
+ <key>Label</key>
130
+ <string>com.icanscale.homesync</string>
131
+ <key>OnDemand</key>
132
+ <true/>
133
+ <key>ProgramArguments</key>
134
+ <array>
135
+ <string>#{executable_path}</string>
136
+ <string>sync:pref</string>
137
+ </array>
138
+ <key>RunAtLoad</key>
139
+ <true/>
140
+ <key>WatchPaths</key>
141
+ <array>
142
+ <string>#{home_path}/Library/Preferences</string>
143
+ <string>#{homesync_path}/Library/Preferences</string>
144
+ </array>
145
+ </dict>
146
+ </plist>
147
+ EOF
148
+
149
+ if launch_agent_path.exist?
150
+ if launch_agent_path.read == launch_agent
151
+ say "Launch Agent already exists"
152
+ else
153
+ launch_agent_path.open("w") { |f| f.write(launch_agent) }
154
+ say "Updated Launch Agent"
155
+ end
156
+ else
157
+ launch_agent_path.dirname.mkpath
158
+ launch_agent_path.open("w") { |f| f.write(launch_agent) }
159
+ say "Created Launch Agent"
160
+ end
161
+ end
162
+ end
163
+
164
+ end
@@ -0,0 +1,3 @@
1
+ module HomeSync
2
+ VERSION = "0.2"
3
+ end
@@ -0,0 +1 @@
1
+ puts "Hello World!"
@@ -0,0 +1,5 @@
1
+ require 'sinatra'
2
+
3
+ get '/' do
4
+ "Hello World!"
5
+ end
@@ -0,0 +1,2 @@
1
+ require './app'
2
+ run Sinatra::Application
@@ -0,0 +1 @@
1
+ abbreviated
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # with numbers
4
+
5
+ 8.times do |i|
6
+ puts "\e[3#{i}mcolor #{i} \e[1mbold color #{i}\e[0m"
7
+ end
@@ -0,0 +1 @@
1
+ I'm already synced
File without changes
File without changes
@@ -0,0 +1 @@
1
+ Use HomeSync to sync files between your computers
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # with color names
4
+
5
+ %w(black red green yellow blue magenta cyan white).each_with_index do |color, i|
6
+ padding = " " * (7-color.length)
7
+ puts "\e[3#{i}m#{i} #{color}#{padding} \e[1m#{i} bold #{color}\e[0m"
8
+ end
File without changes
@@ -0,0 +1 @@
1
+ I'm already synced
File without changes
File without changes
File without changes
File without changes
@@ -0,0 +1,301 @@
1
+ require 'spec_helper'
2
+
3
+ describe HomeSync::CLI do
4
+
5
+ let(:stdin) { nil }
6
+ let(:stdout) { @stdout }
7
+ let(:stderr) { @stderr }
8
+ let(:command) { "" }
9
+ let(:args) { "" }
10
+ let(:home) { Pathname.new(ENV['HOME']) }
11
+ let(:homesync_path) { home.join("Dropbox/HomeSync") }
12
+
13
+ before do
14
+ setup_fixtures
15
+ @stdout, @stderr = capture_io(stdin) { homesync "#{command} #{args}" }
16
+ end
17
+
18
+ describe '#setup' do
19
+
20
+ let(:command) { "setup" }
21
+
22
+ let(:launch_agent_path) { Pathname.new(File.expand_path("~/Library/LaunchAgents/com.icanscale.homesync.plist")) }
23
+ let(:launch_agent) { launch_agent_path.read }
24
+
25
+ shared_examples_for "a launch agent" do
26
+ specify { launch_agent_path.should exist }
27
+ specify { launch_agent.should =~ %r{<string>#{ENV['HOME']}/Library/Preferences</string>} }
28
+ specify { launch_agent.should =~ %r{<string>#{homesync_path}/Library/Preferences</string>} }
29
+ end
30
+
31
+ shared_examples_for "a launch agent generator" do
32
+ context "when launch agent doesn't exist" do
33
+ specify { stdout.should include("Created Launch Agent") }
34
+ it_should_behave_like "a launch agent"
35
+ end
36
+
37
+ context "when launch agent exists with same content" do
38
+ before do
39
+ @stdout, @stderr = capture_io { homesync "#{command} #{args}" }
40
+ end
41
+
42
+ specify { stdout.should include("Launch Agent already exists") }
43
+ it_should_behave_like "a launch agent"
44
+ end
45
+
46
+ context "when launch agent exists with different content" do
47
+ before do
48
+ launch_agent_path.dirname.mkpath
49
+ File.open(launch_agent_path, "w") { |f| f.write("x") }
50
+ @stdout, @stderr = capture_io { homesync "#{command} #{args}" }
51
+ end
52
+
53
+ specify { stdout.should include("Updated Launch Agent") }
54
+ it_should_behave_like "a launch agent"
55
+ end
56
+ end
57
+
58
+ context "without options" do
59
+ it_should_behave_like "a launch agent generator"
60
+ end
61
+
62
+ context "with -p option" do
63
+ let(:args) { "-p ~/DB/HS" }
64
+ let(:homesync_path) { home.join("DB/HS") }
65
+
66
+ it_should_behave_like "a launch agent generator"
67
+
68
+ context "creates configuration file to store homesync path" do
69
+ specify { stdout.should include("Configuration written to") }
70
+ specify { YAML.load_file(File.expand_path("~/.homesync"))['homesync_path'].should == "~/DB/HS" }
71
+ end
72
+ end
73
+
74
+ end
75
+
76
+ describe '#sync' do
77
+
78
+ let(:command) { "sync" }
79
+
80
+ context "when argument is not under user's home" do
81
+ let(:args) { "/bin/bash" }
82
+ specify { stderr.should include("is not inside your home directory") }
83
+ end
84
+
85
+ context "when argument doesn't exist" do
86
+ context "and matching file in homesync doesn't exist either" do
87
+ let(:args) { "~/404" }
88
+ specify { stderr.should include("doesn't exist") }
89
+ end
90
+
91
+ context "but matching file in homesync does" do
92
+ let(:args) { "~/todo.txt" }
93
+ let(:todo) { home.join("todo.txt") }
94
+
95
+ specify { stdout.should include("Created link to #{ENV['HOME']}/Dropbox/HomeSync/todo.txt") }
96
+
97
+ it "should create a link to the file in HomeSync" do
98
+ todo.readlink.should == homesync_path.join("todo.txt")
99
+ end
100
+ end
101
+ end
102
+
103
+ context "when argument is a link to the matching homesync file" do
104
+ let(:args) { "~/synced" }
105
+ specify { stderr.should include("is already syncing") }
106
+ end
107
+
108
+ context "when argument is a link to somewhere else" do
109
+ let(:args) { "~/existing_link" }
110
+ specify { stderr.should include("is a symlink pointing somewhere else") }
111
+ end
112
+
113
+ context "when argument is a regular file" do
114
+ context "and matching file in homesync doesn't exist" do
115
+ let(:args) { "~/Code/hello_world.rb" }
116
+ let(:original_file) { home.join("Code/hello_world.rb") }
117
+ let(:homesync_file) { homesync_path.join("Code/hello_world.rb") }
118
+
119
+ specify { stdout.should include("Moved #{original_file} to HomeSync and created a symlink to it") }
120
+
121
+ it "should move the original file to HomeSync" do
122
+ homesync_file.should be_file
123
+ end
124
+
125
+ it "should create a link to the file in HomeSync" do
126
+ original_file.readlink.should == homesync_file
127
+ end
128
+ end
129
+
130
+ context "and matching file in homesync also exists" do
131
+ let(:args) { "~/bin/colors" }
132
+ let(:local_path) { home.join("bin/colors") }
133
+ let(:sync_path) { homesync_path.join("bin/colors") }
134
+ let(:contents) { File.read(local_path) }
135
+
136
+ context "without options" do
137
+ context "answering Yes to overwrite local" do
138
+ let(:stdin) { "y\n" }
139
+
140
+ specify { stdout.should include("Overwrite #{local_path}?") }
141
+ specify { stdout.should include("Replaced #{local_path} with symlink to #{sync_path}") }
142
+
143
+ it "should create a link to the file in HomeSync" do
144
+ local_path.readlink.should == sync_path
145
+ end
146
+
147
+ it "should keep the HomeSync version of the file" do
148
+ contents.should include("with numbers")
149
+ end
150
+ end
151
+
152
+ context "answering No to overwrite local and Yes to overwrite HomeSync" do
153
+ let(:stdin) { "n\ny\n" }
154
+
155
+ specify { stdout.should include("Overwrite #{local_path}?") }
156
+ specify { stdout.should include("Overwrite #{sync_path}?") }
157
+ specify { stdout.should include("Replaced #{sync_path} with local version and created symlink to it") }
158
+
159
+ it "should create a link to the file in HomeSync" do
160
+ local_path.readlink.should == sync_path
161
+ end
162
+
163
+ it "should keep the local version of the file" do
164
+ contents.should include("with color names")
165
+ end
166
+ end
167
+
168
+ context "answering No both to overwrite local and HomeSync" do
169
+ let(:stdin) { "n\nn\n" }
170
+
171
+ specify { stdout.should include("Overwrite #{local_path}?") }
172
+ specify { stdout.should include("Overwrite #{sync_path}?") }
173
+ specify { stdout.should include("Kept both versions, syncing has been cancelled") }
174
+
175
+ it "should keep the local file in place" do
176
+ contents.should include("with color names")
177
+ end
178
+
179
+ it "should keep the HomeSync version of the file" do
180
+ File.read(sync_path).should include("with numbers")
181
+ end
182
+ end
183
+ end
184
+
185
+ context "using --overwrite-local option" do
186
+ let(:args) { "~/bin/colors --overwrite-local" }
187
+
188
+ specify { stdout.should include("Replaced #{local_path} with symlink to #{sync_path}") }
189
+
190
+ it "should create a link to the file in HomeSync" do
191
+ local_path.readlink.should == sync_path
192
+ end
193
+
194
+ it "should keep the HomeSync version of the file" do
195
+ contents.should include("with numbers")
196
+ end
197
+ end
198
+
199
+ context "using --overwrite-homesync option" do
200
+ let(:args) { "~/bin/colors --overwrite-homesync" }
201
+
202
+ specify { stdout.should include("Replaced #{sync_path} with local version and created symlink to it") }
203
+
204
+ it "should create a link to the file in HomeSync" do
205
+ local_path.readlink.should == sync_path
206
+ end
207
+
208
+ it "should keep the local version of the file" do
209
+ contents.should include("with color names")
210
+ end
211
+ end
212
+
213
+ context "using both --overwrite-local and --overwrite-homesync options" do
214
+ # this does not make any sense
215
+ let(:args) { "~/bin/colors --overwrite-local --overwrite-homesync" }
216
+ specify { stderr.should include("--overwrite-local and --overwrite-homesync cannot be used together") }
217
+ end
218
+ end
219
+ end
220
+
221
+ context "when argument is a directory" do
222
+ context "and matching directory in homesync doesn't exist" do
223
+ let(:args) { "~/Code/hello_world" }
224
+ let(:original_dir) { home.join("Code/hello_world") }
225
+ let(:homesync_dir) { homesync_path.join("Code/hello_world") }
226
+
227
+ specify { stdout.should include("Moved #{original_dir} to HomeSync and created a symlink to it") }
228
+
229
+ it "should move the original directory to HomeSync" do
230
+ homesync_dir.should be_directory
231
+ end
232
+
233
+ it "should create a link to the directory in HomeSync" do
234
+ original_dir.readlink.should == homesync_dir
235
+ end
236
+ end
237
+
238
+ context "and matching directory in homesync also exists" do
239
+ let(:args) { "~/tasks" }
240
+ let(:local_path) { home.join("tasks") }
241
+ let(:sync_path) { homesync_path.join("tasks") }
242
+ let(:dir_entries) { local_path.entries.map(&:basename).map(&:to_s) - %w(. ..) }
243
+
244
+ context "using --overwrite-local option" do
245
+ let(:args) { "~/tasks --overwrite-local" }
246
+
247
+ specify { stdout.should include("Replaced #{local_path} with symlink to #{sync_path}") }
248
+
249
+ it "should create a link to the directory in HomeSync" do
250
+ local_path.readlink.should == sync_path
251
+ end
252
+
253
+ it "should keep the HomeSync version of the directory" do
254
+ dir_entries.should =~ %w(home work world_hunger)
255
+ end
256
+ end
257
+
258
+ context "using --overwrite-homesync option" do
259
+ let(:args) { "~/tasks --overwrite-homesync" }
260
+
261
+ specify { stdout.should include("Replaced #{sync_path} with local version and created symlink to it") }
262
+
263
+ it "should create a link to the directory in HomeSync" do
264
+ local_path.readlink.should == sync_path
265
+ end
266
+
267
+ it "should keep the local version of the directory" do
268
+ dir_entries.should =~ %w(home garden shopping)
269
+ end
270
+ end
271
+ end
272
+ end
273
+
274
+ context "with custom homesync path" do
275
+ let(:contents) { File.read(home.join("custom_homesync")).chomp }
276
+
277
+ context "provided by the -p option" do
278
+ let(:args) { "~/custom_homesync -p ~/DB/HS" }
279
+
280
+ it "should create the link to the file in the custom homesync path" do
281
+ contents.should == "abbreviated"
282
+ end
283
+ end
284
+
285
+ context "stored in ~/.homesync configuration" do
286
+ let(:args) { "~/custom_homesync" }
287
+
288
+ before do
289
+ home.join(".homesync").open("w") {|f| f.write({'homesync_path' => "~/Dropbox/.homesync"}.to_yaml)}
290
+ @stdout, @stderr = capture_io { homesync "#{command} #{args}" }
291
+ end
292
+
293
+ it "should create the link to the file in the custom homesync path" do
294
+ contents.should == "hidden"
295
+ end
296
+ end
297
+ end
298
+
299
+ end
300
+
301
+ end
@@ -0,0 +1,37 @@
1
+ require 'homesync'
2
+ require 'stringio'
3
+
4
+ RSpec.configure do |config|
5
+ config.color_enabled = true
6
+ #config.filter_run :focus => true
7
+
8
+ def capture_io(stdin=nil)
9
+ begin
10
+ $stdin = StringIO.new(stdin) unless stdin.nil?
11
+ $stdout = StringIO.new
12
+ $stderr = StringIO.new
13
+ yield
14
+ result = [ $stdout.string, $stderr.string ]
15
+ ensure
16
+ $stdin = STDIN
17
+ $stdout = STDOUT
18
+ $stderr = STDERR
19
+ end
20
+ result
21
+ end
22
+
23
+ alias :silence :capture_io
24
+ end
25
+
26
+ def homesync(arguments)
27
+ HomeSync::CLI.start(arguments.split(/\s+/))
28
+ end
29
+
30
+ def setup_fixtures
31
+ tmp_path = Pathname.new(__FILE__).dirname.join("../tmp/test").expand_path
32
+ tmp_path.rmtree if tmp_path.exist?
33
+ tmp_path.join("Users").mkpath
34
+ ENV['HOME'] = "#{tmp_path}/Users/Alice"
35
+ fixtures = Pathname.new(__FILE__).dirname.join("fixtures/home")
36
+ %x{ cp -a #{fixtures} #{ENV['HOME']} }
37
+ end
metadata ADDED
@@ -0,0 +1,128 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: homesync
3
+ version: !ruby/object:Gem::Version
4
+ version: '0.2'
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Laszlo Bacsi
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2011-10-02 00:00:00.000000000Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: thor
16
+ requirement: &2152072400 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ~>
20
+ - !ruby/object:Gem::Version
21
+ version: 0.14.6
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: *2152072400
25
+ - !ruby/object:Gem::Dependency
26
+ name: rspec
27
+ requirement: &2152070720 !ruby/object:Gem::Requirement
28
+ none: false
29
+ requirements:
30
+ - - ~>
31
+ - !ruby/object:Gem::Version
32
+ version: 2.6.0
33
+ type: :development
34
+ prerelease: false
35
+ version_requirements: *2152070720
36
+ - !ruby/object:Gem::Dependency
37
+ name: guard
38
+ requirement: &2152069240 !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - ~>
42
+ - !ruby/object:Gem::Version
43
+ version: 0.8.3
44
+ type: :development
45
+ prerelease: false
46
+ version_requirements: *2152069240
47
+ - !ruby/object:Gem::Dependency
48
+ name: guard-rspec
49
+ requirement: &2152067860 !ruby/object:Gem::Requirement
50
+ none: false
51
+ requirements:
52
+ - - ~>
53
+ - !ruby/object:Gem::Version
54
+ version: 0.4.0
55
+ type: :development
56
+ prerelease: false
57
+ version_requirements: *2152067860
58
+ description: ! 'HomeSync makes it easy to synchronize any file under your home directory
59
+
60
+ with other machines through Dropbox by providing a simple commandline
61
+
62
+ interface for adding and removing symlinks to your files. Furthermore,
63
+
64
+ it knows how to handle several key directories correctly and how to
65
+
66
+ synchronize application preferences and data.
67
+
68
+ '
69
+ email: lackac@icanscale.com
70
+ executables:
71
+ - homesync
72
+ extensions: []
73
+ extra_rdoc_files: []
74
+ files:
75
+ - bin/homesync
76
+ - lib/homesync/cli.rb
77
+ - lib/homesync/version.rb
78
+ - lib/homesync.rb
79
+ - spec/fixtures/home/bin/colors
80
+ - spec/fixtures/home/Code/hello_world/app.rb
81
+ - spec/fixtures/home/Code/hello_world/config.ru
82
+ - spec/fixtures/home/Code/hello_world.rb
83
+ - spec/fixtures/home/DB/HS/custom_homesync
84
+ - spec/fixtures/home/Dropbox/HomeSync/bin/colors
85
+ - spec/fixtures/home/Dropbox/HomeSync/synced
86
+ - spec/fixtures/home/Dropbox/HomeSync/tasks/home
87
+ - spec/fixtures/home/Dropbox/HomeSync/tasks/work
88
+ - spec/fixtures/home/Dropbox/HomeSync/tasks/world_hunger
89
+ - spec/fixtures/home/Dropbox/HomeSync/todo.txt
90
+ - spec/fixtures/home/existing_link
91
+ - spec/fixtures/home/synced
92
+ - spec/fixtures/home/tasks/garden
93
+ - spec/fixtures/home/tasks/home
94
+ - spec/fixtures/home/tasks/shopping
95
+ - spec/fixtures/home/to/infinity/and/beyond
96
+ - spec/homesync/cli_spec.rb
97
+ - spec/spec_helper.rb
98
+ - README.md
99
+ - LICENSE
100
+ - Gemfile
101
+ homepage: http://github.com/lackac/homesync
102
+ licenses: []
103
+ post_install_message:
104
+ rdoc_options: []
105
+ require_paths:
106
+ - lib
107
+ required_ruby_version: !ruby/object:Gem::Requirement
108
+ none: false
109
+ requirements:
110
+ - - ! '>='
111
+ - !ruby/object:Gem::Version
112
+ version: '0'
113
+ segments:
114
+ - 0
115
+ hash: 1059405670017922565
116
+ required_rubygems_version: !ruby/object:Gem::Requirement
117
+ none: false
118
+ requirements:
119
+ - - ! '>='
120
+ - !ruby/object:Gem::Version
121
+ version: 1.3.6
122
+ requirements: []
123
+ rubyforge_project: nowarning
124
+ rubygems_version: 1.8.7
125
+ signing_key:
126
+ specification_version: 3
127
+ summary: HomeSync helps you synchronize your files with other machines through Dropbox.
128
+ test_files: []