94 Commits

Author SHA1 Message Date
muratayusuke
10a9c0f482 Regenerate gemspec for version 0.9.2 2013-06-27 17:19:32 +00:00
muratayusuke
498ffa27f9 remove Gemfile.lock from repository 2013-06-27 17:11:56 +00:00
muratayusuke
ce8b46f300 bump up version 2013-06-27 17:08:33 +00:00
Yusuke Murata
995eff975f Merge pull request #45 from austinylin/master
Fix the path for .homesick_subdir in README.md
2013-06-27 09:47:49 -07:00
Yusuke Murata
2ab35e91e2 Merge pull request #44 from DavidMikeSimon/master
Added commands: show_path, status, diff
2013-06-27 09:47:18 -07:00
Austin Lin
4867ac2c7c Update readme with correct file path for .homesick_subdir per technicalpickles/homesick@360e8185f7 2013-06-27 12:06:54 -04:00
David Simon
a68149a87b Whoops, fixed typo 2013-06-26 14:34:43 -04:00
David Simon
8be3cdb6a0 Using DEFAULT_CASTLE_NAME in show_path, diff, status 2013-06-26 14:29:45 -04:00
David Simon
99760c27af Added three commands: show_path, status, diff 2013-06-25 16:11:08 -04:00
Yusuke Murata
4aa76ce444 Merge pull request #42 from akahigeg/default-castle-name
set default castle name: 'dotfiles' for some commands
2013-06-23 09:56:55 -07:00
akahige
82ae128429 default castle name to constant 2013-06-24 00:44:17 +09:00
akahige
dbf333c971 set default castle name: 'dotfiles' for some commands 2013-06-21 14:02:50 +09:00
Yusuke Murata
ca5dc3a4cc Merge pull request #41 from muratayusuke/feature/rubocop
Feature/rubocop
2013-06-20 16:44:12 -07:00
muratayusuke
a267a9c0b8 remove duplicate spec 2013-06-19 17:42:16 +00:00
muratayusuke
21cbb2c697 follow Ruby Style Guide for some points 2013-06-19 17:21:24 +00:00
muratayusuke
00f49be42c don't fail test even if rubocop detects some offence 2013-06-19 16:41:12 +00:00
muratayusuke
37b55bf934 use single-quate if don't need double-quate 2013-06-19 16:23:00 +00:00
muratayusuke
f2aca02b82 don't install rubocop under ruby 1.9.2 2013-06-19 15:58:45 +00:00
muratayusuke
dd101259f0 don't run rubocode on ruby 1.8.7 2013-06-19 15:41:53 +00:00
muratayusuke
b1f2742422 fix coding style 2013-06-19 15:30:18 +00:00
muratayusuke
114b44d4b6 use rubocop 2013-06-19 15:01:36 +00:00
muratayusuke
e07f3f0658 Regenerate gemspec for version 0.9.1 2013-06-17 12:36:14 +00:00
muratayusuke
b21aef09be bump up version 2013-06-17 12:35:39 +00:00
Yusuke Murata
d964e65a7e Merge pull request #40 from fnichol/fix-clone-destination
Remove .git suffix on destination directory if URL ends with it.
2013-06-17 04:47:20 -07:00
Fletcher Nichol
024856e538 Remove .git suffix on destination directory if URL ends with it.
For example, the following:

    homesick clone git://github.com/technicalpickles/pickled-vim.git

should produce a castle directory of:

    $HOME/.homesick/repos/pickled-vim
2013-06-16 10:47:53 -06:00
muratayusuke
e530df7239 fix #35 2013-06-09 23:10:21 +00:00
muratayusuke
e817c816c9 Regenerate gemspec for version 0.9.0 2013-06-06 12:59:00 +00:00
muratayusuke
14f0f8c121 bump up version and update changelog 2013-06-06 12:58:36 +00:00
Yusuke Murata
4c97948e04 Merge pull request #39 from technicalpickles/feature/merge_directory
Merge directories
2013-06-06 05:47:43 -07:00
muratayusuke
360e8185f7 move castle/home/.homesick_subdir to castle/.homesick_subdir 2013-06-06 12:39:41 +00:00
Yusuke Murata
da0958d455 fix typo 2013-06-06 21:19:21 +09:00
Yusuke Murata
70f5d24e0a fix style of README 2013-06-05 03:18:40 +09:00
Yusuke Murata
6b281ef001 fix style of README 2013-06-05 03:15:44 +09:00
muratayusuke
3ddd3207b3 add .homesick_subdir explanation to README 2013-06-04 18:14:20 +00:00
muratayusuke
8e58a3f5e2 deal with edge case: the parent and descendant are both listed in the manifest 2013-06-04 17:36:47 +00:00
muratayusuke
a95c4b2446 refactor symlink 2013-06-03 18:17:38 +00:00
muratayusuke
97fe1686f5 refactor given_castle 2013-05-30 17:38:06 +00:00
muratayusuke
76fcf5d0b7 add ruby-2.0.0 to travis 2013-05-30 14:33:45 +00:00
muratayusuke
bf1fc58e10 fix spec for ruby-1.8.7 2013-05-30 14:33:08 +00:00
muratayusuke
3559d825ca replace .manifest to .homesick_subdir 2013-05-27 18:08:09 +00:00
muratayusuke
2d54086d89 Merge remote-tracking branch 'edubkendo/nested_dirs' into feature/merge_directory 2013-05-27 16:13:31 +00:00
muratayusuke
c31c67a3eb support nested dir in .homesick_subdir 2013-05-26 17:12:28 +00:00
Eric West
e924cbefda refactor, cleanup and tweak 2013-05-24 21:57:12 -05:00
Eric West
6867ef78dc Handling edge cases
Covers only edge cases related to tracking, not yet
handling linking or updating. Getting a bit hairy,
must be refactored.
2013-05-24 16:24:42 -05:00
muratayusuke
a76d09d3f6 symlink subdirs with .homesick_subdir 2013-05-24 17:40:35 +00:00
Eric West
b93eea0e24 Track makes entries in .manifest
When a user tracks a file or directory that is in
a nested folder, Homesick creates a .manifest in the
user's castle (if there isn't one already) and adds
an entry listing the file or directory's parent
directory (if it isn't already listed).
2013-05-24 07:52:54 -05:00
Eric West
7332aa4acd Specs for track 2013-05-20 21:06:31 -05:00
Eric West
49e4d2844b Track now properly traverses folder structure 2013-05-20 19:11:48 -05:00
muratayusuke
236373b7d7 Regenerate gemspec for version 0.8.1 2013-05-19 13:42:49 +00:00
muratayusuke
21a9e4312d update changelog 2013-05-19 13:42:32 +00:00
muratayusuke
628d9bc0c1 update rake version
"rake spec" showed following warning
/home/muratayusuke/.rvm/gems/ruby-1.9.3-p392/gems/rake-0.8.7/lib/rake/alt_system.rb:32: Use RbConfig instead of obsolete and deprecated Config.
(in /mnt/projects/homesick)
/home/muratayusuke/.rvm/rubies/ruby-1.9.3-p392/bin/ruby -S rspec spec/homesick_spec.rb
so update rake version to fix it.
2013-05-19 13:37:54 +00:00
Yusuke Murata
caf5ca04f5 Merge pull request #37 from edubkendo/glob_fix
Fixes glob to work with 2.0.0
2013-05-18 01:15:56 -07:00
Eric West
7cbbf2bdd7 Fixes glob to work with 2.0.0
homesick list fails on ruby 2.0.0-rc2, I think because they fixed this
bug: https://bugs.ruby-lang.org/issues/6977, changing the way recursive
globs work. Test case:

```ruby
require "homesick"
require "pathname"

repos = Homesick.new.send :repos_dir

Dir.glob("#{repos}/**/*/.git") # => []

Dir.glob("#{repos}/**/*/.git", File::FNM_DOTMATCH) # => ["/home/eric/.homesick/repos/dotfiles/.git"]

```
This change, however, then broke 1.9.3, but removing the extra "/*"
works on both 1.9 and 2.0.
2013-05-17 02:37:44 -05:00
muratayusuke
9d6e77fd5a add build status to README 2013-04-06 03:23:40 +09:00
muratayusuke
e7d251f8a1 prepare for release 0.8.0 2013-04-06 03:07:11 +09:00
muratayusuke
af950d042a fix merge miss 2013-03-29 01:58:35 +09:00
muratayusuke
23ae908e7d Merge remote-tracking branch 'jbuckner/track-git_add' into local
Conflicts:
	lib/homesick/actions.rb
2013-03-29 01:57:07 +09:00
Yusuke Murata
38ffaca8cc Merge pull request #11 from diasjorge/master
Fixing issues with uris that contain  and submodules
2013-03-28 08:48:18 -07:00
Yusuke Murata
b0bde0eb44 Merge pull request #26 from jbuckner/castle_push
Castle Commit & Push
2013-03-28 08:23:45 -07:00
Yusuke Murata
763cf8aa0a Merge pull request #28 from muratayusuke/enable_recursive_submodule
yeah merged :)
2013-03-28 08:01:24 -07:00
Josh Nichols
9f0d3e0f3c Merge pull request #30 from wjbuys/master
Build with Travis CI
2013-03-26 16:51:46 -07:00
Jacob Buys
937bb65a14 Build with Travis CI 2013-03-18 23:03:44 +02:00
Josh Nichols
376fd88fc9 Fix git_clone to work with github URLs like https://github.com/technicalpickles/dotpickles 2012-12-09 15:33:15 -05:00
muratayusuke
fca23274bf enable recursive submodule 2012-12-06 20:10:18 +09:00
Jason Buckner
27d038512c perform a git add when doing a homesick track 2012-11-24 23:56:12 -08:00
Jason Buckner
d8291edae0 splits up castle commit from castle push for more fine-grained control 2012-11-24 23:18:48 -08:00
Jason Buckner
e6c0ac91cd update documentation for naming consistency 2012-11-24 22:56:17 -08:00
Jason Buckner
74713f8b7c fix homesick pull documentation 2012-11-24 22:36:45 -08:00
Jason Buckner
38a43ba7ff add homesick push to readme, a placeholder test, and removed the all option from git push 2012-11-24 21:24:41 -08:00
Jason Buckner
ca832a38e2 start adding git push functionality 2012-11-24 21:01:37 -08:00
Jacob Buys
d084128297 Add support for Ruby 1.9.
Some dependencies needed updating, and String#start_with? behaves
slightly differently.
2012-05-30 22:54:18 +02:00
Jacob Buys
a141f9cbbd Fix test that fails on 1.9 due to behaviour of String#start_with?
On ruby 1.9, the argument of String#start_with? does not automatically
get coerced into a string. In Homesick#clone, we use start_with? with a
Pathname instance, which now always returns false.
2012-05-30 22:53:00 +02:00
Jacob Buys
e415da13e4 Fix dependencies that break with ruby 1.9.3
Ruby 1.9.3 requires a recent version of RSpec 2, and simplecov
supercedes rcov on ruby 1.9+.
2012-05-30 22:51:40 +02:00
Jacob Buys
10d65abf47 Merge remote-tracking branch 'technicalpickles/master' 2012-05-30 22:39:51 +02:00
Josh Nichols
a03e580b36 Regenerate gemspec for version 0.7.0 2012-05-28 15:02:10 -04:00
Josh Nichols
79e982d198 Update jeweler to a non-prelease 2012-05-28 15:01:25 -04:00
Josh Nichols
453bd8fc04 Add link to homeshick. 2012-05-28 15:58:08 -03:00
Jacob Buys
9ced2921d9 Fix overriding existing symlinks that point to directories. 2011-08-23 22:04:00 +02:00
Jacob Buys
fa99a89bbf Use RSpec's let feature instead of instance variables. 2011-08-21 22:36:50 +02:00
Jacob Buys
f1a02b8afa Added support for linking non-dotfiles. 2011-08-21 22:22:23 +02:00
Jacob Buys
6e4e60fc64 Silence thor output during tests. 2011-08-21 22:19:06 +02:00
Jacob Buys
4f5e77d189 Refactored tests to use given_castle and fewer mocks. 2011-08-21 22:18:55 +02:00
Jacob Buys
4fa7ce416b Made specs for list pass, refactored track to use given_castle. 2011-08-21 22:04:57 +02:00
Jacob Buys
4d9f75b7b0 Extract common setup into spec_helper, add given_castle helper. 2011-08-21 21:54:25 +02:00
Jorge Dias
bfd83f2e87 Merge branch 'master' of git://github.com/technicalpickles/homesick 2011-05-31 14:09:35 +02:00
Josh Nichols
f0c947a50b Version bump to 0.7.0, and catch up on ChangeLog. 2011-05-30 21:22:21 -04:00
Josh Nichols
e19617be2f Don't try to symlink a castle to itself. Fixes #14 2011-05-30 21:04:41 -04:00
Josh Nichols
54697866f5 Add ruby-debug as a development dependency. 2011-05-30 21:03:34 -04:00
Josh Nichols
8c1f0bd05c Add placeholder specs to fill out eventually. 2011-05-30 20:14:04 -04:00
Ilkka Laukkanen
c3999f92b1 Print each castle's name when pulling all castles 2011-04-27 21:51:08 +03:00
Ilkka Laukkanen
c3f6bef152 Don't treat git repos in other repos as castles
Further abstracted locating castles into Homesick.all_castles which globs as
before, but after that rejects any paths that lie in other paths. This way
castles that have submodules don't cause extra output in e.g. list.
2011-04-27 21:39:02 +03:00
Ilkka Laukkanen
c870bfe442 Add --all option to pull to update all castles
Abstracted the logic for doing some operation for all castles into
Homesick.inside_each_castle() which takes a block argument. Homesick.list() is
also reimplemented to use this new method, because that's where the logic was
stolen from. The actual updating is also moved to the private method
update_castle() to make pull() shorter.
2011-04-27 21:01:29 +03:00
Sam Whitlock
06846afa77 Fixed minor spelling error in README 2011-03-02 08:22:21 -05:00
Jorge
38b40c0f50 Making git repos uri non greedy so it works with uris with / 2010-10-30 21:31:59 +02:00
13 changed files with 829 additions and 235 deletions

6
.gitignore vendored
View File

@@ -39,3 +39,9 @@ pkg
# #
# For vim: # For vim:
*.swp *.swp
#
# For IDEA:
.idea/
*.iml
Gemfile.lock

5
.travis.yml Normal file
View File

@@ -0,0 +1,5 @@
language: ruby
rvm:
- 2.0.0
- 1.9.3
- 1.8.7

View File

@@ -1,3 +1,42 @@
# 0.9.2
* Set "dotfiles" as default castle name
* Introduce new commands
* `homesick show_path`
* `homesick status`
* `homesick diff`
# 0.9.1
* Fixed small bugs: #35, #40
# 0.9.0
* Introduce .homesick_subdir #39
# 0.8.1
*Fixed `homesick list` bug on ruby 2.0 #37
# 0.8.0
* Introduce commit & push command
* commit changes in castle and push to remote
* Enable recursive submodule update
* Git add when track
# 0.7.0
* Fixed double-cloning #14
* New option for pull command: --all
* pulls each castle, instead of just one
# 0.6.1
* Add a license
# 0.6.0
* Introduce .homesickrc
* Castles can now have a .homesickrc inside them
* On clone, this is eval'd inside the destination directory
* Introduce track command
* Allows easily moving an existing file into a castle, and symlinking it back
# 0.5.0 # 0.5.0
* Fixed listing of castles cloned using `homesick clone <github-user>/<github-repo>` (issue 3) * Fixed listing of castles cloned using `homesick clone <github-user>/<github-repo>` (issue 3)

15
Gemfile
View File

@@ -1,4 +1,4 @@
source :gemcutter source 'https://rubygems.org'
# Add dependencies required to use your gem here. # Add dependencies required to use your gem here.
gem "thor", ">= 0.14.0" gem "thor", ">= 0.14.0"
@@ -6,10 +6,13 @@ gem "thor", ">= 0.14.0"
# Add dependencies to develop your gem here. # Add dependencies to develop your gem here.
# Include everything needed to run rake, tests, features, etc. # Include everything needed to run rake, tests, features, etc.
group :development do group :development do
gem "rake" gem "rake", ">= 0.8.7"
gem "rspec", "~> 2.1.0" gem "rspec", "~> 2.10"
gem "bundler", "~> 1.0.0" gem "jeweler", ">= 1.6.2"
gem "jeweler", ">= 1.5.0.pre6" gem "rcov", :platforms => :mri_18
gem "rcov", ">= 0" gem "simplecov", :platforms => :mri_19
gem "test-construct" gem "test-construct"
if RUBY_VERSION >= '1.9.2'
gem "rubocop"
end
end end

View File

@@ -1,33 +0,0 @@
GEM
remote: http://rubygems.org/
specs:
diff-lcs (1.1.2)
git (1.2.5)
jeweler (1.5.0.pre6)
bundler (~> 1.0.0)
git (>= 1.2.5)
rake
rake (0.8.7)
rcov (0.9.8)
rspec (2.1.0)
rspec-core (~> 2.1.0)
rspec-expectations (~> 2.1.0)
rspec-mocks (~> 2.1.0)
rspec-core (2.1.0)
rspec-expectations (2.1.0)
diff-lcs (~> 1.1.2)
rspec-mocks (2.1.0)
test-construct (1.2.0)
thor (0.14.0)
PLATFORMS
ruby
DEPENDENCIES
bundler (~> 1.0.0)
jeweler (>= 1.5.0.pre6)
rake
rcov
rspec (~> 2.1.0)
test-construct
thor (>= 0.14.0)

View File

@@ -1,5 +1,7 @@
# homesick # homesick
[![Build Status](https://travis-ci.org/technicalpickles/homesick.png?branch=master)](https://travis-ci.org/technicalpickles/homesick)
A man's home (directory) is his castle, so don't leave home with out it. A man's home (directory) is his castle, so don't leave home with out it.
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. 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.
@@ -25,7 +27,7 @@ With the castle cloned, you can now link its contents into your home dir:
homesick symlink pickled-vim homesick symlink pickled-vim
If uou use the shorthand syntax for GitHub repositories in your clone, please note you will instead need to run: If you use the shorthand syntax for GitHub repositories in your clone, please note you will instead need to run:
homesick symlink technicalpickles/pickled-vim homesick symlink technicalpickles/pickled-vim
@@ -33,10 +35,100 @@ If you're not sure what castles you have around, you can easily list them:
homesick list homesick list
To pull your castle (or all castles):
homesick pull --all|CASTLE
To commit your castle's changes:
homesick commit CASTLE
To push your castle:
homesick push CASTLE
Not sure what else homesick has up its sleeve? There's always the built in help: Not sure what else homesick has up its sleeve? There's always the built in help:
homesick help homesick help
## .homesick_subdir
`homesick symlink` basically makes symlink to only first depth in `castle/home`. If you want to link nested files/directories, please use .homesick_subdir.
For example, when you have castle like this:
castle/home
`-- .config
`-- fooapp
|-- config1
|-- config2
`-- config3
and have home like this:
$ tree -a
~
|-- .config
| `-- barapp
| |-- config1
| |-- config2
| `-- config3
`-- .emacs.d
|-- elisp
`-- inits
You may want to symlink only to `castle/home/.config/fooapp` instead of `castle/home/.config` because you already have `~/.config/barapp`. In this case, you can use .homesick_subdir. Please write "directories you want to look up sub directories (instead of just first depth)" in this file.
castle/.homesick_subdir
.config
and run `homesick symlink CASTLE`. The result is:
~
|-- .config
| |-- barapp
| | |-- config1
| | |-- config2
| | `-- config3
| `-- fooapp -> castle/home/.config/fooapp
`-- .emacs.d
|-- elisp
`-- inits
Or `homesick track NESTED_FILE CASTLE` adds a line automatically. For example:
homesick track .emacs.d/elisp castle
castle/.homesick_subdir
.config
.emacs.d
home directory
~
|-- .config
| |-- barapp
| | |-- config1
| | |-- config2
| | `-- config3
| `-- fooapp -> castle/home/.config/fooapp
`-- .emacs.d
|-- elisp -> castle/home/.emacs.d/elisp
`-- inits
and castle
castle/home
|-- .config
| `-- fooapp
| |-- config1
| |-- config2
| `-- config3
`-- .emacs.d
`-- elisp
## Note on Patches/Pull Requests ## Note on Patches/Pull Requests
* Fork the project. * Fork the project.
@@ -45,6 +137,10 @@ Not sure what else homesick has up its sleeve? There's always the built in help:
* 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) * 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)
* Send me a pull request. Bonus points for topic branches. * Send me a pull request. Bonus points for topic branches.
## Need homesick without the ruby dependency?
Check out [homeshick](https://github.com/andsens/homeshick).
## Copyright ## Copyright
Copyright (c) 2010 Joshua Nichols. See LICENSE for details. Copyright (c) 2010 Joshua Nichols. See LICENSE for details.

View File

@@ -19,10 +19,10 @@ Jeweler::Tasks.new do |gem|
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. 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.
} }
gem.email = "josh@technicalpickles.com" gem.email = ["josh@technicalpickles.com", "info@muratayusuke.com"]
gem.homepage = "http://github.com/technicalpickles/homesick" gem.homepage = "http://github.com/technicalpickles/homesick"
gem.authors = ["Joshua Nichols"] gem.authors = ["Joshua Nichols", "Yusuke Murata"]
gem.version = "0.6.1" gem.version = "0.9.2"
gem.license = "MIT" gem.license = "MIT"
# Have dependencies? Add them to Gemfile # Have dependencies? Add them to Gemfile
@@ -41,10 +41,20 @@ RSpec::Core::RakeTask.new(:rcov) do |spec|
spec.rcov = true spec.rcov = true
end end
task :rubocop do
if RUBY_VERSION >= '1.9.2'
system('rubocop')
end
end
task :default => :spec task :test do
Rake::Task['spec'].execute
Rake::Task['rubocop'].execute
end
require 'rake/rdoctask' task :default => :test
require 'rdoc/task'
Rake::RDocTask.new do |rdoc| Rake::RDocTask.new do |rdoc|
version = File.exist?('VERSION') ? File.read('VERSION') : "" version = File.exist?('VERSION') ? File.read('VERSION') : ""

View File

@@ -2,7 +2,7 @@
require 'pathname' require 'pathname'
lib = Pathname.new(__FILE__).dirname.join('..', 'lib').expand_path lib = Pathname.new(__FILE__).dirname.join('..', 'lib').expand_path
$LOAD_PATH.unshift lib.to_s $LOAD_PATH.unshift lib.to_s
require 'homesick' require 'homesick'

View File

@@ -1,24 +1,23 @@
# Generated by jeweler # Generated by jeweler
# DO NOT EDIT THIS FILE DIRECTLY # DO NOT EDIT THIS FILE DIRECTLY
# Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command # Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
# -*- encoding: utf-8 -*- # -*- encoding: utf-8 -*-
Gem::Specification.new do |s| Gem::Specification.new do |s|
s.name = %q{homesick} s.name = %q{homesick}
s.version = "0.6.1" s.version = "0.9.2"
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version= s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
s.authors = ["Joshua Nichols"] s.authors = [%q{Joshua Nichols}, %q{Yusuke Murata}]
s.date = %q{2010-11-13} s.date = %q{2013-06-27}
s.default_executable = %q{homesick}
s.description = %q{ s.description = %q{
A man's home (directory) is his castle, so don't leave home with out it. A man's home (directory) is his castle, so don't leave home with out it.
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. 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.
} }
s.email = %q{josh@technicalpickles.com} s.email = [%q{josh@technicalpickles.com}, %q{info@muratayusuke.com}]
s.executables = ["homesick"] s.executables = [%q{homesick}]
s.extra_rdoc_files = [ s.extra_rdoc_files = [
"ChangeLog.markdown", "ChangeLog.markdown",
"LICENSE", "LICENSE",
@@ -27,9 +26,9 @@ Gem::Specification.new do |s|
s.files = [ s.files = [
".document", ".document",
".rspec", ".rspec",
".travis.yml",
"ChangeLog.markdown", "ChangeLog.markdown",
"Gemfile", "Gemfile",
"Gemfile.lock",
"LICENSE", "LICENSE",
"README.markdown", "README.markdown",
"Rakefile", "Rakefile",
@@ -43,43 +42,38 @@ Gem::Specification.new do |s|
"spec/spec_helper.rb" "spec/spec_helper.rb"
] ]
s.homepage = %q{http://github.com/technicalpickles/homesick} s.homepage = %q{http://github.com/technicalpickles/homesick}
s.licenses = ["MIT"] s.licenses = [%q{MIT}]
s.require_paths = ["lib"] s.require_paths = [%q{lib}]
s.rubygems_version = %q{1.3.7} s.rubygems_version = %q{1.8.5}
s.summary = %q{A man's home is his castle. Never leave your dotfiles behind.} s.summary = %q{A man's home is his castle. Never leave your dotfiles behind.}
s.test_files = [
"spec/homesick_spec.rb",
"spec/spec_helper.rb"
]
if s.respond_to? :specification_version then if s.respond_to? :specification_version then
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
s.specification_version = 3 s.specification_version = 3
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
s.add_runtime_dependency(%q<thor>, [">= 0.14.0"]) s.add_runtime_dependency(%q<thor>, [">= 0.14.0"])
s.add_development_dependency(%q<rake>, [">= 0"]) s.add_development_dependency(%q<rake>, [">= 0.8.7"])
s.add_development_dependency(%q<rspec>, ["~> 2.1.0"]) s.add_development_dependency(%q<rspec>, ["~> 2.10"])
s.add_development_dependency(%q<bundler>, ["~> 1.0.0"]) s.add_development_dependency(%q<jeweler>, [">= 1.6.2"])
s.add_development_dependency(%q<jeweler>, [">= 1.5.0.pre6"])
s.add_development_dependency(%q<rcov>, [">= 0"]) s.add_development_dependency(%q<rcov>, [">= 0"])
s.add_development_dependency(%q<simplecov>, [">= 0"])
s.add_development_dependency(%q<test-construct>, [">= 0"]) s.add_development_dependency(%q<test-construct>, [">= 0"])
else else
s.add_dependency(%q<thor>, [">= 0.14.0"]) s.add_dependency(%q<thor>, [">= 0.14.0"])
s.add_dependency(%q<rake>, [">= 0"]) s.add_dependency(%q<rake>, [">= 0.8.7"])
s.add_dependency(%q<rspec>, ["~> 2.1.0"]) s.add_dependency(%q<rspec>, ["~> 2.10"])
s.add_dependency(%q<bundler>, ["~> 1.0.0"]) s.add_dependency(%q<jeweler>, [">= 1.6.2"])
s.add_dependency(%q<jeweler>, [">= 1.5.0.pre6"])
s.add_dependency(%q<rcov>, [">= 0"]) s.add_dependency(%q<rcov>, [">= 0"])
s.add_dependency(%q<simplecov>, [">= 0"])
s.add_dependency(%q<test-construct>, [">= 0"]) s.add_dependency(%q<test-construct>, [">= 0"])
end end
else else
s.add_dependency(%q<thor>, [">= 0.14.0"]) s.add_dependency(%q<thor>, [">= 0.14.0"])
s.add_dependency(%q<rake>, [">= 0"]) s.add_dependency(%q<rake>, [">= 0.8.7"])
s.add_dependency(%q<rspec>, ["~> 2.1.0"]) s.add_dependency(%q<rspec>, ["~> 2.10"])
s.add_dependency(%q<bundler>, ["~> 1.0.0"]) s.add_dependency(%q<jeweler>, [">= 1.6.2"])
s.add_dependency(%q<jeweler>, [">= 1.5.0.pre6"])
s.add_dependency(%q<rcov>, [">= 0"]) s.add_dependency(%q<rcov>, [">= 0"])
s.add_dependency(%q<simplecov>, [">= 0"])
s.add_dependency(%q<test-construct>, [">= 0"]) s.add_dependency(%q<test-construct>, [">= 0"])
end end
end end

View File

@@ -10,24 +10,32 @@ class Homesick < Thor
add_runtime_options! add_runtime_options!
GITHUB_NAME_REPO_PATTERN = /\A([A-Za-z_-]+\/[A-Za-z_-]+)\Z/ GITHUB_NAME_REPO_PATTERN = /\A([A-Za-z_-]+\/[A-Za-z_-]+)\Z/
SUBDIR_FILENAME = '.homesick_subdir'
def initialize(args=[], options={}, config={}) DEFAULT_CASTLE_NAME = 'dotfiles'
def initialize(args = [], options = {}, config = {})
super super
self.shell = Homesick::Shell.new self.shell = Homesick::Shell.new
end end
desc "clone URI", "Clone +uri+ as a castle for homesick" desc 'clone URI', 'Clone +uri+ as a castle for homesick'
def clone(uri) def clone(uri)
inside repos_dir do inside repos_dir do
destination = nil destination = nil
if File.exist?(uri) if File.exist?(uri)
destination = Pathname.new(uri).basename uri = Pathname.new(uri).expand_path
if uri.to_s.start_with?(repos_dir.to_s)
raise "Castle already cloned to #{uri}"
end
destination = uri.basename
ln_s uri, destination ln_s uri, destination
elsif uri =~ GITHUB_NAME_REPO_PATTERN elsif uri =~ GITHUB_NAME_REPO_PATTERN
destination = Pathname.new($1) destination = Pathname.new($1)
git_clone "git://github.com/#{$1}.git", :destination => destination git_clone "git://github.com/#{$1}.git", :destination => destination
elsif uri =~ /\/([^\/]*)(\.git)?\Z/ elsif uri =~ /%r([^%r]*?)(\.git)?\Z/
destination = Pathname.new($1) destination = Pathname.new($1)
git_clone uri git_clone uri
elsif uri =~ /[^:]+:([^:]+)(\.git)?\Z/ elsif uri =~ /[^:]+:([^:]+)(\.git)?\Z/
@@ -48,79 +56,139 @@ class Homesick < Thor
if homesickrc.exist? if homesickrc.exist?
proceed = shell.yes?("#{uri} has a .homesickrc. Proceed with evaling it? (This could be destructive)") proceed = shell.yes?("#{uri} has a .homesickrc. Proceed with evaling it? (This could be destructive)")
if proceed if proceed
shell.say_status "eval", homesickrc shell.say_status 'eval', homesickrc
inside destination do inside destination do
eval homesickrc.read, binding, homesickrc.expand_path eval homesickrc.read, binding, homesickrc.expand_path
end end
else else
shell.say_status "eval skip", "not evaling #{homesickrc}, #{destination} may need manual configuration", :blue shell.say_status 'eval skip', "not evaling #{homesickrc}, #{destination} may need manual configuration", :blue
end end
end end
end end
end end
desc "pull NAME", "Update the specified castle" desc 'pull CASTLE', 'Update the specified castle'
def pull(name) method_option :all, :type => :boolean, :default => false, :required => false, :desc => 'Update all cloned castles'
check_castle_existance(name, "pull") def pull(name = DEFAULT_CASTLE_NAME)
if options[:all]
inside repos_dir.join(name) do inside_each_castle do |castle|
git_pull shell.say castle.to_s.gsub(repos_dir.to_s + '/', '') + ':'
git_submodule_init update_castle castle
git_submodule_update end
else
update_castle name
end end
end end
desc "symlink NAME", "Symlinks all dotfiles from the specified castle" desc 'commit CASTLE', "Commit the specified castle's changes"
def symlink(name) def commit(name = DEFAULT_CASTLE_NAME)
check_castle_existance(name, "symlink") commit_castle name
end
desc 'push CASTLE', 'Push the specified castle'
def push(name = DEFAULT_CASTLE_NAME)
push_castle name
end
desc 'symlink CASTLE', 'Symlinks all dotfiles from the specified castle'
method_option :force, :default => false, :desc => 'Overwrite existing conflicting symlinks without prompting.'
def symlink(name = DEFAULT_CASTLE_NAME)
check_castle_existance(name, 'symlink')
inside castle_dir(name) do inside castle_dir(name) do
files = Pathname.glob('.*').reject{|a| [".",".."].include?(a.to_s)} subdirs = subdirs(name)
files.each do |path|
absolute_path = path.expand_path
inside home_dir do # link files
adjusted_path = (home_dir + path).basename symlink_each(name, castle_dir(name), subdirs)
ln_s absolute_path, adjusted_path # link files in subdirs
end subdirs.each do |subdir|
symlink_each(name, subdir, subdirs)
end end
end end
end end
desc "track FILE CASTLE", "add a file to a castle" desc 'track FILE CASTLE', 'add a file to a castle'
def track(file, castle) def track(file, castle = DEFAULT_CASTLE_NAME)
castle = Pathname.new(castle) castle = Pathname.new(castle)
file = Pathname.new(file) file = Pathname.new(file.chomp('/'))
check_castle_existance(castle, 'track') check_castle_existance(castle, 'track')
absolute_path = file.expand_path absolute_path = file.expand_path
castle_path = castle_dir(castle) relative_dir = absolute_path.relative_path_from(home_dir).dirname
mv absolute_path, castle_path castle_path = Pathname.new(castle_dir(castle)).join(relative_dir)
FileUtils.mkdir_p castle_path
# Are we already tracking this or anything inside it?
target = Pathname.new(castle_path.join(file.basename))
if target.exist?
if absolute_path.directory?
move_dir_contents(target, absolute_path)
absolute_path.rmtree
subdir_remove(castle, relative_dir + file.basename)
elsif more_recent? absolute_path, target
target.delete
mv absolute_path, castle_path
else
shell.say_status(:track, "#{target} already exists, and is more recent than #{file}. Run 'homesick SYMLINK CASTLE' to create symlinks.", :blue) unless options[:quiet]
end
else
mv absolute_path, castle_path
end
inside home_dir do inside home_dir do
absolute_path = castle_dir(castle) + file.basename absolute_path = castle_path + file.basename
home_path = home_dir + file home_path = home_dir + relative_dir + file.basename
ln_s absolute_path, home_path ln_s absolute_path, home_path
end end
inside castle_path do
git_add absolute_path
end
# are we tracking something nested? Add the parent dir to the manifest
subdir_add(castle, relative_dir) unless relative_dir.eql?(Pathname.new('.'))
end end
desc "list", "List cloned castles" desc 'list', 'List cloned castles'
def list def list
Pathname.glob("#{repos_dir}/**/*/.git") do |git_dir| inside_each_castle do |castle|
castle = git_dir.dirname say_status castle.relative_path_from(repos_dir).to_s, `git config remote.origin.url`.chomp, :cyan
Dir.chdir castle do # so we can call git config from the right contxt
say_status castle.relative_path_from(repos_dir), `git config remote.origin.url`.chomp, :cyan
end
end end
end end
desc "generate PATH", "generate a homesick-ready git repo at PATH" desc 'status CASTLE', 'Shows the git status of a castle'
def status(castle = DEFAULT_CASTLE_NAME)
check_castle_existance(castle, 'status')
inside repos_dir.join(castle) do
git_status
end
end
desc 'diff CASTLE', 'Shows the git diff of uncommitted changes in a castle'
def diff(castle = DEFAULT_CASTLE_NAME)
check_castle_existance(castle, 'diff')
inside repos_dir.join(castle) do
git_diff
end
end
desc 'show_path CASTLE', 'Prints the path of a castle'
def show_path(castle = DEFAULT_CASTLE_NAME)
check_castle_existance(castle, 'show_path')
say repos_dir.join(castle)
end
desc 'generate PATH', 'generate a homesick-ready git repo at PATH'
def generate(castle) def generate(castle)
castle = Pathname.new(castle).expand_path castle = Pathname.new(castle).expand_path
github_user = `git config github.user`.chomp github_user = `git config github.user`.chomp
github_user = nil if github_user == "" github_user = nil if github_user == ''
github_repo = castle.basename github_repo = castle.basename
empty_directory castle empty_directory castle
@@ -131,7 +199,7 @@ class Homesick < Thor
git_remote_add 'origin', url git_remote_add 'origin', url
end end
empty_directory "home" empty_directory 'home'
end end
end end
@@ -158,4 +226,142 @@ class Homesick < Thor
end end
end end
def all_castles
dirs = Pathname.glob("#{repos_dir}/**/.git", File::FNM_DOTMATCH)
# reject paths that lie inside another castle, like git submodules
return dirs.reject do |dir|
dirs.any? do |other|
dir != other && dir.fnmatch(other.parent.join('*').to_s)
end
end
end
def inside_each_castle(&block)
all_castles.each do |git_dir|
castle = git_dir.dirname
Dir.chdir castle do # so we can call git config from the right contxt
yield castle
end
end
end
def update_castle(castle)
check_castle_existance(castle, 'pull')
inside repos_dir.join(castle) do
git_pull
git_submodule_init
git_submodule_update
end
end
def commit_castle(castle)
check_castle_existance(castle, 'commit')
inside repos_dir.join(castle) do
git_commit_all
end
end
def push_castle(castle)
check_castle_existance(castle, 'push')
inside repos_dir.join(castle) do
git_push
end
end
def subdir_file(castle)
repos_dir.join(castle, SUBDIR_FILENAME)
end
def subdirs(castle)
subdir_filepath = subdir_file(castle)
subdirs = []
if subdir_filepath.exist?
subdir_filepath.readlines.each do |subdir|
subdirs.push(subdir.chomp)
end
end
subdirs
end
def subdir_add(castle, path)
subdir_filepath = subdir_file(castle)
File.open(subdir_filepath, 'a+') do |subdir|
subdir.puts path unless subdir.readlines.reduce(false) do |memo, line|
line.eql?("#{path.to_s}\n") || memo
end
end
inside castle_dir(castle) do
git_add subdir_filepath
end
end
def subdir_remove(castle, path)
subdir_filepath = subdir_file(castle)
if subdir_filepath.exist?
lines = IO.readlines(subdir_filepath).delete_if { |line| line == "#{path}\n" }
File.open(subdir_filepath, 'w') { |manfile| manfile.puts lines }
end
inside castle_dir(castle) do
git_add subdir_filepath
end
end
def move_dir_contents(target, dir_path)
child_files = dir_path.children
child_files.each do |child|
target_path = target.join(child.basename)
if target_path.exist?
if more_recent?(child, target_path) && target.file?
target_path.delete
mv child, target
end
next
end
mv child, target
end
end
def more_recent?(first, second)
first_p = Pathname.new(first)
second_p = Pathname.new(second)
first_p.mtime > second_p.mtime && !first_p.symlink?
end
def symlink_each(castle, basedir, subdirs)
absolute_basedir = Pathname.new(basedir).expand_path
inside basedir do
files = Pathname.glob('{.*,*}').reject{ |a| ['.', '..'].include?(a.to_s) }
files.each do |path|
absolute_path = path.expand_path
castle_home = castle_dir(castle)
# make ignore dirs
ignore_dirs = []
subdirs.each do |subdir|
# ignore all parent of each line in subdir file
Pathname.new(subdir).ascend do |p|
ignore_dirs.push(p)
end
end
# ignore dirs written in subdir file
matched = false
ignore_dirs.uniq.each do |ignore_dir|
if absolute_path == castle_home.join(ignore_dir)
matched = true
break
end
end
next if matched
relative_dir = absolute_basedir.relative_path_from(castle_home)
home_path = home_dir.join(relative_dir).join(path)
ln_s absolute_path, home_path
end
end
end
end end

View File

@@ -3,10 +3,7 @@ class Homesick
# TODO move this to be more like thor's template, empty_directory, etc # TODO move this to be more like thor's template, empty_directory, etc
def git_clone(repo, config = {}) def git_clone(repo, config = {})
config ||= {} config ||= {}
destination = config[:destination] || begin destination = config[:destination] || File.basename(repo, '.git')
repo =~ /([^\/]+)\.git$/
$1
end
destination = Pathname.new(destination) unless destination.kind_of?(Pathname) destination = Pathname.new(destination) unless destination.kind_of?(Pathname)
FileUtils.mkdir_p destination.dirname FileUtils.mkdir_p destination.dirname
@@ -19,13 +16,13 @@ class Homesick
end end
end end
def git_init(path = ".") def git_init(path = '.')
path = Pathname.new(path) path = Pathname.new(path)
inside path do inside path do
unless path.join('.git').exist? if !path.join('.git').exist?
say_status 'git init', '' unless options[:quiet] say_status 'git init', '' unless options[:quiet]
system "git init >/dev/null" unless options[:pretend] system 'git init >/dev/null' unless options[:pretend]
else else
say_status 'git init', 'already initialized', :blue unless options[:quiet] say_status 'git init', 'already initialized', :blue unless options[:quiet]
end end
@@ -36,7 +33,7 @@ class Homesick
existing_remote = `git config remote.#{name}.url`.chomp existing_remote = `git config remote.#{name}.url`.chomp
existing_remote = nil if existing_remote == '' existing_remote = nil if existing_remote == ''
unless existing_remote if !existing_remote
say_status 'git remote', "add #{name} #{url}" unless options[:quiet] say_status 'git remote', "add #{name} #{url}" unless options[:quiet]
system "git remote add #{name} #{url}" unless options[:pretend] system "git remote add #{name} #{url}" unless options[:pretend]
else else
@@ -46,17 +43,42 @@ class Homesick
def git_submodule_init(config = {}) def git_submodule_init(config = {})
say_status 'git submodule', 'init', :green unless options[:quiet] say_status 'git submodule', 'init', :green unless options[:quiet]
system "git submodule --quiet init" unless options[:pretend] system 'git submodule --quiet init' unless options[:pretend]
end end
def git_submodule_update(config = {}) def git_submodule_update(config = {})
say_status 'git submodule', 'update', :green unless options[:quiet] say_status 'git submodule', 'update', :green unless options[:quiet]
system "git submodule --quiet update >/dev/null 2>&1" unless options[:pretend] system 'git submodule --quiet update --init --recursive >/dev/null 2>&1' unless options[:pretend]
end end
def git_pull(config = {}) def git_pull(config = {})
say_status 'git pull', '', :green unless options[:quiet] say_status 'git pull', '', :green unless options[:quiet]
system "git pull --quiet" unless options[:pretend] system 'git pull --quiet' unless options[:pretend]
end
def git_push(config = {})
say_status 'git push', '', :green unless options[:quiet]
system 'git push' unless options[:pretend]
end
def git_commit_all(config = {})
say_status 'git commit all', '', :green unless options[:quiet]
system 'git commit -v -a' unless options[:pretend]
end
def git_add(file, config = {})
say_status 'git add file', '', :green unless options[:quiet]
system "git add #{file}" unless options[:pretend]
end
def git_status(config = {})
say_status 'git status', '', :green unless options[:quiet]
system "git status" unless options[:pretend]
end
def git_diff(config = {})
say_status 'git diff', '', :green unless options[:quiet]
system "git diff" unless options[:pretend]
end end
def mv(source, destination, config = {}) def mv(source, destination, config = {})
@@ -78,6 +100,7 @@ class Homesick
def ln_s(source, destination, config = {}) def ln_s(source, destination, config = {})
source = Pathname.new(source) source = Pathname.new(source)
destination = Pathname.new(destination) destination = Pathname.new(destination)
FileUtils.mkdir_p destination.dirname
if destination.symlink? if destination.symlink?
if destination.readlink == source if destination.readlink == source
@@ -86,13 +109,14 @@ class Homesick
say_status :conflict, "#{destination} exists and points to #{destination.readlink}", :red unless options[:quiet] say_status :conflict, "#{destination} exists and points to #{destination.readlink}", :red unless options[:quiet]
if options[:force] || shell.file_collision(destination) { source } if options[:force] || shell.file_collision(destination) { source }
system "ln -sf #{source} #{destination}" unless options[:pretend] system "ln -nsf #{source} #{destination}" unless options[:pretend]
end end
end end
elsif destination.exist? elsif destination.exist?
say_status :conflict, "#{destination} exists", :red unless options[:quiet] say_status :conflict, "#{destination} exists", :red unless options[:quiet]
if options[:force] || shell.file_collision(destination) { source } if options[:force] || shell.file_collision(destination) { source }
system "rm -rf #{destination}" unless options[:pretend]
system "ln -sf #{source} #{destination}" unless options[:pretend] system "ln -sf #{source} #{destination}" unless options[:pretend]
end end
else else

View File

@@ -1,113 +1,341 @@
require 'spec_helper' require 'spec_helper'
describe Homesick do describe 'homesick' do
before do let(:home) { create_construct }
@homesick = Homesick.new after { home.destroy! }
end
describe "clone" do let(:castles) { home.directory('.homesick/repos') }
it "should symlink existing directories" do
somewhere = create_construct
somewhere.directory('wtf')
wtf = somewhere + 'wtf'
@homesick.should_receive(:ln_s).with(wtf.to_s, wtf.basename) let(:homesick) { Homesick.new }
@homesick.clone wtf.to_s before { homesick.stub!(:repos_dir).and_return(castles) }
end
it "should clone git repo like git://host/path/to.git" do describe 'clone' do
@homesick.should_receive(:git_clone).with('git://github.com/technicalpickles/pickled-vim.git') context 'of a file' do
it 'should symlink existing directories' do
somewhere = create_construct
local_repo = somewhere.directory('wtf')
@homesick.clone "git://github.com/technicalpickles/pickled-vim.git" homesick.clone local_repo
end
it "should clone git repo like git@host:path/to.git" do castles.join('wtf').readlink.should == local_repo
@homesick.should_receive(:git_clone).with('git@github.com:technicalpickles/pickled-vim.git') end
@homesick.clone 'git@github.com:technicalpickles/pickled-vim.git' context 'when it exists in a repo directory' do
end before do
existing_castle = given_castle('existing_castle')
it "should clone git repo like http://host/path/to.git" do @existing_dir = existing_castle.parent
@homesick.should_receive(:git_clone).with('http://github.com/technicalpickles/pickled-vim.git') end
@homesick.clone 'http://github.com/technicalpickles/pickled-vim.git' it 'should raise an error' do
end homesick.should_not_receive(:git_clone)
expect { homesick.clone @existing_dir.to_s }.to raise_error(/already cloned/i)
it "should clone git repo like http://host/path/to" do end
@homesick.should_receive(:git_clone).with('http://github.com/technicalpickles/pickled-vim') end
end
@homesick.clone 'http://github.com/technicalpickles/pickled-vim'
end it 'should clone git repo like file:///path/to.git' do
bare_repo = File.join(create_construct.to_s, 'dotfiles.git')
it "should clone git repo like host-alias:repos.git" do system "git init --bare #{bare_repo} >/dev/null 2>&1"
@homesick.should_receive(:git_clone).with('gitolite:pickled-vim.git')
homesick.clone "file://#{bare_repo}"
@homesick.clone 'gitolite:pickled-vim.git' File.directory?(File.join(home.to_s, '.homesick/repos/dotfiles')).should be_true
end end
it "should not try to clone a malformed uri like malformed" do it 'should clone git repo like git://host/path/to.git' do
@homesick.should_not_receive(:git_clone) homesick.should_receive(:git_clone).with('git://github.com/technicalpickles/pickled-vim.git')
@homesick.clone 'malformed' rescue nil homesick.clone 'git://github.com/technicalpickles/pickled-vim.git'
end end
it "should throw an exception when trying to clone a malformed uri like malformed" do it 'should clone git repo like git@host:path/to.git' do
lambda { homesick.should_receive(:git_clone).with('git@github.com:technicalpickles/pickled-vim.git')
@homesick.clone 'malformed'
}.should raise_error homesick.clone 'git@github.com:technicalpickles/pickled-vim.git'
end end
it "should clone a github repo" do it 'should clone git repo like http://host/path/to.git' do
@homesick.should_receive(:git_clone).with('git://github.com/wfarr/dotfiles.git', :destination => Pathname.new('wfarr/dotfiles')) homesick.should_receive(:git_clone).with('http://github.com/technicalpickles/pickled-vim.git')
@homesick.clone "wfarr/dotfiles" homesick.clone 'http://github.com/technicalpickles/pickled-vim.git'
end end
end
it 'should clone git repo like http://host/path/to' do
describe "list" do homesick.should_receive(:git_clone).with('http://github.com/technicalpickles/pickled-vim')
# FIXME only passes in isolation. need to setup data a bit better homesick.clone 'http://github.com/technicalpickles/pickled-vim'
xit "should say each castle in the castle directory" do end
@user_dir.directory '.homesick/repos' do |repos_dir|
repos_dir.directory 'zomg' do |zomg| it 'should clone git repo like host-alias:repos.git' do
Dir.chdir do homesick.should_receive(:git_clone).with('gitolite:pickled-vim.git')
system "git init >/dev/null 2>&1"
system "git remote add origin git://github.com/technicalpickles/zomg.git >/dev/null 2>&1" homesick.clone 'gitolite:pickled-vim.git'
end end
end
it 'should throw an exception when trying to clone a malformed uri like malformed' do
repos_dir.directory 'wtf/zomg' do |zomg| homesick.should_not_receive(:git_clone)
Dir.chdir do expect { homesick.clone 'malformed' }.to raise_error
system "git init >/dev/null 2>&1" end
system "git remote add origin git://github.com/technicalpickles/zomg.git >/dev/null 2>&1"
end it 'should clone a github repo' do
end homesick.should_receive(:git_clone).with('git://github.com/wfarr/dotfiles.git', :destination => Pathname.new('wfarr/dotfiles'))
end
@homesick.should_receive(:say_status).with("zomg", "git://github.com/technicalpickles/zomg.git", :cyan) homesick.clone 'wfarr/dotfiles'
@homesick.should_receive(:say_status).with("wtf/zomg", "git://github.com/technicalpickles/zomg.git", :cyan) end
end
@homesick.list
end describe 'symlink' do
end let(:castle) { given_castle('glencairn') }
describe "track" do it 'links dotfiles from a castle to the home folder' do
it "should move the tracked file into the castle" do dotfile = castle.file('.some_dotfile')
some_rc_file = @user_dir.file '.some_rc_file'
homesickrepo = @user_dir.directory('.homesick').directory('repos').directory('castle_repo') homesick.symlink('glencairn')
castle_path = homesickrepo.directory 'home'
home.join('.some_dotfile').readlink.should == dotfile
# There is some hideous thing going on with construct; rming the file I'm moving works on this test. end
# Otherwise when track ln_s's it back out, it sees a conflict. Its as if file operations don't
# actually effect this thing, or something. it 'links non-dotfiles from a castle to the home folder' do
system "rm #{some_rc_file.to_s}" dotfile = castle.file('bin')
Dir.chdir homesickrepo do
system "git init >/dev/null 2>&1" homesick.symlink('glencairn')
home.join('bin').readlink.should == dotfile
end
context 'when forced' do
let(:homesick) { Homesick.new [], :force => true }
it 'can override symlinks to directories' do
somewhere_else = create_construct
existing_dotdir_link = home.join('.vim')
FileUtils.ln_s somewhere_else, existing_dotdir_link
dotdir = castle.directory('.vim')
homesick.symlink('glencairn')
existing_dotdir_link.readlink.should == dotdir
end
it 'can override existing directory' do
existing_dotdir = home.directory('.vim')
dotdir = castle.directory('.vim')
homesick.symlink('glencairn')
existing_dotdir.readlink.should == dotdir
end
end
context "with '.config' in .homesick_subdir" do
let(:castle) { given_castle('glencairn', ['.config']) }
it 'can symlink in sub directory' do
dotdir = castle.directory('.config')
dotfile = dotdir.file('.some_dotfile')
homesick.symlink('glencairn')
home_dotdir = home.join('.config')
home_dotdir.symlink?.should be == false
home_dotdir.join('.some_dotfile').readlink.should == dotfile
end
end
context "with '.config/appA' in .homesick_subdir" do
let(:castle) { given_castle('glencairn', ['.config/appA']) }
it 'can symlink in nested sub directory' do
dotdir = castle.directory('.config').directory('appA')
dotfile = dotdir.file('.some_dotfile')
homesick.symlink('glencairn')
home_dotdir = home.join('.config').join('appA')
home_dotdir.symlink?.should be == false
home_dotdir.join('.some_dotfile').readlink.should == dotfile
end
end
context "with '.config' and '.config/someapp' in .homesick_subdir" do
let(:castle) { given_castle('glencairn', ['.config', '.config/someapp']) }
it 'can symlink under both of .config and .config/someapp' do
config_dir = castle.directory('.config')
config_dotfile = config_dir.file('.some_dotfile')
someapp_dir = config_dir.directory('someapp')
someapp_dotfile = someapp_dir.file('.some_appfile')
homesick.symlink('glencairn')
home_config_dir = home.join('.config')
home_someapp_dir = home_config_dir.join('someapp')
home_config_dir.symlink?.should be == false
home_config_dir.join('.some_dotfile').readlink.should be == config_dotfile
home_someapp_dir.symlink?.should be == false
home_someapp_dir.join('.some_appfile').readlink.should == someapp_dotfile
end
end
context "when call with no castle name" do
let(:castle) { given_castle('dotfiles') }
it 'using default castle name: "dotfiles"' do
dotfile = castle.file('.some_dotfile')
homesick.symlink
home.join('.some_dotfile').readlink.should == dotfile
end
end
end
describe 'list' do
it 'should say each castle in the castle directory' do
given_castle('zomg')
given_castle('wtf/zomg')
homesick.should_receive(:say_status).with('zomg', 'git://github.com/technicalpickles/zomg.git', :cyan)
homesick.should_receive(:say_status).with('wtf/zomg', 'git://github.com/technicalpickles/zomg.git', :cyan)
homesick.list
end
end
describe 'status' do
xit 'needs testing'
end
describe 'diff' do
xit 'needs testing'
end
describe 'show_path' do
it 'should say the path of a castle' do
castle = given_castle('castle_repo')
homesick.should_receive(:say).with(castle.dirname)
homesick.show_path('castle_repo')
end
end
describe 'pull' do
xit 'needs testing'
describe '--all' do
xit 'needs testing'
end
end
describe 'commit' do
xit 'needs testing'
end
describe 'push' do
xit 'needs testing'
end
describe 'track' do
it 'should move the tracked file into the castle' do
castle = given_castle('castle_repo')
some_rc_file = home.file '.some_rc_file'
homesick.track(some_rc_file.to_s, 'castle_repo')
tracked_file = castle.join('.some_rc_file')
tracked_file.should exist
some_rc_file.readlink.should == tracked_file
end
it 'should track a file in nested folder structure' do
castle = given_castle('castle_repo')
some_nested_file = home.file('some/nested/file.txt')
homesick.track(some_nested_file.to_s, 'castle_repo')
tracked_file = castle.join('some/nested/file.txt')
tracked_file.should exist
some_nested_file.readlink.should == tracked_file
end
it 'should track a nested directory' do
castle = given_castle('castle_repo')
some_nested_dir = home.directory('some/nested/directory/')
homesick.track(some_nested_dir.to_s, 'castle_repo')
tracked_file = castle.join('some/nested/directory/')
tracked_file.should exist
some_nested_dir.realpath.should == tracked_file.realpath
end
context "when call with no castle name" do
it 'using default castle name: "dotfiles"' do
castle = given_castle('dotfiles')
some_rc_file = home.file '.some_rc_file'
homesick.track(some_rc_file.to_s)
tracked_file = castle.join('.some_rc_file')
tracked_file.should exist
some_rc_file.readlink.should == tracked_file
end
end
describe 'subdir_file' do
it 'should add the nested files parent to the subdir_file' do
castle = given_castle('castle_repo')
some_nested_file = home.file('some/nested/file.txt')
homesick.track(some_nested_file.to_s, 'castle_repo')
subdir_file = castle.parent.join(Homesick::SUBDIR_FILENAME)
File.open(subdir_file, 'r') do |f|
f.readline.should == "some/nested\n"
end
end
it 'should NOT add anything if the files parent is already listed' do
castle = given_castle('castle_repo')
some_nested_file = home.file('some/nested/file.txt')
other_nested_file = home.file('some/nested/other.txt')
homesick.track(some_nested_file.to_s, 'castle_repo')
homesick.track(other_nested_file.to_s, 'castle_repo')
subdir_file = castle.parent.join(Homesick::SUBDIR_FILENAME)
File.open(subdir_file, 'r') do |f|
f.readlines.size.should == 1
end
end
it 'should remove the parent of a tracked file from the subdir_file if the parent itself is tracked' do
castle = given_castle('castle_repo')
some_nested_file = home.file('some/nested/file.txt')
nested_parent = home.directory('some/nested/')
homesick.track(some_nested_file.to_s, 'castle_repo')
homesick.track(nested_parent.to_s, 'castle_repo')
subdir_file = castle.parent.join(Homesick::SUBDIR_FILENAME)
File.open(subdir_file, 'r') do |f|
f.each_line { |line| line.should_not == "some/nested\n" }
end
end end
@homesick.should_receive(:mv).with(some_rc_file, castle_path)
@homesick.should_receive(:ln_s).with(castle_path + some_rc_file.basename, some_rc_file)
@homesick.track(some_rc_file.to_s, 'castle_repo')
end end
end end
end end

View File

@@ -5,15 +5,31 @@ require 'rspec'
require 'rspec/autorun' require 'rspec/autorun'
require 'construct' require 'construct'
Rspec.configure do |config| RSpec.configure do |config|
config.include Construct::Helpers config.include Construct::Helpers
config.before do config.before { ENV['HOME'] = home.to_s }
@user_dir = create_construct
ENV['HOME'] = @user_dir.to_s config.before { silence! }
def silence!
homesick.stub(:say_status)
end end
config.after do def given_castle(path, subdirs = [])
@user_dir.destroy! name = Pathname.new(path).basename
castles.directory(path) do |castle|
Dir.chdir(castle) do
system 'git init >/dev/null 2>&1'
system "git remote add origin git://github.com/technicalpickles/#{name}.git >/dev/null 2>&1"
if subdirs
subdir_file = castle.join(Homesick::SUBDIR_FILENAME)
subdirs.each do |subdir|
system "echo #{subdir} >> #{subdir_file}"
end
end
return castle.directory('home')
end
end
end end
end end