Compare commits
298 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
db0f604faf | ||
|
|
e5a6e43333 | ||
|
|
faa5f0b9ed | ||
|
|
7c13727978 | ||
|
|
2dba8b6496 | ||
|
|
2dadd4e064 | ||
|
|
a60ca62eba | ||
|
|
674ffb6bb2 | ||
|
|
5fa0fc037c | ||
|
|
8a537b8204 | ||
|
|
6e25f13e06 | ||
|
|
df8f6b1cb0 | ||
|
|
6050a9a7ac | ||
|
|
0abd9436ad | ||
|
|
af159f5b97 | ||
|
|
a657c5622e | ||
|
|
6f216cd916 | ||
|
|
8bf1864335 | ||
|
|
8931739e97 | ||
|
|
ab46cf7b2f | ||
|
|
d115714a9f | ||
|
|
e787abd3f3 | ||
|
|
1c0fe66944 | ||
|
|
148d18565f | ||
|
|
264d586863 | ||
|
|
76bee65475 | ||
|
|
8dac49548c | ||
|
|
5c5d204d15 | ||
|
|
e1f85973c1 | ||
|
|
3554806741 | ||
|
|
e4cc308d43 | ||
|
|
78271a9ed4 | ||
|
|
8f67188c19 | ||
|
|
c432b27c92 | ||
|
|
30a3bbb198 | ||
|
|
e7f9358f96 | ||
|
|
750c7773ae | ||
|
|
900277f426 | ||
|
|
208adeef6c | ||
|
|
086828b12f | ||
|
|
c73d556e6f | ||
|
|
357e2f60f2 | ||
|
|
243ba70b33 | ||
|
|
640da07089 | ||
|
|
69c38774fe | ||
|
|
44527850f6 | ||
|
|
8d96b2c31f | ||
|
|
0019e8c61c | ||
|
|
545f5fc3e9 | ||
|
|
5108de20c3 | ||
|
|
9656be1dde | ||
|
|
09890e8048 | ||
|
|
b672b4c526 | ||
|
|
6ca49327c3 | ||
|
|
3d47cc44af | ||
|
|
e8b471ac97 | ||
|
|
0e6915b860 | ||
|
|
0d48e517f8 | ||
|
|
f2469ecaaf | ||
|
|
c8451c7d3f | ||
|
|
d3025a34ca | ||
|
|
17426583e0 | ||
|
|
04c4a4c059 | ||
|
|
6ae0aaa6f9 | ||
|
|
d22361f2ac | ||
|
|
e21e608cca | ||
|
|
238658cf69 | ||
|
|
2a361d86e0 | ||
|
|
294fb3d4ce | ||
|
|
342da7e250 | ||
|
|
9c52108035 | ||
|
|
5b954b93e3 | ||
|
|
b596e063f5 | ||
|
|
965b35b78c | ||
|
|
9551b3acb4 | ||
|
|
27ac1c7782 | ||
|
|
f9d0b69bce | ||
|
|
a91ce82d77 | ||
|
|
d8b5d8163b | ||
|
|
6fca06d341 | ||
|
|
44080829e3 | ||
|
|
651e028d5b | ||
|
|
6f3186df2f | ||
|
|
92c61f928e | ||
|
|
d3cb45f879 | ||
|
|
314e2932fb | ||
|
|
8ee5165ccf | ||
|
|
8f2a9e6703 | ||
|
|
f8a6fb9ce2 | ||
|
|
bf248cd645 | ||
|
|
1563814cb0 | ||
|
|
91770998a7 | ||
|
|
d7aca1025f | ||
|
|
b3298d18c8 | ||
|
|
359147e7e8 | ||
|
|
937f1912d7 | ||
|
|
18c0e32309 | ||
|
|
1518cb1155 | ||
|
|
c5b7dd2918 | ||
|
|
b668b7eda2 | ||
|
|
a595ead2c6 | ||
|
|
cc1ee544c3 | ||
|
|
a0862936e8 | ||
|
|
f91f5743b6 | ||
|
|
eb74b90b42 | ||
|
|
c3c108bd50 | ||
|
|
06975f79f5 | ||
|
|
830106a168 | ||
|
|
aa2dfcc42f | ||
|
|
ed71fd6227 | ||
|
|
fd60528567 | ||
|
|
01934d5b00 | ||
|
|
bba0e3ed7d | ||
|
|
7db0b13d30 | ||
|
|
b1c6c8f835 | ||
|
|
7620f40cb2 | ||
|
|
cf9058be04 | ||
|
|
234532ebef | ||
|
|
ccddbb1316 | ||
|
|
4ef315d4e2 | ||
|
|
9b7fe331f6 | ||
|
|
eeff0b40fb | ||
|
|
0c933c0085 | ||
|
|
a3d94fcca6 | ||
|
|
9fe1d190da | ||
|
|
73981c2e75 | ||
|
|
107dec388e | ||
|
|
1df44aea40 | ||
|
|
3bc623be7c | ||
|
|
123e6cf82d | ||
|
|
5e9d134021 | ||
|
|
0a022fddcc | ||
|
|
f18a4dc16f | ||
|
|
9ac754fd40 | ||
|
|
2667053fde | ||
|
|
8874994feb | ||
|
|
5a8b92f556 | ||
|
|
a65c2e6a1f | ||
|
|
2d0304feb1 | ||
|
|
34fec63234 | ||
|
|
1d5f27f567 | ||
|
|
093db8bdac | ||
|
|
04602efd6e | ||
|
|
3265de0c1d | ||
|
|
e4a428e0c5 | ||
|
|
6cc28450a4 | ||
|
|
a0c7fbacb7 | ||
|
|
b750094934 | ||
|
|
d953a964cd | ||
|
|
aa95ffac82 | ||
|
|
9c345828b0 | ||
|
|
59c137c653 | ||
|
|
3d405542af | ||
|
|
88ff4b85ce | ||
|
|
461ac5f226 | ||
|
|
a7d2d0a3f3 | ||
|
|
191ce11d8e | ||
|
|
0d28a3ef9b | ||
|
|
ac34249afe | ||
|
|
d1f87be435 | ||
|
|
cbb6117d69 | ||
|
|
334a1db262 | ||
|
|
e3bee69b27 | ||
|
|
0ff5325e3e | ||
|
|
40efb2f58a | ||
|
|
4b20c7224e | ||
|
|
8e06beced6 | ||
|
|
b043f2a5ed | ||
|
|
3d59bc7a97 | ||
|
|
75dcad8ea4 | ||
|
|
4b38eb848f | ||
|
|
bfce04e63c | ||
|
|
846c5c202b | ||
|
|
600811ff01 | ||
|
|
26ce289e9b | ||
|
|
10a9c0f482 | ||
|
|
498ffa27f9 | ||
|
|
ce8b46f300 | ||
|
|
995eff975f | ||
|
|
2ab35e91e2 | ||
|
|
4867ac2c7c | ||
|
|
a68149a87b | ||
|
|
8be3cdb6a0 | ||
|
|
99760c27af | ||
|
|
4aa76ce444 | ||
|
|
82ae128429 | ||
|
|
92dc611bb1 | ||
|
|
dbf333c971 | ||
|
|
ca5dc3a4cc | ||
|
|
a267a9c0b8 | ||
|
|
21cbb2c697 | ||
|
|
00f49be42c | ||
|
|
37b55bf934 | ||
|
|
f2aca02b82 | ||
|
|
dd101259f0 | ||
|
|
b1f2742422 | ||
|
|
114b44d4b6 | ||
|
|
e07f3f0658 | ||
|
|
b21aef09be | ||
|
|
d964e65a7e | ||
|
|
024856e538 | ||
|
|
e530df7239 | ||
|
|
e817c816c9 | ||
|
|
14f0f8c121 | ||
|
|
4c97948e04 | ||
|
|
360e8185f7 | ||
|
|
da0958d455 | ||
|
|
70f5d24e0a | ||
|
|
6b281ef001 | ||
|
|
3ddd3207b3 | ||
|
|
8e58a3f5e2 | ||
|
|
a95c4b2446 | ||
|
|
97fe1686f5 | ||
|
|
76fcf5d0b7 | ||
|
|
bf1fc58e10 | ||
|
|
3559d825ca | ||
|
|
2d54086d89 | ||
|
|
c31c67a3eb | ||
|
|
e924cbefda | ||
|
|
6867ef78dc | ||
|
|
a76d09d3f6 | ||
|
|
b93eea0e24 | ||
|
|
7332aa4acd | ||
|
|
49e4d2844b | ||
|
|
236373b7d7 | ||
|
|
21a9e4312d | ||
|
|
628d9bc0c1 | ||
|
|
caf5ca04f5 | ||
|
|
7cbbf2bdd7 | ||
|
|
9d6e77fd5a | ||
|
|
e7d251f8a1 | ||
|
|
af950d042a | ||
|
|
23ae908e7d | ||
|
|
38ffaca8cc | ||
|
|
b0bde0eb44 | ||
|
|
763cf8aa0a | ||
|
|
9f0d3e0f3c | ||
|
|
937bb65a14 | ||
|
|
376fd88fc9 | ||
|
|
fca23274bf | ||
|
|
27d038512c | ||
|
|
d8291edae0 | ||
|
|
e6c0ac91cd | ||
|
|
74713f8b7c | ||
|
|
38a43ba7ff | ||
|
|
ca832a38e2 | ||
|
|
54b2b9b339 | ||
|
|
fede78c337 | ||
|
|
8a41dca46d | ||
|
|
d084128297 | ||
|
|
a141f9cbbd | ||
|
|
e415da13e4 | ||
|
|
10d65abf47 | ||
|
|
a03e580b36 | ||
|
|
79e982d198 | ||
|
|
453bd8fc04 | ||
|
|
9ced2921d9 | ||
|
|
fa99a89bbf | ||
|
|
f1a02b8afa | ||
|
|
6e4e60fc64 | ||
|
|
4f5e77d189 | ||
|
|
4fa7ce416b | ||
|
|
4d9f75b7b0 | ||
|
|
bfd83f2e87 | ||
|
|
f0c947a50b | ||
|
|
e19617be2f | ||
|
|
54697866f5 | ||
|
|
8c1f0bd05c | ||
|
|
c3999f92b1 | ||
|
|
c3f6bef152 | ||
|
|
c870bfe442 | ||
|
|
06846afa77 | ||
|
|
944988cb63 | ||
|
|
6cd51597a3 | ||
|
|
6209080e0c | ||
|
|
4a7e369c36 | ||
|
|
984da79210 | ||
|
|
38b40c0f50 | ||
|
|
d0097eb5b6 | ||
|
|
71303376ee | ||
|
|
8dbd5a9b21 | ||
|
|
f82dc905a2 | ||
|
|
bfbabc05d5 | ||
|
|
58767454b3 | ||
|
|
4776651b27 | ||
|
|
832eade857 | ||
|
|
44ff9a8b4b | ||
|
|
3f26a74c71 | ||
|
|
1041cb5160 | ||
|
|
04e7df1283 | ||
|
|
fd5d92eb12 | ||
|
|
46d2c72776 | ||
|
|
03f8765279 | ||
|
|
9f027ad164 | ||
|
|
68bd47126a | ||
|
|
f9c351f941 | ||
|
|
0440cd672d | ||
|
|
cb5a71213f |
7
.gitignore
vendored
7
.gitignore
vendored
@@ -39,3 +39,10 @@ pkg
|
|||||||
#
|
#
|
||||||
# For vim:
|
# For vim:
|
||||||
*.swp
|
*.swp
|
||||||
|
#
|
||||||
|
# For IDEA:
|
||||||
|
.idea/
|
||||||
|
*.iml
|
||||||
|
|
||||||
|
Gemfile.lock
|
||||||
|
vendor/
|
||||||
|
|||||||
4
.travis.yml
Normal file
4
.travis.yml
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
language: ruby
|
||||||
|
rvm:
|
||||||
|
- 2.0.0
|
||||||
|
- 1.9.3
|
||||||
@@ -1,3 +1,60 @@
|
|||||||
|
#1.0.0
|
||||||
|
* Removed support for Ruby 1.8.7
|
||||||
|
* Added a version command
|
||||||
|
|
||||||
|
# 0.9.8
|
||||||
|
* Introduce new commands
|
||||||
|
* `homesick cd`
|
||||||
|
* `homesick open`
|
||||||
|
|
||||||
|
# 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
|
||||||
|
* 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)
|
||||||
|
|||||||
30
Gemfile
30
Gemfile
@@ -1,16 +1,26 @@
|
|||||||
|
require 'rbconfig'
|
||||||
|
source 'https://rubygems.org'
|
||||||
|
|
||||||
# Add dependencies required to use your gem here.
|
# Add dependencies required to use your gem here.
|
||||||
group :runtime do
|
gem "thor", ">= 0.14.0"
|
||||||
#gem 'bundler', '>= 0.9.5'
|
|
||||||
gem "thor", ">= 0.13.6"
|
|
||||||
end
|
|
||||||
|
|
||||||
# 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", ">= 1.2.9"
|
gem "rspec", "~> 2.10"
|
||||||
gem "bundler", ">= 0.9.5"
|
gem "guard"
|
||||||
gem "jeweler", ">= 1.4.0"
|
gem "guard-rspec"
|
||||||
gem "rcov", ">= 0"
|
gem "rb-readline", "~> 0.5.0"
|
||||||
gem "test-construct"
|
gem "jeweler", ">= 1.6.2"
|
||||||
|
gem "rcov", :platforms => :mri_18
|
||||||
|
gem "simplecov", :platforms => :mri_19
|
||||||
|
gem "test_construct"
|
||||||
|
gem "capture-output", "~> 1.0.0"
|
||||||
|
if RbConfig::CONFIG['host_os'] =~ /linux|freebsd|openbsd|sunos|solaris/
|
||||||
|
gem 'libnotify'
|
||||||
|
end
|
||||||
|
if RUBY_VERSION >= '1.9.2'
|
||||||
|
gem "rubocop"
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
6
Guardfile
Normal file
6
Guardfile
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
guard :rspec, :cmd => 'bundle exec rspec' do
|
||||||
|
watch(%r{^spec/.+_spec\.rb$})
|
||||||
|
watch(%r{^lib/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" }
|
||||||
|
watch(%r{^lib/homesick/.*\.rb}) { "spec" }
|
||||||
|
watch('spec/spec_helper.rb') { "spec" }
|
||||||
|
end
|
||||||
130
README.markdown
130
README.markdown
@@ -1,6 +1,11 @@
|
|||||||
# homesick
|
# homesick
|
||||||
|
|
||||||
A man's home (directory) is his castle, so don't leave home with out it.
|
[](http://badge.fury.io/rb/homesick)
|
||||||
|
[](https://travis-ci.org/technicalpickles/homesick)
|
||||||
|
[](https://gemnasium.com/technicalpickles/homesick)
|
||||||
|
[](https://codeclimate.com/github/technicalpickles/homesick)
|
||||||
|
|
||||||
|
Your home directory is your castle. Don't leave your dotfiles behind.
|
||||||
|
|
||||||
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,18 +30,133 @@ 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:
|
You can remove symlinks anytime when you don't need them anymore
|
||||||
|
|
||||||
homesick symlink technicalpickles/pickled-vim
|
homesick unlink pickled-vim
|
||||||
|
|
||||||
|
If you need to add further configuration steps you can add these in a file called '.homesickrc' in the root of a castle. Once you've cloned a castle with a .homesickrc run the configuration with:
|
||||||
|
|
||||||
|
homesick rc CASTLE
|
||||||
|
|
||||||
|
The contents of the .homesickrc file must be valid Ruby code as the file will be executed with Ruby's eval construct. The .homesickrc is also passed the current homesick object during its execution and this is available within the .homesickrc file as the 'self' variable.
|
||||||
|
|
||||||
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
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
To open a terminal in the root of a castle:
|
||||||
|
|
||||||
|
homesick cd CASTLE
|
||||||
|
|
||||||
|
To open your default editor in the root of a castle (the $EDITOR environment variable must be set):
|
||||||
|
|
||||||
|
homesick open 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
|
||||||
|
|
||||||
|
If you ever want to see what version of homesick you have type:
|
||||||
|
|
||||||
|
homesick version|-v|--version
|
||||||
|
|
||||||
|
## .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
|
||||||
|
|
||||||
|
## Supported Ruby Versions
|
||||||
|
|
||||||
|
Homesick is tested on the following Ruby versions:
|
||||||
|
|
||||||
|
* 1.9.3
|
||||||
|
* 2.0.0
|
||||||
|
|
||||||
## Note on Patches/Pull Requests
|
## Note on Patches/Pull Requests
|
||||||
|
|
||||||
* Fork the project.
|
* Fork the project.
|
||||||
@@ -45,6 +165,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.
|
||||||
|
|||||||
40
Rakefile
40
Rakefile
@@ -1,7 +1,8 @@
|
|||||||
require 'rubygems'
|
require 'rubygems'
|
||||||
require 'bundler'
|
require 'bundler'
|
||||||
|
require_relative 'lib/homesick/version'
|
||||||
begin
|
begin
|
||||||
Bundler.setup(:runtime, :development)
|
Bundler.setup(:default, :development)
|
||||||
rescue Bundler::BundlerError => e
|
rescue Bundler::BundlerError => e
|
||||||
$stderr.puts e.message
|
$stderr.puts e.message
|
||||||
$stderr.puts "Run `bundle install` to install missing gems"
|
$stderr.puts "Run `bundle install` to install missing gems"
|
||||||
@@ -12,17 +13,19 @@ require 'rake'
|
|||||||
require 'jeweler'
|
require 'jeweler'
|
||||||
Jeweler::Tasks.new do |gem|
|
Jeweler::Tasks.new do |gem|
|
||||||
gem.name = "homesick"
|
gem.name = "homesick"
|
||||||
gem.summary = %Q{A man's home is his castle. Never leave your dotfiles behind.}
|
gem.summary = %Q{Your home directory is your castle. Don't leave your dotfiles behind.}
|
||||||
gem.description = %Q{
|
gem.description = %Q{
|
||||||
A man’s home (directory) is his castle, so don’t leave home with out it.
|
Your home directory is your castle. Don't leave your dotfiles behind.
|
||||||
|
|
||||||
|
|
||||||
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.5.2"
|
gem.version = Homesick::Version::STRING
|
||||||
|
gem.license = "MIT"
|
||||||
# Have dependencies? Add them to Gemfile
|
# Have dependencies? Add them to Gemfile
|
||||||
|
|
||||||
# gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
|
# gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
|
||||||
@@ -30,21 +33,30 @@ end
|
|||||||
Jeweler::GemcutterTasks.new
|
Jeweler::GemcutterTasks.new
|
||||||
|
|
||||||
|
|
||||||
require 'spec/rake/spectask'
|
require 'rspec/core/rake_task'
|
||||||
Spec::Rake::SpecTask.new(:spec) do |spec|
|
RSpec::Core::RakeTask.new(:spec) do |spec|
|
||||||
spec.libs << 'lib' << 'spec'
|
spec.pattern = FileList['spec/**/*_spec.rb']
|
||||||
spec.spec_files = FileList['spec/**/*_spec.rb']
|
|
||||||
end
|
end
|
||||||
|
|
||||||
Spec::Rake::SpecTask.new(:rcov) do |spec|
|
RSpec::Core::RakeTask.new(:rcov) do |spec|
|
||||||
spec.libs << 'lib' << 'spec'
|
|
||||||
spec.pattern = 'spec/**/*_spec.rb'
|
spec.pattern = 'spec/**/*_spec.rb'
|
||||||
spec.rcov = true
|
spec.rcov = true
|
||||||
end
|
end
|
||||||
|
|
||||||
task :default => :spec
|
task :rubocop do
|
||||||
|
if RUBY_VERSION >= '1.9.2'
|
||||||
|
system('rubocop')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
require 'rake/rdoctask'
|
task :test do
|
||||||
|
Rake::Task['spec'].execute
|
||||||
|
Rake::Task['rubocop'].execute
|
||||||
|
end
|
||||||
|
|
||||||
|
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') : ""
|
||||||
|
|
||||||
|
|||||||
@@ -1,23 +1,18 @@
|
|||||||
# 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 -*-
|
||||||
|
# stub: homesick 1.0.0 ruby lib
|
||||||
|
|
||||||
Gem::Specification.new do |s|
|
Gem::Specification.new do |s|
|
||||||
s.name = %q{homesick}
|
s.name = "homesick"
|
||||||
s.version = "0.5.2"
|
s.version = "1.0.0"
|
||||||
|
|
||||||
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 = ["Joshua Nichols", "Yusuke Murata"]
|
||||||
s.date = %q{2010-07-22}
|
s.date = "2014-01-16"
|
||||||
s.default_executable = %q{homesick}
|
s.description = "\n Your home directory is your castle. Don't leave your dotfiles behind.\n \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 = %q{
|
s.email = ["josh@technicalpickles.com", "info@muratayusuke.com"]
|
||||||
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.
|
|
||||||
|
|
||||||
}
|
|
||||||
s.email = %q{josh@technicalpickles.com}
|
|
||||||
s.executables = ["homesick"]
|
s.executables = ["homesick"]
|
||||||
s.extra_rdoc_files = [
|
s.extra_rdoc_files = [
|
||||||
"ChangeLog.markdown",
|
"ChangeLog.markdown",
|
||||||
@@ -26,9 +21,11 @@ Gem::Specification.new do |s|
|
|||||||
]
|
]
|
||||||
s.files = [
|
s.files = [
|
||||||
".document",
|
".document",
|
||||||
".gitignore",
|
".rspec",
|
||||||
|
".travis.yml",
|
||||||
"ChangeLog.markdown",
|
"ChangeLog.markdown",
|
||||||
"Gemfile",
|
"Gemfile",
|
||||||
|
"Guardfile",
|
||||||
"LICENSE",
|
"LICENSE",
|
||||||
"README.markdown",
|
"README.markdown",
|
||||||
"Rakefile",
|
"Rakefile",
|
||||||
@@ -37,28 +34,63 @@ Gem::Specification.new do |s|
|
|||||||
"lib/homesick.rb",
|
"lib/homesick.rb",
|
||||||
"lib/homesick/actions.rb",
|
"lib/homesick/actions.rb",
|
||||||
"lib/homesick/shell.rb",
|
"lib/homesick/shell.rb",
|
||||||
|
"lib/homesick/version.rb",
|
||||||
"spec/homesick_spec.rb",
|
"spec/homesick_spec.rb",
|
||||||
"spec/spec.opts",
|
"spec/spec.opts",
|
||||||
"spec/spec_helper.rb"
|
"spec/spec_helper.rb"
|
||||||
]
|
]
|
||||||
s.homepage = %q{http://github.com/technicalpickles/homesick}
|
s.homepage = "http://github.com/technicalpickles/homesick"
|
||||||
s.rdoc_options = ["--charset=UTF-8"]
|
s.licenses = ["MIT"]
|
||||||
s.require_paths = ["lib"]
|
s.require_paths = ["lib"]
|
||||||
s.rubygems_version = %q{1.3.6}
|
s.rubygems_version = "2.1.11"
|
||||||
s.summary = %q{A man's home is his castle. Never leave your dotfiles behind.}
|
s.summary = "Your home directory is your castle. Don't 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 = 4
|
||||||
s.specification_version = 3
|
|
||||||
|
|
||||||
if Gem::Version.new(Gem::RubyGemsVersion) >= 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_development_dependency(%q<rake>, [">= 0.8.7"])
|
||||||
|
s.add_development_dependency(%q<rspec>, ["~> 2.10"])
|
||||||
|
s.add_development_dependency(%q<guard>, [">= 0"])
|
||||||
|
s.add_development_dependency(%q<guard-rspec>, [">= 0"])
|
||||||
|
s.add_development_dependency(%q<rb-readline>, ["~> 0.5.0"])
|
||||||
|
s.add_development_dependency(%q<jeweler>, [">= 1.6.2"])
|
||||||
|
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<capture-output>, ["~> 1.0.0"])
|
||||||
|
s.add_development_dependency(%q<libnotify>, [">= 0"])
|
||||||
|
s.add_development_dependency(%q<rubocop>, [">= 0"])
|
||||||
else
|
else
|
||||||
|
s.add_dependency(%q<thor>, [">= 0.14.0"])
|
||||||
|
s.add_dependency(%q<rake>, [">= 0.8.7"])
|
||||||
|
s.add_dependency(%q<rspec>, ["~> 2.10"])
|
||||||
|
s.add_dependency(%q<guard>, [">= 0"])
|
||||||
|
s.add_dependency(%q<guard-rspec>, [">= 0"])
|
||||||
|
s.add_dependency(%q<rb-readline>, ["~> 0.5.0"])
|
||||||
|
s.add_dependency(%q<jeweler>, [">= 1.6.2"])
|
||||||
|
s.add_dependency(%q<rcov>, [">= 0"])
|
||||||
|
s.add_dependency(%q<simplecov>, [">= 0"])
|
||||||
|
s.add_dependency(%q<test_construct>, [">= 0"])
|
||||||
|
s.add_dependency(%q<capture-output>, ["~> 1.0.0"])
|
||||||
|
s.add_dependency(%q<libnotify>, [">= 0"])
|
||||||
|
s.add_dependency(%q<rubocop>, [">= 0"])
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
|
s.add_dependency(%q<thor>, [">= 0.14.0"])
|
||||||
|
s.add_dependency(%q<rake>, [">= 0.8.7"])
|
||||||
|
s.add_dependency(%q<rspec>, ["~> 2.10"])
|
||||||
|
s.add_dependency(%q<guard>, [">= 0"])
|
||||||
|
s.add_dependency(%q<guard-rspec>, [">= 0"])
|
||||||
|
s.add_dependency(%q<rb-readline>, ["~> 0.5.0"])
|
||||||
|
s.add_dependency(%q<jeweler>, [">= 1.6.2"])
|
||||||
|
s.add_dependency(%q<rcov>, [">= 0"])
|
||||||
|
s.add_dependency(%q<simplecov>, [">= 0"])
|
||||||
|
s.add_dependency(%q<test_construct>, [">= 0"])
|
||||||
|
s.add_dependency(%q<capture-output>, ["~> 1.0.0"])
|
||||||
|
s.add_dependency(%q<libnotify>, [">= 0"])
|
||||||
|
s.add_dependency(%q<rubocop>, [">= 0"])
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
402
lib/homesick.rb
402
lib/homesick.rb
@@ -1,38 +1,54 @@
|
|||||||
|
# -*- encoding : utf-8 -*-
|
||||||
require 'thor'
|
require 'thor'
|
||||||
|
|
||||||
class Homesick < Thor
|
class Homesick < Thor
|
||||||
autoload :Shell, 'homesick/shell'
|
autoload :Shell, 'homesick/shell'
|
||||||
autoload :Actions, 'homesick/actions'
|
autoload :Actions, 'homesick/actions'
|
||||||
|
autoload :Version, 'homesick/version'
|
||||||
|
|
||||||
include Thor::Actions
|
include Thor::Actions
|
||||||
include Homesick::Actions
|
include Homesick::Actions
|
||||||
|
include Homesick::Version
|
||||||
|
|
||||||
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'
|
||||||
|
|
||||||
def initialize(args=[], options={}, config={})
|
DEFAULT_CASTLE_NAME = 'dotfiles'
|
||||||
|
|
||||||
|
map '-v' => :version
|
||||||
|
map '--version' => :version
|
||||||
|
|
||||||
|
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(uri).basename
|
||||||
|
git_clone "https://github.com/#{$1}.git", :destination => destination
|
||||||
|
elsif uri =~ /%r([^%r]*?)(\.git)?\Z/
|
||||||
destination = Pathname.new($1)
|
destination = Pathname.new($1)
|
||||||
git_clone "git://github.com/#{$1}.git", :destination => destination
|
|
||||||
else
|
|
||||||
if uri =~ /\/([^\/]*).git\Z/
|
|
||||||
destination = Pathname.new($1)
|
|
||||||
end
|
|
||||||
|
|
||||||
git_clone uri
|
git_clone uri
|
||||||
|
elsif uri =~ /[^:]+:([^:]+)(\.git)?\Z/
|
||||||
|
destination = Pathname.new($1)
|
||||||
|
git_clone uri
|
||||||
|
else
|
||||||
|
raise "Unknown URI format: #{uri}"
|
||||||
end
|
end
|
||||||
|
|
||||||
if destination.join('.gitmodules').exist?
|
if destination.join('.gitmodules').exist?
|
||||||
@@ -41,58 +57,170 @@ class Homesick < Thor
|
|||||||
git_submodule_update
|
git_submodule_update
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
rc(destination)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
desc "pull NAME", "Update the specified castle"
|
desc 'rc CASTLE', 'Run the .homesickrc for the specified castle'
|
||||||
def pull(name)
|
def rc(name = DEFAULT_CASTLE_NAME)
|
||||||
check_castle_existance(name, "pull")
|
inside repos_dir do
|
||||||
|
destination = Pathname.new(name)
|
||||||
inside repos_dir.join(name) do
|
homesickrc = destination.join('.homesickrc').expand_path
|
||||||
git_pull
|
if homesickrc.exist?
|
||||||
git_submodule_init
|
proceed = shell.yes?("#{name} has a .homesickrc. Proceed with evaling it? (This could be destructive)")
|
||||||
git_submodule_update
|
if proceed
|
||||||
|
shell.say_status 'eval', homesickrc
|
||||||
|
inside destination do
|
||||||
|
eval homesickrc.read, binding, homesickrc.expand_path.to_s
|
||||||
|
end
|
||||||
|
else
|
||||||
|
shell.say_status 'eval skip', "not evaling #{homesickrc}, #{destination} may need manual configuration", :blue
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
desc "symlink NAME", "Symlinks all dotfiles from the specified castle"
|
desc 'pull CASTLE', 'Update the specified castle'
|
||||||
def symlink(name)
|
method_option :all, :type => :boolean, :default => false, :required => false, :desc => 'Update all cloned castles'
|
||||||
check_castle_existance(name, "symlink")
|
def pull(name = DEFAULT_CASTLE_NAME)
|
||||||
|
if options[:all]
|
||||||
|
inside_each_castle do |castle|
|
||||||
|
shell.say castle.to_s.gsub(repos_dir.to_s + '/', '') + ':'
|
||||||
|
update_castle castle
|
||||||
|
end
|
||||||
|
else
|
||||||
|
update_castle name
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
desc 'commit CASTLE MESSAGE', "Commit the specified castle's changes"
|
||||||
|
def commit(name = DEFAULT_CASTLE_NAME, message = nil)
|
||||||
|
commit_castle name, message
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
desc 'push CASTLE', 'Push the specified castle'
|
||||||
|
def push(name = DEFAULT_CASTLE_NAME)
|
||||||
|
push_castle name
|
||||||
|
end
|
||||||
|
|
||||||
|
desc 'unlink CASTLE', 'Unsymlinks all dotfiles from the specified castle'
|
||||||
|
def unlink(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
|
# unlink files
|
||||||
|
unsymlink_each(name, castle_dir(name), subdirs)
|
||||||
|
|
||||||
|
# unlink files in subdirs
|
||||||
|
subdirs.each do |subdir|
|
||||||
|
unsymlink_each(name, subdir, subdirs)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
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
|
||||||
|
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)
|
||||||
|
file = Pathname.new(file.chomp('/'))
|
||||||
|
check_castle_existance(castle, 'track')
|
||||||
|
|
||||||
|
absolute_path = file.expand_path
|
||||||
|
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
|
||||||
|
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
|
||||||
adjusted_path = (home_dir + path).basename
|
absolute_path = castle_path + file.basename
|
||||||
|
home_path = home_dir + relative_dir + file.basename
|
||||||
ln_s absolute_path, adjusted_path
|
ln_s absolute_path, home_path
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
desc "list", "List cloned castles"
|
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
|
||||||
|
|
||||||
|
desc 'list', 'List cloned castles'
|
||||||
def list
|
def list
|
||||||
#require 'ruby-debug'; breakpoint
|
inside_each_castle do |castle|
|
||||||
Pathname.glob("#{repos_dir}/**/*/.git") do |git_dir|
|
say_status castle.relative_path_from(repos_dir).to_s, `git config remote.origin.url`.chomp, :cyan
|
||||||
castle = git_dir.dirname
|
|
||||||
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
|
||||||
inside castle do
|
inside castle do
|
||||||
git_init
|
git_init
|
||||||
@@ -101,10 +229,51 @@ 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
|
||||||
|
|
||||||
|
desc "destroy CASTLE", "Delete all symlinks and remove the cloned repository"
|
||||||
|
def destroy(name)
|
||||||
|
check_castle_existance name, "destroy"
|
||||||
|
|
||||||
|
if shell.yes?("This will destroy your castle irreversible! Are you sure?")
|
||||||
|
unlink(name)
|
||||||
|
rm_rf repos_dir.join(name)
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
desc "cd CASTLE", "Open a new shell in the root of the given castle"
|
||||||
|
def cd(castle = DEFAULT_CASTLE_NAME)
|
||||||
|
check_castle_existance castle, "cd"
|
||||||
|
castle_dir = repos_dir.join(castle)
|
||||||
|
say_status "cd #{castle_dir.realpath}", "Opening a new shell in castle '#{castle}'. To return to the original one exit from the new shell.", :green
|
||||||
|
inside castle_dir do
|
||||||
|
system(ENV['SHELL'])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
desc "open CASTLE", "Open your default editor in the root of the given castle"
|
||||||
|
def open(castle = DEFAULT_CASTLE_NAME)
|
||||||
|
if ! ENV['EDITOR']
|
||||||
|
say_status :error,"The $EDITOR environment variable must be set to use this command", :red
|
||||||
|
|
||||||
|
exit(1)
|
||||||
|
end
|
||||||
|
check_castle_existance castle, "open"
|
||||||
|
castle_dir = repos_dir.join(castle)
|
||||||
|
say_status "#{ENV['EDITOR']} #{castle_dir.realpath}", "Opening the root directory of castle '#{castle}' in editor '#{ENV['EDITOR']}'.", :green
|
||||||
|
inside castle_dir do
|
||||||
|
system(ENV['EDITOR'])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
desc 'version', 'Display the current version of homesick'
|
||||||
|
def version
|
||||||
|
say Homesick::Version::STRING
|
||||||
|
end
|
||||||
|
|
||||||
protected
|
protected
|
||||||
|
|
||||||
def home_dir
|
def home_dir
|
||||||
@@ -127,4 +296,155 @@ 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, message)
|
||||||
|
check_castle_existance(castle, 'commit')
|
||||||
|
inside repos_dir.join(castle) do
|
||||||
|
git_commit_all :message => message
|
||||||
|
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 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
|
||||||
|
|||||||
@@ -1,31 +1,29 @@
|
|||||||
|
# -*- encoding : utf-8 -*-
|
||||||
class Homesick
|
class Homesick
|
||||||
module Actions
|
module Actions
|
||||||
# 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 --config push.default=upstream --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 +34,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,22 +44,110 @@ 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]
|
||||||
|
if config[:message]
|
||||||
|
system "git commit -a -m '#{config[:message]}'" unless options[:pretend]
|
||||||
|
else
|
||||||
|
system 'git commit -v -a' unless options[:pretend]
|
||||||
|
end
|
||||||
|
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
|
||||||
|
|
||||||
|
def mv(source, destination, config = {})
|
||||||
|
source = Pathname.new(source)
|
||||||
|
destination = Pathname.new(destination + source.basename)
|
||||||
|
|
||||||
|
if destination.exist?
|
||||||
|
say_status :conflict, "#{destination} exists", :red unless options[:quiet]
|
||||||
|
|
||||||
|
if options[:force] || shell.file_collision(destination) { source }
|
||||||
|
system "mv '#{source}' '#{destination}'" unless options[:pretend]
|
||||||
|
end
|
||||||
|
else
|
||||||
|
# this needs some sort of message here.
|
||||||
|
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
|
||||||
|
|
||||||
|
def rm(file)
|
||||||
|
say_status "rm #{file}", '', :green unless options[:quiet]
|
||||||
|
system "rm #{file}" if File.exists?(file)
|
||||||
|
end
|
||||||
|
|
||||||
|
def rm_rf(dir)
|
||||||
|
say_status "rm -rf #{dir}", '', :green unless options[:quiet]
|
||||||
|
system "rm -rf #{dir}"
|
||||||
|
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
|
||||||
|
|
||||||
|
def rm(file)
|
||||||
|
say_status "rm #{file}", '', :green unless options[:quiet]
|
||||||
|
system "rm #{file}"
|
||||||
|
end
|
||||||
|
|
||||||
|
def rm_r(dir)
|
||||||
|
say_status "rm -r #{dir}", '', :green unless options[:quiet]
|
||||||
|
system "rm -r #{dir}"
|
||||||
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
|
||||||
@@ -69,19 +155,20 @@ class Homesick
|
|||||||
else
|
else
|
||||||
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 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 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
|
||||||
|
|||||||
10
lib/homesick/version.rb
Normal file
10
lib/homesick/version.rb
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
# -*- encoding : utf-8 -*-
|
||||||
|
class Homesick
|
||||||
|
module Version
|
||||||
|
MAJOR = 1
|
||||||
|
MINOR = 0
|
||||||
|
PATCH = 0
|
||||||
|
|
||||||
|
STRING = "#{MAJOR}.#{MINOR}.#{PATCH}"
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -1,71 +1,621 @@
|
|||||||
|
# -*- encoding : utf-8 -*-
|
||||||
require 'spec_helper'
|
require 'spec_helper'
|
||||||
|
require 'capture-output'
|
||||||
|
|
||||||
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
|
|
||||||
|
let(:homesick) { Homesick.new }
|
||||||
|
|
||||||
|
before { homesick.stub(:repos_dir).and_return(castles) }
|
||||||
|
|
||||||
|
describe 'clone' do
|
||||||
|
context 'has a .homesickrc' do
|
||||||
|
it 'should run the .homesickrc' do
|
||||||
somewhere = create_construct
|
somewhere = create_construct
|
||||||
somewhere.directory('wtf')
|
local_repo = somewhere.directory('some_repo')
|
||||||
wtf = somewhere + 'wtf'
|
local_repo.file('.homesickrc') do |file|
|
||||||
|
file << "File.open(Dir.pwd + '/testing', 'w') { |f| f.print 'testing' }"
|
||||||
@homesick.should_receive(:ln_s).with(wtf.to_s, wtf.basename)
|
|
||||||
|
|
||||||
@homesick.clone wtf.to_s
|
|
||||||
end
|
end
|
||||||
|
|
||||||
it "should clone git repo like git://host/path/to.git" do
|
expect($stdout).to receive(:print)
|
||||||
@homesick.should_receive(:git_clone).with('git://github.com/technicalpickles/pickled-vim.git')
|
expect($stdin).to receive(:gets).and_return('y')
|
||||||
|
expect_any_instance_of(Thor::Shell::Basic).to receive(:say_status).with('eval', kind_of(Pathname))
|
||||||
|
homesick.clone local_repo
|
||||||
|
|
||||||
@homesick.clone "git://github.com/technicalpickles/pickled-vim.git"
|
castles.join('some_repo').join('testing').should exist
|
||||||
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.clone 'git@github.com:technicalpickles/pickled-vim.git'
|
|
||||||
end
|
|
||||||
|
|
||||||
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.clone 'http://github.com/technicalpickles/pickled-vim.git'
|
|
||||||
end
|
|
||||||
|
|
||||||
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.clone "wfarr/dotfiles"
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "list" do
|
context 'of a file' do
|
||||||
|
it 'should symlink existing directories' do
|
||||||
|
somewhere = create_construct
|
||||||
|
local_repo = somewhere.directory('wtf')
|
||||||
|
|
||||||
# FIXME only passes in isolation. need to setup data a bit better
|
homesick.clone local_repo
|
||||||
xit "should say each castle in the castle directory" do
|
|
||||||
@user_dir.directory '.homesick/repos' do |repos_dir|
|
castles.join('wtf').readlink.should == local_repo
|
||||||
repos_dir.directory 'zomg' do |zomg|
|
|
||||||
Dir.chdir do
|
|
||||||
system "git init >/dev/null 2>&1"
|
|
||||||
system "git remote add origin git://github.com/technicalpickles/zomg.git >/dev/null 2>&1"
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
repos_dir.directory 'wtf/zomg' do |zomg|
|
context 'when it exists in a repo directory' do
|
||||||
Dir.chdir do
|
before do
|
||||||
system "git init >/dev/null 2>&1"
|
existing_castle = given_castle('existing_castle')
|
||||||
system "git remote add origin git://github.com/technicalpickles/zomg.git >/dev/null 2>&1"
|
@existing_dir = existing_castle.parent
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'should raise an error' do
|
||||||
|
homesick.should_not_receive(:git_clone)
|
||||||
|
expect { homesick.clone @existing_dir.to_s }.to raise_error(/already cloned/i)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@homesick.should_receive(:say_status).with("zomg", "git://github.com/technicalpickles/zomg.git", :cyan)
|
it 'should clone git repo like file:///path/to.git' do
|
||||||
@homesick.should_receive(:say_status).with("wtf/zomg", "git://github.com/technicalpickles/zomg.git", :cyan)
|
bare_repo = File.join(create_construct.to_s, 'dotfiles.git')
|
||||||
|
system "git init --bare #{bare_repo} >/dev/null 2>&1"
|
||||||
@homesick.list
|
# Capture stderr to suppress message about cloning an empty repo.
|
||||||
|
Capture.stderr do
|
||||||
|
homesick.clone "file://#{bare_repo}"
|
||||||
|
end
|
||||||
|
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
|
||||||
|
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.clone 'git@github.com:technicalpickles/pickled-vim.git'
|
||||||
|
end
|
||||||
|
|
||||||
|
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.clone 'http://github.com/technicalpickles/pickled-vim.git'
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'should clone git repo like http://host/path/to' do
|
||||||
|
homesick.should_receive(:git_clone).with('http://github.com/technicalpickles/pickled-vim')
|
||||||
|
|
||||||
|
homesick.clone 'http://github.com/technicalpickles/pickled-vim'
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'should clone git repo like host-alias:repos.git' do
|
||||||
|
homesick.should_receive(:git_clone).with('gitolite:pickled-vim.git')
|
||||||
|
|
||||||
|
homesick.clone 'gitolite:pickled-vim.git'
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'should throw an exception when trying to clone a malformed uri like malformed' do
|
||||||
|
homesick.should_not_receive(:git_clone)
|
||||||
|
expect { homesick.clone 'malformed' }.to raise_error
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'should clone a github repo' do
|
||||||
|
homesick.should_receive(:git_clone).with('https://github.com/wfarr/dotfiles.git', :destination => Pathname.new('dotfiles'))
|
||||||
|
|
||||||
|
homesick.clone 'wfarr/dotfiles'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe 'rc' do
|
||||||
|
let(:castle) { given_castle('glencairn') }
|
||||||
|
|
||||||
|
context 'when told to do so' do
|
||||||
|
before do
|
||||||
|
expect($stdout).to receive(:print)
|
||||||
|
expect($stdin).to receive(:gets).and_return('y')
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'executes the .homesickrc' do
|
||||||
|
castle.file('.homesickrc') do |file|
|
||||||
|
file << "File.open(Dir.pwd + '/testing', 'w') { |f| f.print 'testing' }"
|
||||||
|
end
|
||||||
|
|
||||||
|
expect_any_instance_of(Thor::Shell::Basic).to receive(:say_status).with('eval', kind_of(Pathname))
|
||||||
|
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
|
||||||
|
|
||||||
|
expect_any_instance_of(Thor::Shell::Basic).to receive(:say_status).with('eval skip', /not evaling.+/, :blue)
|
||||||
|
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 }
|
||||||
|
|
||||||
|
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 '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('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
|
||||||
|
it 'should say "nothing to commit" when there are no changes' do
|
||||||
|
given_castle('castle_repo')
|
||||||
|
text = Capture.stdout { homesick.status('castle_repo') }
|
||||||
|
text.should =~ /nothing to commit \(create\/copy files and use "git add" to track\)$/
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'should say "Changes to be committed" when there are changes' do
|
||||||
|
given_castle('castle_repo')
|
||||||
|
some_rc_file = home.file '.some_rc_file'
|
||||||
|
homesick.track(some_rc_file.to_s, 'castle_repo')
|
||||||
|
text = Capture.stdout { homesick.status('castle_repo') }
|
||||||
|
text.should =~ /Changes to be committed:.*new file:\s*home\/.some_rc_file/m
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe 'diff' do
|
||||||
|
it 'should output an empty message when there are no changes to commit' do
|
||||||
|
given_castle('castle_repo')
|
||||||
|
some_rc_file = home.file '.some_rc_file'
|
||||||
|
homesick.track(some_rc_file.to_s, 'castle_repo')
|
||||||
|
Capture.stdout { homesick.commit 'castle_repo', 'Adding a file to the test' }
|
||||||
|
text = Capture.stdout { homesick.diff('castle_repo') }
|
||||||
|
text.should eq('')
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'should output a diff message when there are changes to commit' do
|
||||||
|
given_castle('castle_repo')
|
||||||
|
some_rc_file = home.file '.some_rc_file'
|
||||||
|
homesick.track(some_rc_file.to_s, 'castle_repo')
|
||||||
|
Capture.stdout { homesick.commit 'castle_repo', 'Adding a file to the test' }
|
||||||
|
File.open(some_rc_file.to_s, 'w') do |file|
|
||||||
|
file.puts "Some test text"
|
||||||
|
end
|
||||||
|
text = Capture.stdout { homesick.diff('castle_repo') }
|
||||||
|
text.should =~ /diff --git.+Some test text$/m
|
||||||
|
end
|
||||||
|
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
|
||||||
|
it 'should perform a pull, submodule init and update when the given castle exists' do
|
||||||
|
given_castle('castle_repo')
|
||||||
|
homesick.stub(:system).once.with('git pull --quiet')
|
||||||
|
homesick.stub(:system).once.with('git submodule --quiet init')
|
||||||
|
homesick.stub(:system).once.with('git submodule --quiet update --init --recursive >/dev/null 2>&1')
|
||||||
|
homesick.pull 'castle_repo'
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'should print an error message when trying to pull a non-existant castle' do
|
||||||
|
homesick.should_receive("say_status").once.with(:error, /Could not pull castle_repo, expected \/tmp\/construct_container.* exist and contain dotfiles/, :red)
|
||||||
|
expect { homesick.pull "castle_repo" }.to raise_error(SystemExit)
|
||||||
|
end
|
||||||
|
|
||||||
|
describe '--all' do
|
||||||
|
it 'should pull each castle when invoked with --all' do
|
||||||
|
given_castle('castle_repo')
|
||||||
|
given_castle('glencairn')
|
||||||
|
homesick.stub(:system).exactly(2).times.with('git pull --quiet')
|
||||||
|
homesick.stub(:system).exactly(2).times.with('git submodule --quiet init')
|
||||||
|
homesick.stub(:system).exactly(2).times.with('git submodule --quiet update --init --recursive >/dev/null 2>&1')
|
||||||
|
Capture.stdout { Capture.stderr { homesick.invoke 'pull', [], all: true } }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
describe 'push' do
|
||||||
|
it 'should perform a git push on the given castle' do
|
||||||
|
given_castle('castle_repo')
|
||||||
|
homesick.stub(:system).once.with('git push')
|
||||||
|
homesick.push 'castle_repo'
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'should print an error message when trying to push a non-existant castle' do
|
||||||
|
homesick.should_receive("say_status").once.with(:error, /Could not push castle_repo, expected \/tmp\/construct_container.* exist and contain dotfiles/, :red)
|
||||||
|
expect { homesick.push "castle_repo" }.to raise_error(SystemExit)
|
||||||
|
end
|
||||||
|
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 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
|
||||||
|
|
||||||
|
some_rc_file.readlink.should == tracked_file
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe 'commit' do
|
||||||
|
it 'should have a commit message when the commit succeeds' do
|
||||||
|
given_castle('castle_repo')
|
||||||
|
some_rc_file = home.file '.a_random_rc_file'
|
||||||
|
homesick.track(some_rc_file.to_s, 'castle_repo')
|
||||||
|
text = Capture.stdout { homesick.commit('castle_repo', 'Test message') }
|
||||||
|
text.should =~ /^\[master \(root-commit\) \w+\] Test message/
|
||||||
|
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
|
||||||
|
|
||||||
|
describe "destroy" do
|
||||||
|
it "removes the symlink files" do
|
||||||
|
expect_any_instance_of(Thor::Shell::Basic).to receive(:yes?).and_return('y')
|
||||||
|
given_castle("stronghold")
|
||||||
|
some_rc_file = home.file '.some_rc_file'
|
||||||
|
homesick.track(some_rc_file.to_s, "stronghold")
|
||||||
|
homesick.destroy('stronghold')
|
||||||
|
|
||||||
|
some_rc_file.should_not be_exist
|
||||||
|
end
|
||||||
|
|
||||||
|
it "deletes the cloned repository" do
|
||||||
|
expect_any_instance_of(Thor::Shell::Basic).to receive(:yes?).and_return('y')
|
||||||
|
castle = given_castle("stronghold")
|
||||||
|
some_rc_file = home.file '.some_rc_file'
|
||||||
|
homesick.track(some_rc_file.to_s, "stronghold")
|
||||||
|
homesick.destroy('stronghold')
|
||||||
|
|
||||||
|
castle.should_not be_exist
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "cd" do
|
||||||
|
it "cd's to the root directory of the given castle" do
|
||||||
|
given_castle('castle_repo')
|
||||||
|
homesick.should_receive("inside").once.with(kind_of(Pathname)).and_yield
|
||||||
|
homesick.should_receive("system").once.with(ENV["SHELL"])
|
||||||
|
Capture.stdout { homesick.cd 'castle_repo' }
|
||||||
|
end
|
||||||
|
|
||||||
|
it "returns an error message when the given castle does not exist" do
|
||||||
|
homesick.should_receive("say_status").once.with(:error, /Could not cd castle_repo, expected \/tmp\/construct_container.* exist and contain dotfiles/, :red)
|
||||||
|
expect { homesick.cd "castle_repo" }.to raise_error(SystemExit)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "open" do
|
||||||
|
it "opens the system default editor in the root of the given castle" do
|
||||||
|
ENV.stub(:[]).and_call_original # Make sure calls to ENV use default values for most things...
|
||||||
|
ENV.stub(:[]).with('EDITOR').and_return('vim') # Set a default value for 'EDITOR' just in case none is set
|
||||||
|
given_castle 'castle_repo'
|
||||||
|
homesick.should_receive("inside").once.with(kind_of(Pathname)).and_yield
|
||||||
|
homesick.should_receive("system").once.with('vim')
|
||||||
|
Capture.stdout { homesick.open 'castle_repo' }
|
||||||
|
end
|
||||||
|
|
||||||
|
it "returns an error message when the $EDITOR environment variable is not set" do
|
||||||
|
ENV.stub(:[]).with('EDITOR').and_return(nil) # Set the default editor to make sure it fails.
|
||||||
|
homesick.should_receive("say_status").once.with(:error, "The $EDITOR environment variable must be set to use this command", :red)
|
||||||
|
expect { homesick.open "castle_repo" }.to raise_error(SystemExit)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "returns an error message when the given castle does not exist" do
|
||||||
|
ENV.stub(:[]).with('EDITOR').and_return('vim') # Set a default just in case none is set
|
||||||
|
homesick.should_receive("say_status").once.with(:error, /Could not open castle_repo, expected \/tmp\/construct_container.* exist and contain dotfiles/, :red)
|
||||||
|
expect { homesick.open "castle_repo" }.to raise_error(SystemExit)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe 'version' do
|
||||||
|
it 'should print the current version of homesick' do
|
||||||
|
text = Capture.stdout { homesick.version }
|
||||||
|
text.chomp.should =~ /\d+\.\d+\.\d+/
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,19 +1,38 @@
|
|||||||
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
||||||
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
||||||
require 'homesick'
|
require 'homesick'
|
||||||
require 'spec'
|
require 'rspec'
|
||||||
require 'spec/autorun'
|
require 'rspec/autorun'
|
||||||
require 'construct'
|
require 'test_construct'
|
||||||
|
require 'tempfile'
|
||||||
|
|
||||||
Spec::Runner.configure do |config|
|
RSpec.configure do |config|
|
||||||
config.include Construct::Helpers
|
config.include TestConstruct::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 config user.email "test@test.com"'
|
||||||
|
system 'git config user.name "Test Name"'
|
||||||
|
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
|
||||||
|
|||||||
Reference in New Issue
Block a user