homesync 0.2

Sign up to get free protection for your applications and to get access to all the features.
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: []