89 Commits

Author SHA1 Message Date
Trae Robrock
093db8bdac Regenerate gemspec for version 0.9.6 2013-10-18 07:18:15 -07:00
Trae Robrock
04602efd6e Bump version 2013-10-18 07:18:07 -07:00
Trae Robrock
3265de0c1d Regenerate gemspec for version 0.9.5 2013-10-18 07:17:39 -07:00
Trae Robrock
e4a428e0c5 Merge pull request #55 from mingkai0812/master
Change github-repo pattern to allow numbers for usernames/repos
2013-10-18 07:15:05 -07:00
mingkai
6cc28450a4 Change github-repo pattern to allow numbers for usernames/repos 2013-10-18 14:35:56 +02:00
Yusuke Murata
a0c7fbacb7 Merge pull request #53 from boyvanduuren/issue52
Change the destination for the github clone shortcut
2013-10-07 09:39:40 -07:00
bcd87
b750094934 Rake now passes on Ruby 1.8.7 on my machine 2013-09-24 08:15:56 +02:00
bcd87
d953a964cd Changed the spec, bundle exec rake works 2013-09-23 20:58:16 +02:00
bcd87
aa95ffac82 Using the homesick clone github shortcut now clones to ~/.homesick/repos/repo/, in stead of ~/.homesick/repos/username/repo/ 2013-09-23 20:30:10 +02:00
Trae Robrock
9c345828b0 Regenerate gemspec for version 0.9.5 2013-09-18 09:48:33 -07:00
Trae Robrock
59c137c653 Bump version the right way 2013-09-18 09:48:26 -07:00
Trae Robrock
3d405542af Regenerate gemspec for version 0.9.4 2013-09-18 09:47:46 -07:00
Trae Robrock
88ff4b85ce Bump version 2013-09-18 09:47:36 -07:00
Trae Robrock
461ac5f226 Merge pull request #51 from trobrock/fix-quoting
Files with parentheses in filename fail to symlink/track
2013-09-18 09:46:40 -07:00
Trae Robrock
a7d2d0a3f3 Add test for parens in filenames, and fixed 2013-09-18 09:25:09 -07:00
muratayusuke
191ce11d8e Regenerate gemspec for version 0.9.4 2013-07-31 23:41:49 +09:00
muratayusuke
0d28a3ef9b bump up version 2013-07-31 23:41:36 +09:00
muratayusuke
ac34249afe Regenerate gemspec for version 0.9.3 2013-07-31 23:40:22 +09:00
muratayusuke
d1f87be435 bump up version 2013-07-31 23:38:37 +09:00
muratayusuke
cbb6117d69 remove unused variables 2013-07-31 23:21:46 +09:00
muratayusuke
334a1db262 fix deprecated method: stub! -> stub 2013-07-31 23:14:51 +09:00
Yusuke Murata
e3bee69b27 Merge pull request #48 from trobrock/fix-homesickrc
Fix #19 homesickrc pathname needs a to_s to eval
2013-07-30 09:54:48 -07:00
Yusuke Murata
0ff5325e3e Merge pull request #43 from johnbellone/master
Default GitHub to use HTTPS protocol.
2013-07-21 10:47:31 -07:00
Yusuke Murata
40efb2f58a Merge pull request #47 from trobrock/unlink
Adding unlink function
2013-07-21 10:37:16 -07:00
Trae Robrock
4b20c7224e Add tests for the rc command 2013-07-17 08:04:34 -07:00
Trae Robrock
8e06beced6 Ignore vendor 2013-07-17 07:26:00 -07:00
Trae Robrock
b043f2a5ed Adding test for clone running homesickrc 2013-07-17 07:23:35 -07:00
John Bellone
3d59bc7a97 Update specs to for change to https vs. git protocol. 2013-07-17 07:28:39 -04:00
Trae Robrock
75dcad8ea4 Fix #19 homesickrc pathname needs a to_s to eval
Also, moved the file evaluation into a new function so the script can be
ran manually which should make testing these scripts easier.
2013-07-16 21:13:09 -07:00
Trae Robrock
4b38eb848f Add unlink functionality 2013-07-16 20:50:36 -07:00
Trae Robrock
bfce04e63c Ignore vendor dir 2013-07-16 20:49:40 -07:00
muratayusuke
846c5c202b Regenerate gemspec for version 0.9.3 2013-07-07 03:36:51 +09:00
muratayusuke
600811ff01 bump up version 2013-07-07 03:26:34 +09:00
muratayusuke
26ce289e9b add recursive option to 'homesick clone' 2013-07-01 16:35:19 +00:00
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
John Bellone
92dc611bb1 Update homesick.rb to make https default for GitHub clones.
If we use HTTPS it is a lot easier for corporate worlds to manage proxies since its usually already done for us. Also HTTPS cloning is just as fast as the git protocol as of more recent versions.
2013-06-21 09:45:26 -03: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
13 changed files with 825 additions and 206 deletions

7
.gitignore vendored
View File

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

View File

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

View File

@@ -1,3 +1,28 @@
# 0.9.4
* Use https protocol instead of git protocol
* Introduce new commands
* `homesick unlink`
* `homesick rc`
# 0.9.3
* Add recursive option to `homesick clone`
# 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 # 0.8.0
* Introduce commit & push command * Introduce commit & push command
* commit changes in castle and push to remote * commit changes in castle and push to remote

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", "~> 0.8.7" gem "rake", ">= 0.8.7"
gem "rspec", "~> 2.10" gem "rspec", "~> 2.10"
gem "jeweler", ">= 1.6.2" gem "jeweler", ">= 1.6.2"
gem "rcov", :platforms => :mri_18 gem "rcov", :platforms => :mri_18
gem "simplecov", :platforms => :mri_19 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,42 +0,0 @@
GEM
remote: http://rubygems.org/
specs:
diff-lcs (1.1.3)
git (1.2.5)
jeweler (1.8.3)
bundler (~> 1.0)
git (>= 1.2.5)
rake
rdoc
json (1.7.3)
multi_json (1.3.6)
rake (0.8.7)
rcov (1.0.0)
rdoc (3.12)
json (~> 1.4)
rspec (2.10.0)
rspec-core (~> 2.10.0)
rspec-expectations (~> 2.10.0)
rspec-mocks (~> 2.10.0)
rspec-core (2.10.1)
rspec-expectations (2.10.0)
diff-lcs (~> 1.1.3)
rspec-mocks (2.10.1)
simplecov (0.6.4)
multi_json (~> 1.0)
simplecov-html (~> 0.5.3)
simplecov-html (0.5.3)
test-construct (1.2.0)
thor (0.15.2)
PLATFORMS
ruby
DEPENDENCIES
jeweler (>= 1.6.2)
rake (~> 0.8.7)
rcov
rspec (~> 2.10)
simplecov
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.
@@ -29,6 +31,10 @@ If you use the shorthand syntax for GitHub repositories in your clone, please no
homesick symlink technicalpickles/pickled-vim homesick symlink technicalpickles/pickled-vim
You can remove symlinks anytime when you don't need them anymore
homesick unlink pickled-vim
If you're not sure what castles you have around, you can easily list them: If you're not sure what castles you have around, you can easily list them:
homesick list homesick list
@@ -49,6 +55,84 @@ 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.

View File

@@ -22,7 +22,7 @@ Jeweler::Tasks.new do |gem|
gem.email = ["josh@technicalpickles.com", "info@muratayusuke.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", "Yusuke Murata"] gem.authors = ["Joshua Nichols", "Yusuke Murata"]
gem.version = "0.8.0" gem.version = "0.9.6"
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

@@ -5,11 +5,11 @@
Gem::Specification.new do |s| Gem::Specification.new do |s|
s.name = "homesick" s.name = "homesick"
s.version = "0.8.0" s.version = "0.9.6"
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", "Yusuke Murata"] s.authors = ["Joshua Nichols", "Yusuke Murata"]
s.date = "2013-04-05" s.date = "2013-10-18"
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 " 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 "
s.email = ["josh@technicalpickles.com", "info@muratayusuke.com"] s.email = ["josh@technicalpickles.com", "info@muratayusuke.com"]
s.executables = ["homesick"] s.executables = ["homesick"]
@@ -24,7 +24,6 @@ Gem::Specification.new do |s|
".travis.yml", ".travis.yml",
"ChangeLog.markdown", "ChangeLog.markdown",
"Gemfile", "Gemfile",
"Gemfile.lock",
"LICENSE", "LICENSE",
"README.markdown", "README.markdown",
"Rakefile", "Rakefile",
@@ -40,7 +39,7 @@ Gem::Specification.new do |s|
s.homepage = "http://github.com/technicalpickles/homesick" s.homepage = "http://github.com/technicalpickles/homesick"
s.licenses = ["MIT"] s.licenses = ["MIT"]
s.require_paths = ["lib"] s.require_paths = ["lib"]
s.rubygems_version = "1.8.24" s.rubygems_version = "1.8.23"
s.summary = "A man's home is his castle. Never leave your dotfiles behind." s.summary = "A man's home is his castle. Never leave your dotfiles behind."
if s.respond_to? :specification_version then if s.respond_to? :specification_version then
@@ -48,29 +47,32 @@ Gem::Specification.new do |s|
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.8.7"]) s.add_development_dependency(%q<rake>, [">= 0.8.7"])
s.add_development_dependency(%q<rspec>, ["~> 2.10"]) s.add_development_dependency(%q<rspec>, ["~> 2.10"])
s.add_development_dependency(%q<jeweler>, [">= 1.6.2"]) s.add_development_dependency(%q<jeweler>, [">= 1.6.2"])
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<simplecov>, [">= 0"])
s.add_development_dependency(%q<test-construct>, [">= 0"]) s.add_development_dependency(%q<test-construct>, [">= 0"])
s.add_development_dependency(%q<rubocop>, [">= 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.8.7"]) s.add_dependency(%q<rake>, [">= 0.8.7"])
s.add_dependency(%q<rspec>, ["~> 2.10"]) s.add_dependency(%q<rspec>, ["~> 2.10"])
s.add_dependency(%q<jeweler>, [">= 1.6.2"]) s.add_dependency(%q<jeweler>, [">= 1.6.2"])
s.add_dependency(%q<rcov>, [">= 0"]) s.add_dependency(%q<rcov>, [">= 0"])
s.add_dependency(%q<simplecov>, [">= 0"]) s.add_dependency(%q<simplecov>, [">= 0"])
s.add_dependency(%q<test-construct>, [">= 0"]) s.add_dependency(%q<test-construct>, [">= 0"])
s.add_dependency(%q<rubocop>, [">= 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.8.7"]) s.add_dependency(%q<rake>, [">= 0.8.7"])
s.add_dependency(%q<rspec>, ["~> 2.10"]) s.add_dependency(%q<rspec>, ["~> 2.10"])
s.add_dependency(%q<jeweler>, [">= 1.6.2"]) s.add_dependency(%q<jeweler>, [">= 1.6.2"])
s.add_dependency(%q<rcov>, [">= 0"]) s.add_dependency(%q<rcov>, [">= 0"])
s.add_dependency(%q<simplecov>, [">= 0"]) s.add_dependency(%q<simplecov>, [">= 0"])
s.add_dependency(%q<test-construct>, [">= 0"]) s.add_dependency(%q<test-construct>, [">= 0"])
s.add_dependency(%q<rubocop>, [">= 0"])
end end
end end

View File

@@ -9,14 +9,17 @@ 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-z0-9_-]+\/[A-Za-z0-9_-]+)\Z/
SUBDIR_FILENAME = '.homesick_subdir'
DEFAULT_CASTLE_NAME = 'dotfiles'
def initialize(args = [], options = {}, config = {}) 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
@@ -30,9 +33,9 @@ class Homesick < Thor
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(uri).basename
git_clone "git://github.com/#{$1}.git", :destination => destination git_clone "https://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/
@@ -49,24 +52,32 @@ class Homesick < Thor
end end
end end
rc(destination)
end
end
desc 'rc CASTLE', 'Run the .homesickrc for the specified castle'
def rc(name = DEFAULT_CASTLE_NAME)
inside repos_dir do
destination = Pathname.new(name)
homesickrc = destination.join('.homesickrc').expand_path homesickrc = destination.join('.homesickrc').expand_path
if homesickrc.exist? if homesickrc.exist?
proceed = shell.yes?("#{uri} has a .homesickrc. Proceed with evaling it? (This could be destructive)") proceed = shell.yes?("#{name} 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.to_s
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 CASTLE", "Update the specified castle" desc 'pull CASTLE', 'Update the specified castle'
method_option :all, :type => :boolean, :default => false, :required => false, :desc => "Update all cloned castles" method_option :all, :type => :boolean, :default => false, :required => false, :desc => 'Update all cloned castles'
def pull(name="") def pull(name = DEFAULT_CASTLE_NAME)
if options[:all] if options[:all]
inside_each_castle do |castle| inside_each_castle do |castle|
shell.say castle.to_s.gsub(repos_dir.to_s + '/', '') + ':' shell.say castle.to_s.gsub(repos_dir.to_s + '/', '') + ':'
@@ -78,71 +89,130 @@ class Homesick < Thor
end end
desc "commit CASTLE", "Commit the specified castle's changes" desc 'commit CASTLE', "Commit the specified castle's changes"
def commit(name) def commit(name = DEFAULT_CASTLE_NAME)
commit_castle name commit_castle name
end end
desc "push CASTLE", "Push the specified castle" desc 'push CASTLE', 'Push the specified castle'
def push(name) def push(name = DEFAULT_CASTLE_NAME)
push_castle name push_castle name
end end
desc "symlink CASTLE", "Symlinks all dotfiles from the specified castle" desc 'unlink CASTLE', 'Unsymlinks all dotfiles from the specified castle'
method_option :force, :default => false, :desc => "Overwrite existing conflicting symlinks without prompting." def unlink(name = DEFAULT_CASTLE_NAME)
def symlink(name) check_castle_existance(name, 'symlink')
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 # unlink files
adjusted_path = (home_dir + path).basename unsymlink_each(name, castle_dir(name), subdirs)
ln_s absolute_path, adjusted_path # unlink files in subdirs
end subdirs.each do |subdir|
unsymlink_each(name, subdir, subdirs)
end end
end end
end end
desc "track FILE CASTLE", "add a file to a castle" desc 'symlink CASTLE', 'Symlinks all dotfiles from the specified castle'
def track(file, 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
subdirs = subdirs(name)
# link files
symlink_each(name, castle_dir(name), subdirs)
# link files in subdirs
subdirs.each do |subdir|
symlink_each(name, subdir, subdirs)
end
end
end
desc 'track FILE CASTLE', 'add a file to a 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
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 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 inside castle_path do
git_add absolute_path git_add absolute_path
end 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
inside_each_castle do |castle| inside_each_castle do |castle|
say_status castle.relative_path_from(repos_dir).to_s, `git config remote.origin.url`.chomp, :cyan say_status castle.relative_path_from(repos_dir).to_s, `git config remote.origin.url`.chomp, :cyan
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
@@ -153,7 +223,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
@@ -181,10 +251,12 @@ class Homesick < Thor
end end
def all_castles def all_castles
dirs = Pathname.glob("#{repos_dir}/**/*/.git") dirs = Pathname.glob("#{repos_dir}/**/.git", File::FNM_DOTMATCH)
# reject paths that lie inside another castle, like git submodules # reject paths that lie inside another castle, like git submodules
return dirs.reject do |dir| return dirs.reject do |dir|
dirs.any? {|other| dir != other && dir.fnmatch(other.parent.join('*').to_s) } dirs.any? do |other|
dir != other && dir.fnmatch(other.parent.join('*').to_s)
end
end end
end end
@@ -198,7 +270,7 @@ class Homesick < Thor
end end
def update_castle(castle) def update_castle(castle)
check_castle_existance(castle, "pull") check_castle_existance(castle, 'pull')
inside repos_dir.join(castle) do inside repos_dir.join(castle) do
git_pull git_pull
git_submodule_init git_submodule_init
@@ -207,16 +279,126 @@ class Homesick < Thor
end end
def commit_castle(castle) def commit_castle(castle)
check_castle_existance(castle, "commit") check_castle_existance(castle, 'commit')
inside repos_dir.join(castle) do inside repos_dir.join(castle) do
git_commit_all git_commit_all
end end
end end
def push_castle(castle) def push_castle(castle)
check_castle_existance(castle, "push") check_castle_existance(castle, 'push')
inside repos_dir.join(castle) do inside repos_dir.join(castle) do
git_push git_push
end end
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 each_file(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)
yield(absolute_path, home_path)
end
end
end
def unsymlink_each(castle, basedir, subdirs)
each_file(castle, basedir, subdirs) do |absolute_path, home_path|
rm_link home_path
end
end
def symlink_each(castle, basedir, subdirs)
each_file(castle, basedir, subdirs) do |absolute_path, home_path|
ln_s absolute_path, home_path
end
end
end end

View File

@@ -3,29 +3,26 @@ 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
if ! destination.directory? if ! destination.directory?
say_status 'git clone', "#{repo} to #{destination.expand_path}", :green unless options[:quiet] say_status 'git clone', "#{repo} to #{destination.expand_path}", :green unless options[:quiet]
system "git clone -q #{repo} #{destination}" unless options[:pretend] system "git clone -q --recursive #{repo} #{destination}" unless options[:pretend]
else else
say_status :exist, destination.expand_path, :blue unless options[:quiet] say_status :exist, destination.expand_path, :blue unless options[:quiet]
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,32 +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 --init --recursive >/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 end
def git_push(config = {}) def git_push(config = {})
say_status 'git push', '', :green unless options[:quiet] say_status 'git push', '', :green unless options[:quiet]
system "git push" unless options[:pretend] system 'git push' unless options[:pretend]
end end
def git_commit_all(config = {}) def git_commit_all(config = {})
say_status 'git commit all', '', :green unless options[:quiet] say_status 'git commit all', '', :green unless options[:quiet]
system "git commit -v -a" unless options[:pretend] system 'git commit -v -a' unless options[:pretend]
end end
def git_add(file, config = {}) def git_add(file, config = {})
say_status 'git add file', '', :green unless options[:quiet] say_status 'git add file', '', :green unless options[:quiet]
system "git add #{file}" unless options[:pretend] 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 = {})
@@ -82,17 +89,29 @@ class Homesick
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 "mv #{source} #{destination}" unless options[:pretend] system "mv '#{source}' '#{destination}'" unless options[:pretend]
end end
else else
# this needs some sort of message here. # this needs some sort of message here.
system "mv #{source} #{destination}" unless options[:pretend] system "mv '#{source}' '#{destination}'" unless options[:pretend]
end
end
def rm_link(target)
target = Pathname.new(target)
if target.symlink?
say_status :unlink, "#{target.expand_path}", :green unless options[:quiet]
FileUtils.rm_rf target
else
say_status :conflict, "#{target} is not a symlink", :red unless options[:quiet]
end end
end end
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
@@ -101,18 +120,19 @@ 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 -nsf #{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 "ln -sf #{source} #{destination}" unless options[:pretend] system "rm -rf '#{destination}'" unless options[:pretend]
system "ln -sf '#{source}' '#{destination}'" unless options[:pretend]
end end
else else
say_status :symlink, "#{source.expand_path} to #{destination.expand_path}", :green unless options[:quiet] say_status :symlink, "#{source.expand_path} to #{destination.expand_path}", :green unless options[:quiet]
system "ln -s #{source} #{destination}" unless options[:pretend] system "ln -s '#{source}' '#{destination}'" unless options[:pretend]
end end
end end
end end

View File

@@ -1,173 +1,493 @@
require 'spec_helper' require 'spec_helper'
describe "homesick" do describe 'homesick' do
let(:home) { create_construct } let(:home) { create_construct }
after { home.destroy! } after { home.destroy! }
let(:castles) { home.directory(".homesick/repos") } let(:castles) { home.directory('.homesick/repos') }
let(:homesick) { Homesick.new } let(:homesick) { Homesick.new }
before { homesick.stub!(:repos_dir).and_return(castles) } before { homesick.stub(:repos_dir).and_return(castles) }
describe "clone" do describe 'clone' do
context "of a file" do context 'has a .homesickrc' do
it "should symlink existing directories" do it 'should run the .homesickrc' do
somewhere = create_construct
local_repo = somewhere.directory('some_repo')
local_repo.file('.homesickrc') do |file|
file << "File.open(Dir.pwd + '/testing', 'w') { |f| f.print 'testing' }"
end
expect($stdout).to receive(:print)
expect($stdin).to receive(:gets).and_return('y')
homesick.clone local_repo
castles.join('some_repo').join('testing').should exist
end
end
context 'of a file' do
it 'should symlink existing directories' do
somewhere = create_construct somewhere = create_construct
local_repo = somewhere.directory('wtf') local_repo = somewhere.directory('wtf')
homesick.clone local_repo homesick.clone local_repo
castles.join("wtf").readlink.should == local_repo castles.join('wtf').readlink.should == local_repo
end end
context "when it exists in a repo directory" do context 'when it exists in a repo directory' do
before do before do
existing_castle = given_castle("existing_castle") existing_castle = given_castle('existing_castle')
@existing_dir = existing_castle.parent @existing_dir = existing_castle.parent
end end
it "should not symlink" do it 'should raise an error' do
homesick.should_not_receive(:git_clone) homesick.should_not_receive(:git_clone)
homesick.clone @existing_dir.to_s rescue nil
end
it "should raise an error" do
expect { homesick.clone @existing_dir.to_s }.to raise_error(/already cloned/i) expect { homesick.clone @existing_dir.to_s }.to raise_error(/already cloned/i)
end end
end end
end end
it "should clone git repo like git://host/path/to.git" do it 'should clone git repo like file:///path/to.git' do
homesick.should_receive(:git_clone).with('git://github.com/technicalpickles/pickled-vim.git') bare_repo = File.join(create_construct.to_s, 'dotfiles.git')
system "git init --bare #{bare_repo} >/dev/null 2>&1"
homesick.clone "git://github.com/technicalpickles/pickled-vim.git" homesick.clone "file://#{bare_repo}"
File.directory?(File.join(home.to_s, '.homesick/repos/dotfiles')).should be_true
end end
it "should clone git repo like git@host:path/to.git" do it 'should clone git repo like git://host/path/to.git' do
homesick.should_receive(:git_clone).with('git://github.com/technicalpickles/pickled-vim.git')
homesick.clone 'git://github.com/technicalpickles/pickled-vim.git'
end
it 'should clone git repo like git@host:path/to.git' do
homesick.should_receive(:git_clone).with('git@github.com:technicalpickles/pickled-vim.git') homesick.should_receive(:git_clone).with('git@github.com:technicalpickles/pickled-vim.git')
homesick.clone 'git@github.com:technicalpickles/pickled-vim.git' homesick.clone 'git@github.com:technicalpickles/pickled-vim.git'
end end
it "should clone git repo like http://host/path/to.git" do it 'should clone git repo like http://host/path/to.git' do
homesick.should_receive(:git_clone).with('http://github.com/technicalpickles/pickled-vim.git') homesick.should_receive(:git_clone).with('http://github.com/technicalpickles/pickled-vim.git')
homesick.clone 'http://github.com/technicalpickles/pickled-vim.git' homesick.clone 'http://github.com/technicalpickles/pickled-vim.git'
end end
it "should clone git repo like http://host/path/to" do it 'should clone git repo like http://host/path/to' do
homesick.should_receive(:git_clone).with('http://github.com/technicalpickles/pickled-vim') homesick.should_receive(:git_clone).with('http://github.com/technicalpickles/pickled-vim')
homesick.clone 'http://github.com/technicalpickles/pickled-vim' homesick.clone 'http://github.com/technicalpickles/pickled-vim'
end end
it "should clone git repo like host-alias:repos.git" do it 'should clone git repo like host-alias:repos.git' do
homesick.should_receive(:git_clone).with('gitolite:pickled-vim.git') homesick.should_receive(:git_clone).with('gitolite:pickled-vim.git')
homesick.clone 'gitolite:pickled-vim.git' homesick.clone 'gitolite:pickled-vim.git'
end end
it "should not try to clone a malformed uri like malformed" do it 'should throw an exception when trying to clone a malformed uri like malformed' do
homesick.should_not_receive(:git_clone) homesick.should_not_receive(:git_clone)
homesick.clone 'malformed' rescue nil
end
it "should throw an exception when trying to clone a malformed uri like malformed" do
expect { homesick.clone 'malformed' }.to raise_error expect { homesick.clone 'malformed' }.to raise_error
end end
it "should clone a github repo" do it 'should clone a github repo' do
homesick.should_receive(:git_clone).with('git://github.com/wfarr/dotfiles.git', :destination => Pathname.new('wfarr/dotfiles')) homesick.should_receive(:git_clone).with('https://github.com/wfarr/dotfiles.git', :destination => Pathname.new('dotfiles'))
homesick.clone "wfarr/dotfiles" homesick.clone 'wfarr/dotfiles'
end end
end end
describe "symlink" do describe 'rc' do
let(:castle) { given_castle("glencairn") } let(:castle) { given_castle('glencairn') }
it "links dotfiles from a castle to the home folder" do context 'when told to do so' do
dotfile = castle.file(".some_dotfile") before do
expect($stdout).to receive(:print)
homesick.symlink("glencairn") expect($stdin).to receive(:gets).and_return('y')
home.join(".some_dotfile").readlink.should == dotfile
end end
it "links non-dotfiles from a castle to the home folder" do it 'executes the .homesickrc' do
dotfile = castle.file("bin") castle.file('.homesickrc') do |file|
file << "File.open(Dir.pwd + '/testing', 'w') { |f| f.print 'testing' }"
homesick.symlink("glencairn")
home.join("bin").readlink.should == dotfile
end end
context "when forced" do homesick.rc castle
castle.join('testing').should exist
end
end
context 'when told not to do so' do
before do
expect($stdout).to receive(:print)
expect($stdin).to receive(:gets).and_return('n')
end
it 'does not execute the .homesickrc' do
castle.file('.homesickrc') do |file|
file << "File.open(Dir.pwd + '/testing', 'w') { |f| f.print 'testing' }"
end
homesick.rc castle
castle.join('testing').should_not exist
end
end
end
describe 'symlink' do
let(:castle) { given_castle('glencairn') }
it 'links dotfiles from a castle to the home folder' do
dotfile = castle.file('.some_dotfile')
homesick.symlink('glencairn')
home.join('.some_dotfile').readlink.should == dotfile
end
it 'links non-dotfiles from a castle to the home folder' do
dotfile = castle.file('bin')
homesick.symlink('glencairn')
home.join('bin').readlink.should == dotfile
end
context 'when forced' do
let(:homesick) { Homesick.new [], :force => true } let(:homesick) { Homesick.new [], :force => true }
it "can override symlinks to directories" do it 'can override symlinks to directories' do
somewhere_else = create_construct somewhere_else = create_construct
existing_dotdir_link = home.join(".vim") existing_dotdir_link = home.join('.vim')
FileUtils.ln_s somewhere_else, existing_dotdir_link FileUtils.ln_s somewhere_else, existing_dotdir_link
dotdir = castle.directory(".vim") dotdir = castle.directory('.vim')
homesick.symlink("glencairn") homesick.symlink('glencairn')
existing_dotdir_link.readlink.should == dotdir existing_dotdir_link.readlink.should == dotdir
end 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
end end
describe "list" do context "with '.config' in .homesick_subdir" do
it "should say each castle in the castle directory" 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 'unlink' do
let(:castle) { given_castle('glencairn') }
it 'unlinks dotfiles in the home folder' do
castle.file('.some_dotfile')
homesick.symlink('glencairn')
homesick.unlink('glencairn')
home.join('.some_dotfile').should_not exist
end
it 'unlinks non-dotfiles from the home folder' do
castle.file('bin')
homesick.symlink('glencairn')
homesick.unlink('glencairn')
home.join('bin').should_not exist
end
context "with '.config' in .homesick_subdir" do
let(:castle) { given_castle('glencairn', ['.config']) }
it 'can unlink sub directories' do
castle.directory('.config').file('.some_dotfile')
homesick.symlink('glencairn')
homesick.unlink('glencairn')
home_dotdir = home.join('.config')
home_dotdir.should exist
home_dotdir.join('.some_dotfile').should_not exist
end
end
context "with '.config/appA' in .homesick_subdir" do
let(:castle) { given_castle('glencairn', ['.config/appA']) }
it 'can unsymlink in nested sub directory' do
castle.directory('.config').directory('appA').file('.some_dotfile')
homesick.symlink('glencairn')
homesick.unlink('glencairn')
home_dotdir = home.join('.config').join('appA')
home_dotdir.should exist
home_dotdir.join('.some_dotfile').should_not exist
end
end
context "with '.config' and '.config/someapp' in .homesick_subdir" do
let(:castle) { given_castle('glencairn', ['.config', '.config/someapp']) }
it 'can unsymlink under both of .config and .config/someapp' do
config_dir = castle.directory('.config')
config_dir.file('.some_dotfile')
config_dir.directory('someapp').file('.some_appfile')
homesick.symlink('glencairn')
homesick.unlink('glencairn')
home_config_dir = home.join('.config')
home_someapp_dir = home_config_dir.join('someapp')
home_config_dir.should exist
home_config_dir.join('.some_dotfile').should_not exist
home_someapp_dir.should exist
home_someapp_dir.join('.some_appfile').should_not exist
end
end
context "when call with no castle name" do
let(:castle) { given_castle('dotfiles') }
it 'using default castle name: "dotfiles"' do
castle.file('.some_dotfile')
homesick.symlink
homesick.unlink
home.join('.some_dotfile').should_not exist
end
end
end
describe 'list' do
it 'should say each castle in the castle directory' do
given_castle('zomg') given_castle('zomg')
given_castle('zomg', 'wtf/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('zomg', 'git://github.com/technicalpickles/zomg.git', :cyan)
homesick.should_receive(:say_status).with("wtf/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 homesick.list
end end
end end
describe "pull" do describe 'status' do
xit "needs testing" xit 'needs testing'
describe "--all" do end
xit "needs testing"
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
end end
describe "commit" do describe 'commit' do
xit "needs testing" xit 'needs testing'
end end
describe "push" do describe 'push' do
xit "needs testing" xit 'needs testing'
end end
describe "track" do describe 'track' do
it "should move the tracked file into the castle" do it 'should move the tracked file into the castle' do
castle = given_castle('castle_repo') castle = given_castle('castle_repo')
some_rc_file = home.file '.some_rc_file' some_rc_file = home.file '.some_rc_file'
homesick.track(some_rc_file.to_s, 'castle_repo') homesick.track(some_rc_file.to_s, 'castle_repo')
tracked_file = castle.join(".some_rc_file") tracked_file = castle.join('.some_rc_file')
tracked_file.should exist
some_rc_file.readlink.should == tracked_file
end
it 'should handle files with parens' do
castle = given_castle('castle_repo')
some_rc_file = home.file 'Default (Linux).sublime-keymap'
homesick.track(some_rc_file.to_s, 'castle_repo')
tracked_file = castle.join('Default (Linux).sublime-keymap')
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 tracked_file.should exist
some_rc_file.readlink.should == tracked_file some_rc_file.readlink.should == tracked_file
end end
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
end
end end

View File

@@ -16,12 +16,19 @@ RSpec.configure do |config|
homesick.stub(:say_status) homesick.stub(:say_status)
end end
def given_castle(name, path=name) def given_castle(path, subdirs = [])
name = Pathname.new(path).basename
castles.directory(path) do |castle| castles.directory(path) do |castle|
Dir.chdir(castle) do Dir.chdir(castle) do
system "git init >/dev/null 2>&1" system 'git init >/dev/null 2>&1'
system "git remote add origin git://github.com/technicalpickles/#{name}.git >/dev/null 2>&1" system "git remote add origin git://github.com/technicalpickles/#{name}.git >/dev/null 2>&1"
return castle.directory("home") 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