homesick 1.0.0 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.rubocop.yml +19 -0
- data/.travis.yml +1 -0
- data/ChangeLog.markdown +4 -0
- data/Gemfile +2 -2
- data/README.markdown +11 -0
- data/bin/homesick +1 -1
- data/homesick.gemspec +14 -16
- data/lib/homesick.rb +9 -444
- data/lib/homesick/actions/file_actions.rb +91 -0
- data/lib/homesick/actions/git_actions.rb +94 -0
- data/lib/homesick/cli.rb +316 -0
- data/lib/homesick/shell.rb +3 -3
- data/lib/homesick/utils.rb +216 -0
- data/lib/homesick/version.rb +5 -3
- data/spec/homesick_cli_spec.rb +787 -0
- data/spec/spec_helper.rb +7 -2
- metadata +37 -61
- data/lib/homesick/actions.rb +0 -175
- data/spec/homesick_spec.rb +0 -621
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: bcecddd4148681735ac7cb0126a5d46ce51274ff
|
4
|
+
data.tar.gz: c4102a683c881383d3836e8604ee21f5780cc996
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0d1ade2b0417f4e5d829a330c1d6e45d2ffd41f16182abc354206365858c9a60b83430acb68c1b4184bf19233fbbb34e6464d58935f6230d3119693a793e94e9
|
7
|
+
data.tar.gz: 07c13eaed62b4f906df29b020c993c6a6809ba1d7eaa613d9c176c7d2c27b0e440d1371a32b315974b4795ba70f49ff83215456cd5c30d1d034b03a610fed6d5
|
data/.rubocop.yml
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
# TODO: Eval is required for the .homesickrc feature. This should eventually be
|
2
|
+
# removed if the feature is implemented in a more secure way.
|
3
|
+
Eval:
|
4
|
+
Enabled: false
|
5
|
+
|
6
|
+
# TODO: The following settings disable reports about issues that can be fixed
|
7
|
+
# through refactoring. Remove these as offenses are removed from the code base.
|
8
|
+
|
9
|
+
ClassLength:
|
10
|
+
Enabled: false
|
11
|
+
|
12
|
+
CyclomaticComplexity:
|
13
|
+
Max: 13
|
14
|
+
|
15
|
+
LineLength:
|
16
|
+
Enabled: false
|
17
|
+
|
18
|
+
MethodLength:
|
19
|
+
Max: 36
|
data/.travis.yml
CHANGED
data/ChangeLog.markdown
CHANGED
data/Gemfile
CHANGED
@@ -13,8 +13,8 @@ group :development do
|
|
13
13
|
gem "guard-rspec"
|
14
14
|
gem "rb-readline", "~> 0.5.0"
|
15
15
|
gem "jeweler", ">= 1.6.2"
|
16
|
-
gem "
|
17
|
-
gem
|
16
|
+
#gem "simplecov"
|
17
|
+
gem 'coveralls', require: false
|
18
18
|
gem "test_construct"
|
19
19
|
gem "capture-output", "~> 1.0.0"
|
20
20
|
if RbConfig::CONFIG['host_os'] =~ /linux|freebsd|openbsd|sunos|solaris/
|
data/README.markdown
CHANGED
@@ -3,7 +3,9 @@
|
|
3
3
|
[](http://badge.fury.io/rb/homesick)
|
4
4
|
[](https://travis-ci.org/technicalpickles/homesick)
|
5
5
|
[](https://gemnasium.com/technicalpickles/homesick)
|
6
|
+
[](https://coveralls.io/r/technicalpickles/homesick)
|
6
7
|
[](https://codeclimate.com/github/technicalpickles/homesick)
|
8
|
+
[](https://gitter.im/technicalpickles/homesick)
|
7
9
|
|
8
10
|
Your home directory is your castle. Don't leave your dotfiles behind.
|
9
11
|
|
@@ -64,6 +66,14 @@ To open your default editor in the root of a castle (the $EDITOR environment var
|
|
64
66
|
|
65
67
|
homesick open CASTLE
|
66
68
|
|
69
|
+
To execute a shell command inside the root directory of a given castle:
|
70
|
+
|
71
|
+
homesick exec CASTLE COMMAND
|
72
|
+
|
73
|
+
To execute a shell command inside the root directory of every cloned castle:
|
74
|
+
|
75
|
+
homesick exec_all COMMAND
|
76
|
+
|
67
77
|
Not sure what else homesick has up its sleeve? There's always the built in help:
|
68
78
|
|
69
79
|
homesick help
|
@@ -156,6 +166,7 @@ Homesick is tested on the following Ruby versions:
|
|
156
166
|
|
157
167
|
* 1.9.3
|
158
168
|
* 2.0.0
|
169
|
+
* 2.1.0
|
159
170
|
|
160
171
|
## Note on Patches/Pull Requests
|
161
172
|
|
data/bin/homesick
CHANGED
data/homesick.gemspec
CHANGED
@@ -2,15 +2,16 @@
|
|
2
2
|
# DO NOT EDIT THIS FILE DIRECTLY
|
3
3
|
# Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
|
4
4
|
# -*- encoding: utf-8 -*-
|
5
|
-
# stub: homesick 1.
|
5
|
+
# stub: homesick 1.1.0 ruby lib
|
6
6
|
|
7
7
|
Gem::Specification.new do |s|
|
8
8
|
s.name = "homesick"
|
9
|
-
s.version = "1.
|
9
|
+
s.version = "1.1.0"
|
10
10
|
|
11
11
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
12
|
+
s.require_paths = ["lib"]
|
12
13
|
s.authors = ["Joshua Nichols", "Yusuke Murata"]
|
13
|
-
s.date = "2014-
|
14
|
+
s.date = "2014-04-29"
|
14
15
|
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 "
|
15
16
|
s.email = ["josh@technicalpickles.com", "info@muratayusuke.com"]
|
16
17
|
s.executables = ["homesick"]
|
@@ -22,6 +23,7 @@ Gem::Specification.new do |s|
|
|
22
23
|
s.files = [
|
23
24
|
".document",
|
24
25
|
".rspec",
|
26
|
+
".rubocop.yml",
|
25
27
|
".travis.yml",
|
26
28
|
"ChangeLog.markdown",
|
27
29
|
"Gemfile",
|
@@ -32,17 +34,19 @@ Gem::Specification.new do |s|
|
|
32
34
|
"bin/homesick",
|
33
35
|
"homesick.gemspec",
|
34
36
|
"lib/homesick.rb",
|
35
|
-
"lib/homesick/actions.rb",
|
37
|
+
"lib/homesick/actions/file_actions.rb",
|
38
|
+
"lib/homesick/actions/git_actions.rb",
|
39
|
+
"lib/homesick/cli.rb",
|
36
40
|
"lib/homesick/shell.rb",
|
41
|
+
"lib/homesick/utils.rb",
|
37
42
|
"lib/homesick/version.rb",
|
38
|
-
"spec/
|
43
|
+
"spec/homesick_cli_spec.rb",
|
39
44
|
"spec/spec.opts",
|
40
45
|
"spec/spec_helper.rb"
|
41
46
|
]
|
42
47
|
s.homepage = "http://github.com/technicalpickles/homesick"
|
43
48
|
s.licenses = ["MIT"]
|
44
|
-
s.
|
45
|
-
s.rubygems_version = "2.1.11"
|
49
|
+
s.rubygems_version = "2.2.2"
|
46
50
|
s.summary = "Your home directory is your castle. Don't leave your dotfiles behind."
|
47
51
|
|
48
52
|
if s.respond_to? :specification_version then
|
@@ -56,11 +60,9 @@ Gem::Specification.new do |s|
|
|
56
60
|
s.add_development_dependency(%q<guard-rspec>, [">= 0"])
|
57
61
|
s.add_development_dependency(%q<rb-readline>, ["~> 0.5.0"])
|
58
62
|
s.add_development_dependency(%q<jeweler>, [">= 1.6.2"])
|
59
|
-
s.add_development_dependency(%q<
|
60
|
-
s.add_development_dependency(%q<simplecov>, [">= 0"])
|
63
|
+
s.add_development_dependency(%q<coveralls>, [">= 0"])
|
61
64
|
s.add_development_dependency(%q<test_construct>, [">= 0"])
|
62
65
|
s.add_development_dependency(%q<capture-output>, ["~> 1.0.0"])
|
63
|
-
s.add_development_dependency(%q<libnotify>, [">= 0"])
|
64
66
|
s.add_development_dependency(%q<rubocop>, [">= 0"])
|
65
67
|
else
|
66
68
|
s.add_dependency(%q<thor>, [">= 0.14.0"])
|
@@ -70,11 +72,9 @@ Gem::Specification.new do |s|
|
|
70
72
|
s.add_dependency(%q<guard-rspec>, [">= 0"])
|
71
73
|
s.add_dependency(%q<rb-readline>, ["~> 0.5.0"])
|
72
74
|
s.add_dependency(%q<jeweler>, [">= 1.6.2"])
|
73
|
-
s.add_dependency(%q<
|
74
|
-
s.add_dependency(%q<simplecov>, [">= 0"])
|
75
|
+
s.add_dependency(%q<coveralls>, [">= 0"])
|
75
76
|
s.add_dependency(%q<test_construct>, [">= 0"])
|
76
77
|
s.add_dependency(%q<capture-output>, ["~> 1.0.0"])
|
77
|
-
s.add_dependency(%q<libnotify>, [">= 0"])
|
78
78
|
s.add_dependency(%q<rubocop>, [">= 0"])
|
79
79
|
end
|
80
80
|
else
|
@@ -85,11 +85,9 @@ Gem::Specification.new do |s|
|
|
85
85
|
s.add_dependency(%q<guard-rspec>, [">= 0"])
|
86
86
|
s.add_dependency(%q<rb-readline>, ["~> 0.5.0"])
|
87
87
|
s.add_dependency(%q<jeweler>, [">= 1.6.2"])
|
88
|
-
s.add_dependency(%q<
|
89
|
-
s.add_dependency(%q<simplecov>, [">= 0"])
|
88
|
+
s.add_dependency(%q<coveralls>, [">= 0"])
|
90
89
|
s.add_dependency(%q<test_construct>, [">= 0"])
|
91
90
|
s.add_dependency(%q<capture-output>, ["~> 1.0.0"])
|
92
|
-
s.add_dependency(%q<libnotify>, [">= 0"])
|
93
91
|
s.add_dependency(%q<rubocop>, [">= 0"])
|
94
92
|
end
|
95
93
|
end
|
data/lib/homesick.rb
CHANGED
@@ -1,450 +1,15 @@
|
|
1
1
|
# -*- encoding : utf-8 -*-
|
2
|
-
require '
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
include Homesick::Version
|
12
|
-
|
13
|
-
add_runtime_options!
|
14
|
-
|
2
|
+
require 'homesick/shell'
|
3
|
+
require 'homesick/actions/file_actions'
|
4
|
+
require 'homesick/actions/git_actions'
|
5
|
+
require 'homesick/version'
|
6
|
+
require 'homesick/utils'
|
7
|
+
require 'homesick/cli'
|
8
|
+
|
9
|
+
# Homesick's top-level module
|
10
|
+
module Homesick
|
15
11
|
GITHUB_NAME_REPO_PATTERN = /\A([A-Za-z0-9_-]+\/[A-Za-z0-9_-]+)\Z/
|
16
12
|
SUBDIR_FILENAME = '.homesick_subdir'
|
17
13
|
|
18
14
|
DEFAULT_CASTLE_NAME = 'dotfiles'
|
19
|
-
|
20
|
-
map '-v' => :version
|
21
|
-
map '--version' => :version
|
22
|
-
|
23
|
-
def initialize(args = [], options = {}, config = {})
|
24
|
-
super
|
25
|
-
self.shell = Homesick::Shell.new
|
26
|
-
end
|
27
|
-
|
28
|
-
desc 'clone URI', 'Clone +uri+ as a castle for homesick'
|
29
|
-
def clone(uri)
|
30
|
-
inside repos_dir do
|
31
|
-
destination = nil
|
32
|
-
if File.exist?(uri)
|
33
|
-
uri = Pathname.new(uri).expand_path
|
34
|
-
if uri.to_s.start_with?(repos_dir.to_s)
|
35
|
-
raise "Castle already cloned to #{uri}"
|
36
|
-
end
|
37
|
-
|
38
|
-
destination = uri.basename
|
39
|
-
|
40
|
-
ln_s uri, destination
|
41
|
-
elsif uri =~ GITHUB_NAME_REPO_PATTERN
|
42
|
-
destination = Pathname.new(uri).basename
|
43
|
-
git_clone "https://github.com/#{$1}.git", :destination => destination
|
44
|
-
elsif uri =~ /%r([^%r]*?)(\.git)?\Z/
|
45
|
-
destination = Pathname.new($1)
|
46
|
-
git_clone uri
|
47
|
-
elsif uri =~ /[^:]+:([^:]+)(\.git)?\Z/
|
48
|
-
destination = Pathname.new($1)
|
49
|
-
git_clone uri
|
50
|
-
else
|
51
|
-
raise "Unknown URI format: #{uri}"
|
52
|
-
end
|
53
|
-
|
54
|
-
if destination.join('.gitmodules').exist?
|
55
|
-
inside destination do
|
56
|
-
git_submodule_init
|
57
|
-
git_submodule_update
|
58
|
-
end
|
59
|
-
end
|
60
|
-
|
61
|
-
rc(destination)
|
62
|
-
end
|
63
|
-
end
|
64
|
-
|
65
|
-
desc 'rc CASTLE', 'Run the .homesickrc for the specified castle'
|
66
|
-
def rc(name = DEFAULT_CASTLE_NAME)
|
67
|
-
inside repos_dir do
|
68
|
-
destination = Pathname.new(name)
|
69
|
-
homesickrc = destination.join('.homesickrc').expand_path
|
70
|
-
if homesickrc.exist?
|
71
|
-
proceed = shell.yes?("#{name} has a .homesickrc. Proceed with evaling it? (This could be destructive)")
|
72
|
-
if proceed
|
73
|
-
shell.say_status 'eval', homesickrc
|
74
|
-
inside destination do
|
75
|
-
eval homesickrc.read, binding, homesickrc.expand_path.to_s
|
76
|
-
end
|
77
|
-
else
|
78
|
-
shell.say_status 'eval skip', "not evaling #{homesickrc}, #{destination} may need manual configuration", :blue
|
79
|
-
end
|
80
|
-
end
|
81
|
-
end
|
82
|
-
end
|
83
|
-
|
84
|
-
desc 'pull CASTLE', 'Update the specified castle'
|
85
|
-
method_option :all, :type => :boolean, :default => false, :required => false, :desc => 'Update all cloned castles'
|
86
|
-
def pull(name = DEFAULT_CASTLE_NAME)
|
87
|
-
if options[:all]
|
88
|
-
inside_each_castle do |castle|
|
89
|
-
shell.say castle.to_s.gsub(repos_dir.to_s + '/', '') + ':'
|
90
|
-
update_castle castle
|
91
|
-
end
|
92
|
-
else
|
93
|
-
update_castle name
|
94
|
-
end
|
95
|
-
|
96
|
-
end
|
97
|
-
|
98
|
-
desc 'commit CASTLE MESSAGE', "Commit the specified castle's changes"
|
99
|
-
def commit(name = DEFAULT_CASTLE_NAME, message = nil)
|
100
|
-
commit_castle name, message
|
101
|
-
|
102
|
-
end
|
103
|
-
|
104
|
-
desc 'push CASTLE', 'Push the specified castle'
|
105
|
-
def push(name = DEFAULT_CASTLE_NAME)
|
106
|
-
push_castle name
|
107
|
-
end
|
108
|
-
|
109
|
-
desc 'unlink CASTLE', 'Unsymlinks all dotfiles from the specified castle'
|
110
|
-
def unlink(name = DEFAULT_CASTLE_NAME)
|
111
|
-
check_castle_existance(name, 'symlink')
|
112
|
-
|
113
|
-
inside castle_dir(name) do
|
114
|
-
subdirs = subdirs(name)
|
115
|
-
|
116
|
-
# unlink files
|
117
|
-
unsymlink_each(name, castle_dir(name), subdirs)
|
118
|
-
|
119
|
-
# unlink files in subdirs
|
120
|
-
subdirs.each do |subdir|
|
121
|
-
unsymlink_each(name, subdir, subdirs)
|
122
|
-
end
|
123
|
-
end
|
124
|
-
end
|
125
|
-
|
126
|
-
desc 'symlink CASTLE', 'Symlinks all dotfiles from the specified castle'
|
127
|
-
method_option :force, :default => false, :desc => 'Overwrite existing conflicting symlinks without prompting.'
|
128
|
-
def symlink(name = DEFAULT_CASTLE_NAME)
|
129
|
-
check_castle_existance(name, 'symlink')
|
130
|
-
|
131
|
-
inside castle_dir(name) do
|
132
|
-
subdirs = subdirs(name)
|
133
|
-
|
134
|
-
# link files
|
135
|
-
symlink_each(name, castle_dir(name), subdirs)
|
136
|
-
|
137
|
-
# link files in subdirs
|
138
|
-
subdirs.each do |subdir|
|
139
|
-
symlink_each(name, subdir, subdirs)
|
140
|
-
end
|
141
|
-
end
|
142
|
-
end
|
143
|
-
|
144
|
-
desc 'track FILE CASTLE', 'add a file to a castle'
|
145
|
-
def track(file, castle = DEFAULT_CASTLE_NAME)
|
146
|
-
castle = Pathname.new(castle)
|
147
|
-
file = Pathname.new(file.chomp('/'))
|
148
|
-
check_castle_existance(castle, 'track')
|
149
|
-
|
150
|
-
absolute_path = file.expand_path
|
151
|
-
relative_dir = absolute_path.relative_path_from(home_dir).dirname
|
152
|
-
castle_path = Pathname.new(castle_dir(castle)).join(relative_dir)
|
153
|
-
FileUtils.mkdir_p castle_path
|
154
|
-
|
155
|
-
# Are we already tracking this or anything inside it?
|
156
|
-
target = Pathname.new(castle_path.join(file.basename))
|
157
|
-
if target.exist?
|
158
|
-
if absolute_path.directory?
|
159
|
-
move_dir_contents(target, absolute_path)
|
160
|
-
absolute_path.rmtree
|
161
|
-
subdir_remove(castle, relative_dir + file.basename)
|
162
|
-
|
163
|
-
elsif more_recent? absolute_path, target
|
164
|
-
target.delete
|
165
|
-
mv absolute_path, castle_path
|
166
|
-
else
|
167
|
-
shell.say_status(:track, "#{target} already exists, and is more recent than #{file}. Run 'homesick SYMLINK CASTLE' to create symlinks.", :blue) unless options[:quiet]
|
168
|
-
end
|
169
|
-
else
|
170
|
-
mv absolute_path, castle_path
|
171
|
-
end
|
172
|
-
|
173
|
-
inside home_dir do
|
174
|
-
absolute_path = castle_path + file.basename
|
175
|
-
home_path = home_dir + relative_dir + file.basename
|
176
|
-
ln_s absolute_path, home_path
|
177
|
-
end
|
178
|
-
|
179
|
-
inside castle_path do
|
180
|
-
git_add absolute_path
|
181
|
-
end
|
182
|
-
|
183
|
-
# are we tracking something nested? Add the parent dir to the manifest
|
184
|
-
subdir_add(castle, relative_dir) unless relative_dir.eql?(Pathname.new('.'))
|
185
|
-
end
|
186
|
-
|
187
|
-
desc 'list', 'List cloned castles'
|
188
|
-
def list
|
189
|
-
inside_each_castle do |castle|
|
190
|
-
say_status castle.relative_path_from(repos_dir).to_s, `git config remote.origin.url`.chomp, :cyan
|
191
|
-
end
|
192
|
-
end
|
193
|
-
|
194
|
-
desc 'status CASTLE', 'Shows the git status of a castle'
|
195
|
-
def status(castle = DEFAULT_CASTLE_NAME)
|
196
|
-
check_castle_existance(castle, 'status')
|
197
|
-
inside repos_dir.join(castle) do
|
198
|
-
git_status
|
199
|
-
end
|
200
|
-
end
|
201
|
-
|
202
|
-
desc 'diff CASTLE', 'Shows the git diff of uncommitted changes in a castle'
|
203
|
-
def diff(castle = DEFAULT_CASTLE_NAME)
|
204
|
-
check_castle_existance(castle, 'diff')
|
205
|
-
inside repos_dir.join(castle) do
|
206
|
-
git_diff
|
207
|
-
end
|
208
|
-
end
|
209
|
-
|
210
|
-
desc 'show_path CASTLE', 'Prints the path of a castle'
|
211
|
-
def show_path(castle = DEFAULT_CASTLE_NAME)
|
212
|
-
check_castle_existance(castle, 'show_path')
|
213
|
-
say repos_dir.join(castle)
|
214
|
-
end
|
215
|
-
|
216
|
-
desc 'generate PATH', 'generate a homesick-ready git repo at PATH'
|
217
|
-
def generate(castle)
|
218
|
-
castle = Pathname.new(castle).expand_path
|
219
|
-
|
220
|
-
github_user = `git config github.user`.chomp
|
221
|
-
github_user = nil if github_user == ''
|
222
|
-
github_repo = castle.basename
|
223
|
-
|
224
|
-
empty_directory castle
|
225
|
-
inside castle do
|
226
|
-
git_init
|
227
|
-
if github_user
|
228
|
-
url = "git@github.com:#{github_user}/#{github_repo}.git"
|
229
|
-
git_remote_add 'origin', url
|
230
|
-
end
|
231
|
-
|
232
|
-
empty_directory 'home'
|
233
|
-
end
|
234
|
-
end
|
235
|
-
|
236
|
-
desc "destroy CASTLE", "Delete all symlinks and remove the cloned repository"
|
237
|
-
def destroy(name)
|
238
|
-
check_castle_existance name, "destroy"
|
239
|
-
|
240
|
-
if shell.yes?("This will destroy your castle irreversible! Are you sure?")
|
241
|
-
unlink(name)
|
242
|
-
rm_rf repos_dir.join(name)
|
243
|
-
end
|
244
|
-
|
245
|
-
end
|
246
|
-
|
247
|
-
desc "cd CASTLE", "Open a new shell in the root of the given castle"
|
248
|
-
def cd(castle = DEFAULT_CASTLE_NAME)
|
249
|
-
check_castle_existance castle, "cd"
|
250
|
-
castle_dir = repos_dir.join(castle)
|
251
|
-
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
|
252
|
-
inside castle_dir do
|
253
|
-
system(ENV['SHELL'])
|
254
|
-
end
|
255
|
-
end
|
256
|
-
|
257
|
-
desc "open CASTLE", "Open your default editor in the root of the given castle"
|
258
|
-
def open(castle = DEFAULT_CASTLE_NAME)
|
259
|
-
if ! ENV['EDITOR']
|
260
|
-
say_status :error,"The $EDITOR environment variable must be set to use this command", :red
|
261
|
-
|
262
|
-
exit(1)
|
263
|
-
end
|
264
|
-
check_castle_existance castle, "open"
|
265
|
-
castle_dir = repos_dir.join(castle)
|
266
|
-
say_status "#{ENV['EDITOR']} #{castle_dir.realpath}", "Opening the root directory of castle '#{castle}' in editor '#{ENV['EDITOR']}'.", :green
|
267
|
-
inside castle_dir do
|
268
|
-
system(ENV['EDITOR'])
|
269
|
-
end
|
270
|
-
end
|
271
|
-
|
272
|
-
desc 'version', 'Display the current version of homesick'
|
273
|
-
def version
|
274
|
-
say Homesick::Version::STRING
|
275
|
-
end
|
276
|
-
|
277
|
-
protected
|
278
|
-
|
279
|
-
def home_dir
|
280
|
-
@home_dir ||= Pathname.new(ENV['HOME'] || '~').expand_path
|
281
|
-
end
|
282
|
-
|
283
|
-
def repos_dir
|
284
|
-
@repos_dir ||= home_dir.join('.homesick', 'repos').expand_path
|
285
|
-
end
|
286
|
-
|
287
|
-
def castle_dir(name)
|
288
|
-
repos_dir.join(name, 'home')
|
289
|
-
end
|
290
|
-
|
291
|
-
def check_castle_existance(name, action)
|
292
|
-
unless castle_dir(name).exist?
|
293
|
-
say_status :error, "Could not #{action} #{name}, expected #{castle_dir(name)} exist and contain dotfiles", :red
|
294
|
-
|
295
|
-
exit(1)
|
296
|
-
end
|
297
|
-
end
|
298
|
-
|
299
|
-
def all_castles
|
300
|
-
dirs = Pathname.glob("#{repos_dir}/**/.git", File::FNM_DOTMATCH)
|
301
|
-
# reject paths that lie inside another castle, like git submodules
|
302
|
-
return dirs.reject do |dir|
|
303
|
-
dirs.any? do |other|
|
304
|
-
dir != other && dir.fnmatch(other.parent.join('*').to_s)
|
305
|
-
end
|
306
|
-
end
|
307
|
-
end
|
308
|
-
|
309
|
-
def inside_each_castle(&block)
|
310
|
-
all_castles.each do |git_dir|
|
311
|
-
castle = git_dir.dirname
|
312
|
-
Dir.chdir castle do # so we can call git config from the right contxt
|
313
|
-
yield castle
|
314
|
-
end
|
315
|
-
end
|
316
|
-
end
|
317
|
-
|
318
|
-
def update_castle(castle)
|
319
|
-
check_castle_existance(castle, 'pull')
|
320
|
-
inside repos_dir.join(castle) do
|
321
|
-
git_pull
|
322
|
-
git_submodule_init
|
323
|
-
git_submodule_update
|
324
|
-
end
|
325
|
-
end
|
326
|
-
|
327
|
-
def commit_castle(castle, message)
|
328
|
-
check_castle_existance(castle, 'commit')
|
329
|
-
inside repos_dir.join(castle) do
|
330
|
-
git_commit_all :message => message
|
331
|
-
end
|
332
|
-
end
|
333
|
-
|
334
|
-
def push_castle(castle)
|
335
|
-
check_castle_existance(castle, 'push')
|
336
|
-
inside repos_dir.join(castle) do
|
337
|
-
git_push
|
338
|
-
end
|
339
|
-
end
|
340
|
-
|
341
|
-
def subdir_file(castle)
|
342
|
-
repos_dir.join(castle, SUBDIR_FILENAME)
|
343
|
-
end
|
344
|
-
|
345
|
-
def subdirs(castle)
|
346
|
-
subdir_filepath = subdir_file(castle)
|
347
|
-
subdirs = []
|
348
|
-
if subdir_filepath.exist?
|
349
|
-
subdir_filepath.readlines.each do |subdir|
|
350
|
-
subdirs.push(subdir.chomp)
|
351
|
-
end
|
352
|
-
end
|
353
|
-
subdirs
|
354
|
-
end
|
355
|
-
|
356
|
-
def subdir_add(castle, path)
|
357
|
-
subdir_filepath = subdir_file(castle)
|
358
|
-
File.open(subdir_filepath, 'a+') do |subdir|
|
359
|
-
subdir.puts path unless subdir.readlines.reduce(false) do |memo, line|
|
360
|
-
line.eql?("#{path.to_s}\n") || memo
|
361
|
-
end
|
362
|
-
end
|
363
|
-
|
364
|
-
inside castle_dir(castle) do
|
365
|
-
git_add subdir_filepath
|
366
|
-
end
|
367
|
-
end
|
368
|
-
|
369
|
-
def subdir_remove(castle, path)
|
370
|
-
subdir_filepath = subdir_file(castle)
|
371
|
-
if subdir_filepath.exist?
|
372
|
-
lines = IO.readlines(subdir_filepath).delete_if { |line| line == "#{path}\n" }
|
373
|
-
File.open(subdir_filepath, 'w') { |manfile| manfile.puts lines }
|
374
|
-
end
|
375
|
-
|
376
|
-
inside castle_dir(castle) do
|
377
|
-
git_add subdir_filepath
|
378
|
-
end
|
379
|
-
end
|
380
|
-
|
381
|
-
def move_dir_contents(target, dir_path)
|
382
|
-
child_files = dir_path.children
|
383
|
-
child_files.each do |child|
|
384
|
-
|
385
|
-
target_path = target.join(child.basename)
|
386
|
-
if target_path.exist?
|
387
|
-
if more_recent?(child, target_path) && target.file?
|
388
|
-
target_path.delete
|
389
|
-
mv child, target
|
390
|
-
end
|
391
|
-
next
|
392
|
-
end
|
393
|
-
|
394
|
-
mv child, target
|
395
|
-
end
|
396
|
-
end
|
397
|
-
|
398
|
-
def more_recent?(first, second)
|
399
|
-
first_p = Pathname.new(first)
|
400
|
-
second_p = Pathname.new(second)
|
401
|
-
first_p.mtime > second_p.mtime && !first_p.symlink?
|
402
|
-
end
|
403
|
-
|
404
|
-
def each_file(castle, basedir, subdirs)
|
405
|
-
absolute_basedir = Pathname.new(basedir).expand_path
|
406
|
-
inside basedir do
|
407
|
-
files = Pathname.glob('{.*,*}').reject{ |a| ['.', '..'].include?(a.to_s) }
|
408
|
-
files.each do |path|
|
409
|
-
absolute_path = path.expand_path
|
410
|
-
castle_home = castle_dir(castle)
|
411
|
-
|
412
|
-
# make ignore dirs
|
413
|
-
ignore_dirs = []
|
414
|
-
subdirs.each do |subdir|
|
415
|
-
# ignore all parent of each line in subdir file
|
416
|
-
Pathname.new(subdir).ascend do |p|
|
417
|
-
ignore_dirs.push(p)
|
418
|
-
end
|
419
|
-
end
|
420
|
-
|
421
|
-
# ignore dirs written in subdir file
|
422
|
-
matched = false
|
423
|
-
ignore_dirs.uniq.each do |ignore_dir|
|
424
|
-
if absolute_path == castle_home.join(ignore_dir)
|
425
|
-
matched = true
|
426
|
-
break
|
427
|
-
end
|
428
|
-
end
|
429
|
-
next if matched
|
430
|
-
|
431
|
-
relative_dir = absolute_basedir.relative_path_from(castle_home)
|
432
|
-
home_path = home_dir.join(relative_dir).join(path)
|
433
|
-
|
434
|
-
yield(absolute_path, home_path)
|
435
|
-
end
|
436
|
-
end
|
437
|
-
end
|
438
|
-
|
439
|
-
def unsymlink_each(castle, basedir, subdirs)
|
440
|
-
each_file(castle, basedir, subdirs) do |absolute_path, home_path|
|
441
|
-
rm_link home_path
|
442
|
-
end
|
443
|
-
end
|
444
|
-
|
445
|
-
def symlink_each(castle, basedir, subdirs)
|
446
|
-
each_file(castle, basedir, subdirs) do |absolute_path, home_path|
|
447
|
-
ln_s absolute_path, home_path
|
448
|
-
end
|
449
|
-
end
|
450
15
|
end
|