homesick 1.0.0 → 1.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
[![Gem Version](https://badge.fury.io/rb/homesick.png)](http://badge.fury.io/rb/homesick)
|
4
4
|
[![Build Status](https://travis-ci.org/technicalpickles/homesick.png?branch=master)](https://travis-ci.org/technicalpickles/homesick)
|
5
5
|
[![Dependency Status](https://gemnasium.com/technicalpickles/homesick.png)](https://gemnasium.com/technicalpickles/homesick)
|
6
|
+
[![Coverage Status](https://coveralls.io/repos/technicalpickles/homesick/badge.png)](https://coveralls.io/r/technicalpickles/homesick)
|
6
7
|
[![Code Climate](https://codeclimate.com/github/technicalpickles/homesick.png)](https://codeclimate.com/github/technicalpickles/homesick)
|
8
|
+
[![Gitter chat](https://badges.gitter.im/technicalpickles/homesick.png)](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
|