yahomesick 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/.document ADDED
@@ -0,0 +1,5 @@
1
+ README.rdoc
2
+ lib/**/*.rb
3
+ bin/*
4
+ features/**/*.feature
5
+ LICENSE
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --color
@@ -0,0 +1,56 @@
1
+ # 0.7.0
2
+ * Fixed double-cloning #14
3
+ * New option for pull command: --all
4
+ * pulls each castle, instead of just one
5
+
6
+ # 0.6.1
7
+
8
+ * Add a license
9
+
10
+ # 0.6.0
11
+
12
+ * Introduce .homesickrc
13
+ * Castles can now have a .homesickrc inside them
14
+ * On clone, this is eval'd inside the destination directory
15
+ * Introduce track command
16
+ * Allows easily moving an existing file into a castle, and symlinking it back
17
+
18
+ # 0.5.0
19
+
20
+ * Fixed listing of castles cloned using `homesick clone <github-user>/<github-repo>` (issue 3)
21
+ * Added `homesick pull <CASTLE>` for updating castles (thanks Jorge Dias!)
22
+ * Added a very basic `homesick generate <CASTLE>`
23
+
24
+ # 0.4.1
25
+
26
+ * Improved error message when a castle's home dir doesn't exist
27
+
28
+ # 0.4.0
29
+
30
+ * `homesick clone` can now take a path to a directory on the filesystem, which will be symlinked into place
31
+ * `homesick clone` now tries to `git submodule init` and `git submodule update` if git submodules are defined for a cloned repo
32
+ * Fixed missing dependency on thor and others
33
+ * Use HOME environment variable for where to store files, instead of assuming ~
34
+
35
+ # 0.3.0
36
+
37
+ * Renamed 'link' to 'symlink'
38
+ * Fixed conflict resolution when symlink destination exists and is a normal file
39
+
40
+ # 0.2.0
41
+
42
+ * Better support for recognizing git urls (thanks jacobat!)
43
+ * if it looks like a github user/repo, do that
44
+ * otherwise hand off to git clone
45
+ * Listing now displays in color, and show git remote
46
+ * Support pretend, force, and quiet modes
47
+
48
+ # 0.1.1
49
+
50
+ * Fixed trying to link against castles that don't exist
51
+ * Fixed linking, which tries to exclude . and .. from the list of files to
52
+ link (thanks Martinos!)
53
+
54
+ # 0.1.0
55
+
56
+ * Initial release
data/Gemfile ADDED
@@ -0,0 +1,15 @@
1
+ source :gemcutter
2
+
3
+ # Add dependencies required to use your gem here.
4
+ gem "thor", ">= 0.14.0"
5
+
6
+ # Add dependencies to develop your gem here.
7
+ # Include everything needed to run rake, tests, features, etc.
8
+ group :development do
9
+ gem "rake", "~> 0.8.7"
10
+ gem "rspec", "~> 2.10"
11
+ gem "jeweler", ">= 1.6.2"
12
+ gem "rcov", :platforms => :mri_18
13
+ gem "simplecov", :platforms => :mri_19
14
+ gem "test-construct"
15
+ end
data/Gemfile.lock ADDED
@@ -0,0 +1,42 @@
1
+ GEM
2
+ remote: http://rubygems.org/
3
+ specs:
4
+ diff-lcs (1.1.3)
5
+ git (1.2.5)
6
+ jeweler (1.8.3)
7
+ bundler (~> 1.0)
8
+ git (>= 1.2.5)
9
+ rake
10
+ rdoc
11
+ json (1.7.3)
12
+ multi_json (1.3.6)
13
+ rake (0.8.7)
14
+ rcov (1.0.0)
15
+ rdoc (3.12)
16
+ json (~> 1.4)
17
+ rspec (2.10.0)
18
+ rspec-core (~> 2.10.0)
19
+ rspec-expectations (~> 2.10.0)
20
+ rspec-mocks (~> 2.10.0)
21
+ rspec-core (2.10.1)
22
+ rspec-expectations (2.10.0)
23
+ diff-lcs (~> 1.1.3)
24
+ rspec-mocks (2.10.1)
25
+ simplecov (0.6.4)
26
+ multi_json (~> 1.0)
27
+ simplecov-html (~> 0.5.3)
28
+ simplecov-html (0.5.3)
29
+ test-construct (1.2.0)
30
+ thor (0.15.2)
31
+
32
+ PLATFORMS
33
+ ruby
34
+
35
+ DEPENDENCIES
36
+ jeweler (>= 1.6.2)
37
+ rake (~> 0.8.7)
38
+ rcov
39
+ rspec (~> 2.10)
40
+ simplecov
41
+ test-construct
42
+ thor (>= 0.14.0)
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2009 Joshua Nichols
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.markdown ADDED
@@ -0,0 +1,68 @@
1
+ # homesick
2
+
3
+ A man's home (directory) is his castle, so don't leave home with out it.
4
+
5
+ Homesick is sorta like [rip](http://github.com/defunkt/rip), but for dotfiles. It uses git to clone a repository containing dotfiles, and saves them in `~/.homesick`. It then allows you to symlink all the dotfiles into place with a single command.
6
+
7
+ We call a repository that is compatible with homesick to be a 'castle'. To act as a castle, a repository must be organized like so:
8
+
9
+ * Contains a 'home' directory
10
+ * 'home' contains any number of files and directories that begin with '.'
11
+
12
+ To get started, install homesick first:
13
+
14
+ git clone https://github.com/muratayusuke/homesick.git
15
+ cd homesick/gems
16
+ gem install homesick.gem
17
+
18
+ Next, you use the homesick command to clone a castle:
19
+
20
+ homesick clone git://github.com/technicalpickles/pickled-vim.git
21
+
22
+ Alternatively, if it's on github, there's a slightly shorter way:
23
+
24
+ homesick clone technicalpickles/pickled-vim
25
+
26
+ With the castle cloned, you can now link its contents into your home dir:
27
+
28
+ homesick symlink pickled-vim
29
+
30
+ If you use the shorthand syntax for GitHub repositories in your clone, please note you will instead need to run:
31
+
32
+ homesick symlink technicalpickles/pickled-vim
33
+
34
+ If you're not sure what castles you have around, you can easily list them:
35
+
36
+ homesick list
37
+
38
+ To pull your castle (or all castles):
39
+
40
+ homesick pull --all|CASTLE
41
+
42
+ To commit your castle's changes:
43
+
44
+ homesick commit CASTLE
45
+
46
+ To push your castle:
47
+
48
+ homesick push CASTLE
49
+
50
+ Not sure what else homesick has up its sleeve? There's always the built in help:
51
+
52
+ homesick help
53
+
54
+ ## Note on Patches/Pull Requests
55
+
56
+ * Fork the project.
57
+ * Make your feature addition or bug fix.
58
+ * Add tests for it. This is important so I don't break it in a future version unintentionally.
59
+ * Commit, do not mess with rakefile, version, or history. (if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
60
+ * Send me a pull request. Bonus points for topic branches.
61
+
62
+ ## Need homesick without the ruby dependency?
63
+
64
+ Check out [homeshick](https://github.com/andsens/homeshick).
65
+
66
+ ## Copyright
67
+
68
+ Copyright (c) 2010 Joshua Nichols. See LICENSE for details.
data/Rakefile ADDED
@@ -0,0 +1,56 @@
1
+ require 'rubygems'
2
+ require 'bundler'
3
+ begin
4
+ Bundler.setup(:default, :development)
5
+ rescue Bundler::BundlerError => e
6
+ $stderr.puts e.message
7
+ $stderr.puts "Run `bundle install` to install missing gems"
8
+ exit e.status_code
9
+ end
10
+ require 'rake'
11
+
12
+ require 'jeweler'
13
+ Jeweler::Tasks.new do |gem|
14
+ gem.name = "homesick"
15
+ gem.summary = %Q{A man's home is his castle. Never leave your dotfiles behind.}
16
+ gem.description = %Q{
17
+ A man's home (directory) is his castle, so don't leave home with out it.
18
+
19
+ Homesick is sorta like rip, but for dotfiles. It uses git to clone a repository containing dotfiles, and saves them in ~/.homesick. It then allows you to symlink all the dotfiles into place with a single command.
20
+
21
+ }
22
+ gem.email = "josh@technicalpickles.com"
23
+ gem.homepage = "http://github.com/technicalpickles/homesick"
24
+ gem.authors = ["Joshua Nichols"]
25
+ gem.version = "0.7.0"
26
+ gem.license = "MIT"
27
+ # Have dependencies? Add them to Gemfile
28
+
29
+ # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
30
+ end
31
+ Jeweler::GemcutterTasks.new
32
+
33
+
34
+ require 'rspec/core/rake_task'
35
+ RSpec::Core::RakeTask.new(:spec) do |spec|
36
+ spec.pattern = FileList['spec/**/*_spec.rb']
37
+ end
38
+
39
+ RSpec::Core::RakeTask.new(:rcov) do |spec|
40
+ spec.pattern = 'spec/**/*_spec.rb'
41
+ spec.rcov = true
42
+ end
43
+
44
+
45
+ task :default => :spec
46
+
47
+ require 'rake/rdoctask'
48
+ Rake::RDocTask.new do |rdoc|
49
+ version = File.exist?('VERSION') ? File.read('VERSION') : ""
50
+
51
+ rdoc.rdoc_dir = 'rdoc'
52
+ rdoc.title = "homesick #{version}"
53
+ rdoc.rdoc_files.include('README*')
54
+ rdoc.rdoc_files.include('lib/**/*.rb')
55
+ end
56
+
data/bin/homesick ADDED
@@ -0,0 +1,9 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'pathname'
4
+ lib = Pathname.new(__FILE__).dirname.join('..', 'lib').expand_path
5
+ $LOAD_PATH.unshift lib.to_s
6
+
7
+ require 'homesick'
8
+
9
+ Homesick.start
data/gems/homesick.gem ADDED
Binary file
data/homesick.gemspec ADDED
@@ -0,0 +1,75 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = "homesick"
8
+ s.version = "0.7.5"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Yusuke Murata"]
12
+ s.date = "2012-12-15"
13
+ s.description = "\n A man's home (directory) is his castle, so don't leave home with out it.\n\n Homesick is sorta like rip, but for dotfiles. It uses git to clone a repository containing dotfiles, and saves them in ~/.homesick. It then allows you to symlink all the dotfiles into place with a single command. \n\n "
14
+ s.email = "info@muratayusuke.com"
15
+ s.executables = ["homesick"]
16
+ s.extra_rdoc_files = [
17
+ "ChangeLog.markdown",
18
+ "LICENSE",
19
+ "README.markdown"
20
+ ]
21
+ s.files = [
22
+ ".document",
23
+ ".rspec",
24
+ "ChangeLog.markdown",
25
+ "Gemfile",
26
+ "Gemfile.lock",
27
+ "LICENSE",
28
+ "README.markdown",
29
+ "Rakefile",
30
+ "bin/homesick",
31
+ "homesick.gemspec",
32
+ "lib/homesick.rb",
33
+ "lib/homesick/actions.rb",
34
+ "lib/homesick/shell.rb",
35
+ "spec/homesick_spec.rb",
36
+ "spec/spec.opts",
37
+ "spec/spec_helper.rb"
38
+ ]
39
+ s.homepage = "http://github.com/technicalpickles/homesick"
40
+ s.licenses = ["MIT"]
41
+ s.require_paths = ["lib"]
42
+ s.rubygems_version = "1.8.15"
43
+ s.summary = "A man's home is his castle. Never leave your dotfiles behind."
44
+
45
+ if s.respond_to? :specification_version then
46
+ s.specification_version = 3
47
+
48
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
49
+ s.add_runtime_dependency(%q<thor>, [">= 0.14.0"])
50
+ s.add_development_dependency(%q<rake>, [">= 0"])
51
+ s.add_development_dependency(%q<rspec>, ["~> 2.1.0"])
52
+ s.add_development_dependency(%q<jeweler>, [">= 1.6.2"])
53
+ s.add_development_dependency(%q<rcov>, [">= 0"])
54
+ s.add_development_dependency(%q<test-construct>, [">= 0"])
55
+ s.add_development_dependency(%q<ruby-debug>, [">= 0"])
56
+ else
57
+ s.add_dependency(%q<thor>, [">= 0.14.0"])
58
+ s.add_dependency(%q<rake>, [">= 0"])
59
+ s.add_dependency(%q<rspec>, ["~> 2.1.0"])
60
+ s.add_dependency(%q<jeweler>, [">= 1.6.2"])
61
+ s.add_dependency(%q<rcov>, [">= 0"])
62
+ s.add_dependency(%q<test-construct>, [">= 0"])
63
+ s.add_dependency(%q<ruby-debug>, [">= 0"])
64
+ end
65
+ else
66
+ s.add_dependency(%q<thor>, [">= 0.14.0"])
67
+ s.add_dependency(%q<rake>, [">= 0"])
68
+ s.add_dependency(%q<rspec>, ["~> 2.1.0"])
69
+ s.add_dependency(%q<jeweler>, [">= 1.6.2"])
70
+ s.add_dependency(%q<rcov>, [">= 0"])
71
+ s.add_dependency(%q<test-construct>, [">= 0"])
72
+ s.add_dependency(%q<ruby-debug>, [">= 0"])
73
+ end
74
+ end
75
+
data/lib/homesick.rb ADDED
@@ -0,0 +1,218 @@
1
+ require 'thor'
2
+
3
+ class Homesick < Thor
4
+ autoload :Shell, 'homesick/shell'
5
+ autoload :Actions, 'homesick/actions'
6
+
7
+ include Thor::Actions
8
+ include Homesick::Actions
9
+
10
+ add_runtime_options!
11
+
12
+ GITHUB_NAME_REPO_PATTERN = /\A([A-Za-z_-]+\/[A-Za-z_-]+)\Z/
13
+
14
+ def initialize(args=[], options={}, config={})
15
+ super
16
+ self.shell = Homesick::Shell.new
17
+ end
18
+
19
+ desc "clone URI", "Clone +uri+ as a castle for homesick"
20
+ def clone(uri)
21
+ inside repos_dir do
22
+ destination = nil
23
+ if File.exist?(uri)
24
+ uri = Pathname.new(uri).expand_path
25
+ if uri.to_s.start_with?(repos_dir.to_s)
26
+ raise "Castle already cloned to #{uri}"
27
+ end
28
+
29
+ destination = uri.basename
30
+
31
+ ln_s uri, destination
32
+ elsif uri =~ GITHUB_NAME_REPO_PATTERN
33
+ destination = Pathname.new($1)
34
+ git_clone "git@github.com:#{$1}.git", :destination => destination
35
+ elsif uri =~ /\/([^\/]*)(\.git)?\Z/
36
+ destination = Pathname.new($1)
37
+ git_clone uri
38
+ elsif uri =~ /[^:]+:([^:]+)(\.git)?\Z/
39
+ destination = Pathname.new($1)
40
+ git_clone uri
41
+ else
42
+ raise "Unknown URI format: #{uri}"
43
+ end
44
+
45
+ if destination.join('.gitmodules').exist?
46
+ inside destination do
47
+ git_submodule_init
48
+ git_submodule_update
49
+ end
50
+ end
51
+
52
+ homesickrc = destination.join('.homesickrc').expand_path
53
+ if homesickrc.exist?
54
+ proceed = shell.yes?("#{uri} has a .homesickrc. Proceed with evaling it? (This could be destructive)")
55
+ if proceed
56
+ shell.say_status "eval", homesickrc
57
+ inside destination do
58
+ eval homesickrc.read, binding, homesickrc.expand_path
59
+ end
60
+ else
61
+ shell.say_status "eval skip", "not evaling #{homesickrc}, #{destination} may need manual configuration", :blue
62
+ end
63
+ end
64
+ end
65
+ end
66
+
67
+ desc "pull CASTLE", "Update the specified castle"
68
+ method_option :all, :type => :boolean, :default => false, :required => false, :desc => "Update all cloned castles"
69
+ def pull(name="")
70
+ if options[:all]
71
+ inside_each_castle do |castle|
72
+ shell.say castle.to_s.gsub(repos_dir.to_s + '/', '') + ':'
73
+ update_castle castle
74
+ end
75
+ else
76
+ update_castle name
77
+ end
78
+
79
+ end
80
+
81
+ desc "commit CASTLE", "Commit the specified castle's changes"
82
+ def commit(name)
83
+ commit_castle name
84
+
85
+ end
86
+
87
+ desc "push CASTLE", "Push the specified castle"
88
+ def push(name)
89
+ push_castle name
90
+
91
+ end
92
+
93
+ desc "symlink CASTLE", "Symlinks all dotfiles from the specified castle"
94
+ method_option :force, :default => false, :desc => "Overwrite existing conflicting symlinks without prompting."
95
+ def symlink(name)
96
+ check_castle_existance(name, "symlink")
97
+
98
+ inside castle_dir(name) do
99
+ files = Pathname.glob('{.*,*}').reject{|a| [".",".."].include?(a.to_s)}
100
+ files.each do |path|
101
+ absolute_path = path.expand_path
102
+
103
+ inside home_dir do
104
+ adjusted_path = (home_dir + path).basename
105
+
106
+ ln_s absolute_path, adjusted_path
107
+ end
108
+ end
109
+ end
110
+ end
111
+
112
+ desc "track FILE CASTLE", "add a file to a castle"
113
+ def track(file, castle)
114
+ castle = Pathname.new(castle)
115
+ file = Pathname.new(file)
116
+ check_castle_existance(castle, 'track')
117
+
118
+ absolute_path = file.expand_path
119
+ castle_path = castle_dir(castle)
120
+ mv absolute_path, castle_path
121
+
122
+ inside home_dir do
123
+ absolute_path = castle_dir(castle) + file.basename
124
+ home_path = home_dir + file
125
+ ln_s absolute_path, home_path
126
+ end
127
+ end
128
+
129
+ desc "list", "List cloned castles"
130
+ def list
131
+ inside_each_castle do |castle|
132
+ say_status castle.relative_path_from(repos_dir).to_s, `git config remote.origin.url`.chomp, :cyan
133
+ end
134
+ end
135
+
136
+ desc "generate PATH", "generate a homesick-ready git repo at PATH"
137
+ def generate(castle)
138
+ castle = Pathname.new(castle).expand_path
139
+
140
+ github_user = `git config github.user`.chomp
141
+ github_user = nil if github_user == ""
142
+ github_repo = castle.basename
143
+
144
+ empty_directory castle
145
+ inside castle do
146
+ git_init
147
+ if github_user
148
+ url = "git@github.com:#{github_user}/#{github_repo}.git"
149
+ git_remote_add 'origin', url
150
+ end
151
+
152
+ empty_directory "home"
153
+ end
154
+ end
155
+
156
+
157
+ protected
158
+
159
+ def home_dir
160
+ @home_dir ||= Pathname.new(ENV['HOME'] || '~').expand_path
161
+ end
162
+
163
+ def repos_dir
164
+ @repos_dir ||= home_dir.join('.homesick', 'repos').expand_path
165
+ end
166
+
167
+ def castle_dir(name)
168
+ repos_dir.join(name, 'home')
169
+ end
170
+
171
+ def check_castle_existance(name, action)
172
+ unless castle_dir(name).exist?
173
+ say_status :error, "Could not #{action} #{name}, expected #{castle_dir(name)} exist and contain dotfiles", :red
174
+
175
+ exit(1)
176
+ end
177
+ end
178
+
179
+ def all_castles
180
+ dirs = Pathname.glob("#{repos_dir}/**/*/.git")
181
+ # reject paths that lie inside another castle, like git submodules
182
+ return dirs.reject do |dir|
183
+ dirs.any? {|other| dir != other && dir.fnmatch(other.parent.join('*').to_s) }
184
+ end
185
+ end
186
+
187
+ def inside_each_castle(&block)
188
+ all_castles.each do |git_dir|
189
+ castle = git_dir.dirname
190
+ Dir.chdir castle do # so we can call git config from the right contxt
191
+ yield castle
192
+ end
193
+ end
194
+ end
195
+
196
+ def update_castle(castle)
197
+ check_castle_existance(castle, "pull")
198
+ inside repos_dir.join(castle) do
199
+ git_pull
200
+ git_submodule_init
201
+ git_submodule_update
202
+ end
203
+ end
204
+
205
+ def commit_castle(castle)
206
+ check_castle_existance(castle, "commit")
207
+ inside repos_dir.join(castle) do
208
+ git_commit_all
209
+ end
210
+ end
211
+
212
+ def push_castle(castle)
213
+ check_castle_existance(castle, "push")
214
+ inside repos_dir.join(castle) do
215
+ git_push
216
+ end
217
+ end
218
+ end
@@ -0,0 +1,121 @@
1
+ class Homesick
2
+ module Actions
3
+ # TODO move this to be more like thor's template, empty_directory, etc
4
+ def git_clone(repo, config = {})
5
+ config ||= {}
6
+ destination = config[:destination] || begin
7
+ repo =~ /([^\/]+)(?:\.git)?$/
8
+ $1
9
+ end
10
+
11
+ destination = Pathname.new(destination) unless destination.kind_of?(Pathname)
12
+ FileUtils.mkdir_p destination.dirname
13
+
14
+ if ! destination.directory?
15
+ say_status 'git clone', "#{repo} to #{destination.expand_path}", :green unless options[:quiet]
16
+ ok = system "git clone -q #{repo} #{destination}" unless options[:pretend]
17
+ # Fallback to HTTPS
18
+ unless ok
19
+ say_status 'git clone', "#{repo} failed, trying HTTP", :green unless options[:quiet]
20
+ repo.sub!(/:/, '/')
21
+ repo.sub!(/git@/, 'https://')
22
+ system "git clone -q #{repo} #{destination}" unless options[:pretend]
23
+ end
24
+ else
25
+ say_status :exist, destination.expand_path, :blue unless options[:quiet]
26
+ end
27
+ end
28
+
29
+ def git_init(path = ".")
30
+ path = Pathname.new(path)
31
+
32
+ inside path do
33
+ unless path.join('.git').exist?
34
+ say_status 'git init', '' unless options[:quiet]
35
+ system "git init >/dev/null" unless options[:pretend]
36
+ else
37
+ say_status 'git init', 'already initialized', :blue unless options[:quiet]
38
+ end
39
+ end
40
+ end
41
+
42
+ def git_remote_add(name, url)
43
+ existing_remote = `git config remote.#{name}.url`.chomp
44
+ existing_remote = nil if existing_remote == ''
45
+
46
+ unless existing_remote
47
+ say_status 'git remote', "add #{name} #{url}" unless options[:quiet]
48
+ system "git remote add #{name} #{url}" unless options[:pretend]
49
+ else
50
+ say_status 'git remote', "#{name} already exists", :blue unless options[:quiet]
51
+ end
52
+ end
53
+
54
+ def git_submodule_init(config = {})
55
+ say_status 'git submodule', 'init', :green unless options[:quiet]
56
+ system "git submodule --quiet init" unless options[:pretend]
57
+ end
58
+
59
+ def git_submodule_update(config = {})
60
+ say_status 'git submodule', 'update', :green unless options[:quiet]
61
+ system "git submodule --quiet update --init --recursive >/dev/null 2>&1" unless options[:pretend]
62
+ end
63
+
64
+ def git_pull(config = {})
65
+ say_status 'git pull', '', :green unless options[:quiet]
66
+ system "git pull --quiet" unless options[:pretend]
67
+ end
68
+
69
+ def git_push(config = {})
70
+ say_status 'git push', '', :green unless options[:quiet]
71
+ system "git push" unless options[:pretend]
72
+ end
73
+
74
+ def git_commit_all(config = {})
75
+ say_status 'git commit all', '', :green unless options[:quiet]
76
+ system "git commit -v -a" unless options[:pretend]
77
+ end
78
+
79
+ def mv(source, destination, config = {})
80
+ source = Pathname.new(source)
81
+ destination = Pathname.new(destination + source.basename)
82
+
83
+ if destination.exist?
84
+ say_status :conflict, "#{destination} exists", :red unless options[:quiet]
85
+
86
+ if options[:force] || shell.file_collision(destination) { source }
87
+ system "mv #{source} #{destination}" unless options[:pretend]
88
+ end
89
+ else
90
+ # this needs some sort of message here.
91
+ system "mv #{source} #{destination}" unless options[:pretend]
92
+ end
93
+ end
94
+
95
+ def ln_s(source, destination, config = {})
96
+ source = Pathname.new(source)
97
+ destination = Pathname.new(destination)
98
+
99
+ if destination.symlink?
100
+ if destination.readlink == source
101
+ say_status :identical, destination.expand_path, :blue unless options[:quiet]
102
+ else
103
+ say_status :conflict, "#{destination} exists and points to #{destination.readlink}", :red unless options[:quiet]
104
+
105
+ if options[:force] || shell.file_collision(destination) { source }
106
+ system "ln -nsf #{source} #{destination}" unless options[:pretend]
107
+ end
108
+ end
109
+ elsif destination.exist?
110
+ say_status :conflict, "#{destination} exists", :red unless options[:quiet]
111
+
112
+ if options[:force] || shell.file_collision(destination) { source }
113
+ system "ln -sf #{source} #{destination}" unless options[:pretend]
114
+ end
115
+ else
116
+ say_status :symlink, "#{source.expand_path} to #{destination.expand_path}", :green unless options[:quiet]
117
+ system "ln -s #{source} #{destination}" unless options[:pretend]
118
+ end
119
+ end
120
+ end
121
+ end
@@ -0,0 +1,17 @@
1
+ class Homesick
2
+ # Hack in support for diffing symlinks
3
+ class Shell < Thor::Shell::Color
4
+
5
+ def show_diff(destination, content)
6
+ destination = Pathname.new(destination)
7
+
8
+ if destination.symlink?
9
+ say "- #{destination.readlink}", :red, true
10
+ say "+ #{content.expand_path}", :green, true
11
+ else
12
+ super
13
+ end
14
+ end
15
+
16
+ end
17
+ end
@@ -0,0 +1,173 @@
1
+ require 'spec_helper'
2
+
3
+ describe "homesick" do
4
+ let(:home) { create_construct }
5
+ after { home.destroy! }
6
+
7
+ let(:castles) { home.directory(".homesick/repos") }
8
+
9
+ let(:homesick) { Homesick.new }
10
+
11
+ before { homesick.stub!(:repos_dir).and_return(castles) }
12
+
13
+ describe "clone" do
14
+ context "of a file" do
15
+ it "should symlink existing directories" do
16
+ somewhere = create_construct
17
+ local_repo = somewhere.directory('wtf')
18
+
19
+ homesick.clone local_repo
20
+
21
+ castles.join("wtf").readlink.should == local_repo
22
+ end
23
+
24
+ context "when it exists in a repo directory" do
25
+ before do
26
+ existing_castle = given_castle("existing_castle")
27
+ @existing_dir = existing_castle.parent
28
+ end
29
+
30
+ it "should not symlink" do
31
+ homesick.should_not_receive(:git_clone)
32
+
33
+ homesick.clone @existing_dir.to_s rescue nil
34
+ end
35
+
36
+ it "should raise an error" do
37
+ expect { homesick.clone @existing_dir.to_s }.to raise_error(/already cloned/i)
38
+ end
39
+ end
40
+ end
41
+
42
+ it "should clone git repo like git://host/path/to.git" do
43
+ homesick.should_receive(:git_clone).with('git://github.com/technicalpickles/pickled-vim.git')
44
+
45
+ homesick.clone "git://github.com/technicalpickles/pickled-vim.git"
46
+ end
47
+
48
+ it "should clone git repo like git@host:path/to.git" do
49
+ homesick.should_receive(:git_clone).with('git@github.com:technicalpickles/pickled-vim.git')
50
+
51
+ homesick.clone 'git@github.com:technicalpickles/pickled-vim.git'
52
+ end
53
+
54
+ it "should clone git repo like http://host/path/to.git" do
55
+ homesick.should_receive(:git_clone).with('http://github.com/technicalpickles/pickled-vim.git')
56
+
57
+ homesick.clone 'http://github.com/technicalpickles/pickled-vim.git'
58
+ end
59
+
60
+ it "should clone git repo like http://host/path/to" do
61
+ homesick.should_receive(:git_clone).with('http://github.com/technicalpickles/pickled-vim')
62
+
63
+ homesick.clone 'http://github.com/technicalpickles/pickled-vim'
64
+ end
65
+
66
+ it "should clone git repo like host-alias:repos.git" do
67
+ homesick.should_receive(:git_clone).with('gitolite:pickled-vim.git')
68
+
69
+ homesick.clone 'gitolite:pickled-vim.git'
70
+ end
71
+
72
+ it "should not try to clone a malformed uri like malformed" do
73
+ homesick.should_not_receive(:git_clone)
74
+
75
+ homesick.clone 'malformed' rescue nil
76
+ end
77
+
78
+ it "should throw an exception when trying to clone a malformed uri like malformed" do
79
+ expect { homesick.clone 'malformed' }.to raise_error
80
+ end
81
+
82
+ it "should clone a github repo" do
83
+ homesick.should_receive(:git_clone).with('git://github.com/wfarr/dotfiles.git', :destination => Pathname.new('wfarr/dotfiles'))
84
+
85
+ homesick.clone "wfarr/dotfiles"
86
+ end
87
+ end
88
+
89
+ describe "symlink" do
90
+ let(:castle) { given_castle("glencairn") }
91
+
92
+ it "links dotfiles from a castle to the home folder" do
93
+ dotfile = castle.file(".some_dotfile")
94
+
95
+ homesick.symlink("glencairn")
96
+
97
+ home.join(".some_dotfile").readlink.should == dotfile
98
+ end
99
+
100
+ it "links non-dotfiles from a castle to the home folder" do
101
+ dotfile = castle.file("bin")
102
+
103
+ homesick.symlink("glencairn")
104
+
105
+ home.join("bin").readlink.should == dotfile
106
+ end
107
+
108
+ context "when forced" do
109
+ let(:homesick) { Homesick.new [], :force => true }
110
+
111
+ it "can override symlinks to directories" do
112
+ somewhere_else = create_construct
113
+ existing_dotdir_link = home.join(".vim")
114
+ FileUtils.ln_s somewhere_else, existing_dotdir_link
115
+
116
+ dotdir = castle.directory(".vim")
117
+
118
+ homesick.symlink("glencairn")
119
+
120
+ existing_dotdir_link.readlink.should == dotdir
121
+ end
122
+ end
123
+ end
124
+
125
+ describe "list" do
126
+ it "should say each castle in the castle directory" do
127
+ given_castle('zomg')
128
+ given_castle('zomg', 'wtf/zomg')
129
+
130
+ homesick.should_receive(:say_status).with("zomg", "git://github.com/technicalpickles/zomg.git", :cyan)
131
+ homesick.should_receive(:say_status).with("wtf/zomg", "git://github.com/technicalpickles/zomg.git", :cyan)
132
+
133
+ homesick.list
134
+ end
135
+ end
136
+
137
+ describe "pull" do
138
+
139
+ xit "needs testing"
140
+
141
+ describe "--all" do
142
+ xit "needs testing"
143
+ end
144
+
145
+ end
146
+
147
+ describe "commit" do
148
+
149
+ xit "needs testing"
150
+
151
+ end
152
+
153
+ describe "push" do
154
+
155
+ xit "needs testing"
156
+
157
+ end
158
+
159
+ describe "track" do
160
+ it "should move the tracked file into the castle" do
161
+ castle = given_castle('castle_repo')
162
+
163
+ some_rc_file = home.file '.some_rc_file'
164
+
165
+ homesick.track(some_rc_file.to_s, 'castle_repo')
166
+
167
+ tracked_file = castle.join(".some_rc_file")
168
+ tracked_file.should exist
169
+
170
+ some_rc_file.readlink.should == tracked_file
171
+ end
172
+ end
173
+ end
data/spec/spec.opts ADDED
@@ -0,0 +1 @@
1
+ --color
@@ -0,0 +1,28 @@
1
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
2
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
3
+ require 'homesick'
4
+ require 'rspec'
5
+ require 'rspec/autorun'
6
+ require 'construct'
7
+
8
+ RSpec.configure do |config|
9
+ config.include Construct::Helpers
10
+
11
+ config.before { ENV['HOME'] = home.to_s }
12
+
13
+ config.before { silence! }
14
+
15
+ def silence!
16
+ homesick.stub(:say_status)
17
+ end
18
+
19
+ def given_castle(name, path=name)
20
+ castles.directory(path) do |castle|
21
+ Dir.chdir(castle) do
22
+ system "git init >/dev/null 2>&1"
23
+ system "git remote add origin git://github.com/technicalpickles/#{name}.git >/dev/null 2>&1"
24
+ return castle.directory("home")
25
+ end
26
+ end
27
+ end
28
+ end
metadata ADDED
@@ -0,0 +1,185 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: yahomesick
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Yusuke Murata
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-01-10 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: thor
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: 0.14.0
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: 0.14.0
30
+ - !ruby/object:Gem::Dependency
31
+ name: rake
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ~>
36
+ - !ruby/object:Gem::Version
37
+ version: 0.8.7
38
+ type: :development
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ~>
44
+ - !ruby/object:Gem::Version
45
+ version: 0.8.7
46
+ - !ruby/object:Gem::Dependency
47
+ name: rspec
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ~>
52
+ - !ruby/object:Gem::Version
53
+ version: '2.10'
54
+ type: :development
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ~>
60
+ - !ruby/object:Gem::Version
61
+ version: '2.10'
62
+ - !ruby/object:Gem::Dependency
63
+ name: jeweler
64
+ requirement: !ruby/object:Gem::Requirement
65
+ none: false
66
+ requirements:
67
+ - - ! '>='
68
+ - !ruby/object:Gem::Version
69
+ version: 1.6.2
70
+ type: :development
71
+ prerelease: false
72
+ version_requirements: !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ! '>='
76
+ - !ruby/object:Gem::Version
77
+ version: 1.6.2
78
+ - !ruby/object:Gem::Dependency
79
+ name: rcov
80
+ requirement: !ruby/object:Gem::Requirement
81
+ none: false
82
+ requirements:
83
+ - - ! '>='
84
+ - !ruby/object:Gem::Version
85
+ version: '0'
86
+ type: :development
87
+ prerelease: false
88
+ version_requirements: !ruby/object:Gem::Requirement
89
+ none: false
90
+ requirements:
91
+ - - ! '>='
92
+ - !ruby/object:Gem::Version
93
+ version: '0'
94
+ - !ruby/object:Gem::Dependency
95
+ name: simplecov
96
+ requirement: !ruby/object:Gem::Requirement
97
+ none: false
98
+ requirements:
99
+ - - ! '>='
100
+ - !ruby/object:Gem::Version
101
+ version: '0'
102
+ type: :development
103
+ prerelease: false
104
+ version_requirements: !ruby/object:Gem::Requirement
105
+ none: false
106
+ requirements:
107
+ - - ! '>='
108
+ - !ruby/object:Gem::Version
109
+ version: '0'
110
+ - !ruby/object:Gem::Dependency
111
+ name: test-construct
112
+ requirement: !ruby/object:Gem::Requirement
113
+ none: false
114
+ requirements:
115
+ - - ! '>='
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ none: false
122
+ requirements:
123
+ - - ! '>='
124
+ - !ruby/object:Gem::Version
125
+ version: '0'
126
+ description: ! "\n A man's home (directory) is his castle, so don't leave home
127
+ with out it.\n\n YAHomesick is yet another homesick.\n Homesick is sorta like
128
+ rip, but for dotfiles. It uses git to clone a repository containing dotfiles, and
129
+ saves them in ~/.homesick. It then allows you to symlink all the dotfiles into place
130
+ with a single command. \n\n "
131
+ email: info@muratayusuke.com
132
+ executables:
133
+ - homesick
134
+ extensions: []
135
+ extra_rdoc_files:
136
+ - ChangeLog.markdown
137
+ - LICENSE
138
+ - README.markdown
139
+ files:
140
+ - .document
141
+ - .rspec
142
+ - ChangeLog.markdown
143
+ - Gemfile
144
+ - Gemfile.lock
145
+ - LICENSE
146
+ - README.markdown
147
+ - Rakefile
148
+ - bin/homesick
149
+ - gems/homesick.gem
150
+ - homesick.gemspec
151
+ - lib/homesick.rb
152
+ - lib/homesick/actions.rb
153
+ - lib/homesick/shell.rb
154
+ - spec/homesick_spec.rb
155
+ - spec/spec.opts
156
+ - spec/spec_helper.rb
157
+ homepage: http://github.com/muratayusuke/yahomesick
158
+ licenses:
159
+ - MIT
160
+ post_install_message:
161
+ rdoc_options: []
162
+ require_paths:
163
+ - lib
164
+ required_ruby_version: !ruby/object:Gem::Requirement
165
+ none: false
166
+ requirements:
167
+ - - ! '>='
168
+ - !ruby/object:Gem::Version
169
+ version: '0'
170
+ segments:
171
+ - 0
172
+ hash: 526183215
173
+ required_rubygems_version: !ruby/object:Gem::Requirement
174
+ none: false
175
+ requirements:
176
+ - - ! '>='
177
+ - !ruby/object:Gem::Version
178
+ version: '0'
179
+ requirements: []
180
+ rubyforge_project:
181
+ rubygems_version: 1.8.24
182
+ signing_key:
183
+ specification_version: 3
184
+ summary: A man's home is his castle. Never leave your dotfiles behind.
185
+ test_files: []