homesick 1.1.6 → 2.0.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 +5 -5
- data/.github/dependabot.yml +9 -0
- data/.github/workflows/ci.yml +67 -0
- data/.github/workflows/mutant-nightly.yml +31 -0
- data/.github/workflows/release.yml +27 -0
- data/.gitignore +52 -0
- data/.mutant.yml +26 -0
- data/.rubocop.yml +37 -14
- data/ChangeLog.markdown +28 -1
- data/Gemfile +3 -34
- data/Gemfile.lock +128 -0
- data/Guardfile +6 -4
- data/README.markdown +7 -11
- data/Rakefile +8 -62
- data/bin/homesick +1 -0
- data/homesick.gemspec +28 -99
- data/lib/homesick/actions/file_actions.rb +31 -37
- data/lib/homesick/actions/git_actions.rb +18 -15
- data/lib/homesick/cli.rb +39 -62
- data/lib/homesick/rc.rb +30 -0
- data/lib/homesick/utils.rb +94 -52
- data/lib/homesick/version.rb +5 -4
- data/lib/homesick.rb +19 -1
- data/spec/homesick_cli_spec.rb +74 -47
- data/spec/homesick_rc_spec.rb +59 -0
- data/spec/spec_helper.rb +1 -2
- metadata +37 -120
- data/.travis.yml +0 -6
data/homesick.gemspec
CHANGED
|
@@ -1,105 +1,34 @@
|
|
|
1
|
-
#
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
# -*- encoding: utf-8 -*-
|
|
5
|
-
# stub: homesick 1.1.6 ruby lib
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'lib/homesick/version'
|
|
6
4
|
|
|
7
5
|
Gem::Specification.new do |s|
|
|
8
|
-
s.name
|
|
9
|
-
s.version
|
|
6
|
+
s.name = 'homesick'
|
|
7
|
+
s.version = Homesick::Version::STRING
|
|
8
|
+
s.authors = ['Joshua Nichols', 'Yusuke Murata']
|
|
9
|
+
s.email = ['josh@technicalpickles.com', 'info@muratayusuke.com']
|
|
10
|
+
s.homepage = 'http://github.com/technicalpickles/homesick'
|
|
11
|
+
s.summary = "Your home directory is your castle. Don't leave your dotfiles behind."
|
|
12
|
+
s.description = 'Homesick is sorta like rip, but for dotfiles. It uses git to clone a ' \
|
|
13
|
+
'repository containing dotfiles, and saves them in ~/.homesick. It then ' \
|
|
14
|
+
'allows you to symlink all the dotfiles into place with a single command.'
|
|
15
|
+
s.license = 'MIT'
|
|
16
|
+
s.metadata = { 'rubygems_mfa_required' => 'true' }
|
|
10
17
|
|
|
11
|
-
s.
|
|
12
|
-
s.require_paths = ["lib".freeze]
|
|
13
|
-
s.authors = ["Joshua Nichols".freeze, "Yusuke Murata".freeze]
|
|
14
|
-
s.date = "2017-12-20"
|
|
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 ".freeze
|
|
16
|
-
s.email = ["josh@technicalpickles.com".freeze, "info@muratayusuke.com".freeze]
|
|
17
|
-
s.executables = ["homesick".freeze]
|
|
18
|
-
s.extra_rdoc_files = [
|
|
19
|
-
"ChangeLog.markdown",
|
|
20
|
-
"LICENSE",
|
|
21
|
-
"README.markdown"
|
|
22
|
-
]
|
|
23
|
-
s.files = [
|
|
24
|
-
".document",
|
|
25
|
-
".rspec",
|
|
26
|
-
".rubocop.yml",
|
|
27
|
-
".travis.yml",
|
|
28
|
-
"ChangeLog.markdown",
|
|
29
|
-
"Gemfile",
|
|
30
|
-
"Guardfile",
|
|
31
|
-
"LICENSE",
|
|
32
|
-
"README.markdown",
|
|
33
|
-
"Rakefile",
|
|
34
|
-
"bin/homesick",
|
|
35
|
-
"homesick.gemspec",
|
|
36
|
-
"lib/homesick.rb",
|
|
37
|
-
"lib/homesick/actions/file_actions.rb",
|
|
38
|
-
"lib/homesick/actions/git_actions.rb",
|
|
39
|
-
"lib/homesick/cli.rb",
|
|
40
|
-
"lib/homesick/utils.rb",
|
|
41
|
-
"lib/homesick/version.rb",
|
|
42
|
-
"spec/homesick_cli_spec.rb",
|
|
43
|
-
"spec/spec.opts",
|
|
44
|
-
"spec/spec_helper.rb"
|
|
45
|
-
]
|
|
46
|
-
s.homepage = "http://github.com/technicalpickles/homesick".freeze
|
|
47
|
-
s.licenses = ["MIT".freeze]
|
|
48
|
-
s.rubygems_version = "2.6.11".freeze
|
|
49
|
-
s.summary = "Your home directory is your castle. Don't leave your dotfiles behind.".freeze
|
|
18
|
+
s.required_ruby_version = '>= 3.2'
|
|
50
19
|
|
|
51
|
-
|
|
52
|
-
|
|
20
|
+
s.files = `git ls-files`.split("\n")
|
|
21
|
+
s.executables = ['homesick']
|
|
22
|
+
s.require_paths = ['lib']
|
|
53
23
|
|
|
54
|
-
|
|
55
|
-
s.add_runtime_dependency(%q<thor>.freeze, [">= 0.14.0"])
|
|
56
|
-
s.add_development_dependency(%q<capture-output>.freeze, ["~> 1.0.0"])
|
|
57
|
-
s.add_development_dependency(%q<coveralls>.freeze, [">= 0"])
|
|
58
|
-
s.add_development_dependency(%q<guard>.freeze, [">= 0"])
|
|
59
|
-
s.add_development_dependency(%q<guard-rspec>.freeze, [">= 0"])
|
|
60
|
-
s.add_development_dependency(%q<jeweler>.freeze, [">= 1.6.2"])
|
|
61
|
-
s.add_development_dependency(%q<rake>.freeze, [">= 0.8.7"])
|
|
62
|
-
s.add_development_dependency(%q<rb-readline>.freeze, ["~> 0.5.0"])
|
|
63
|
-
s.add_development_dependency(%q<rspec>.freeze, ["~> 3.5.0"])
|
|
64
|
-
s.add_development_dependency(%q<rubocop>.freeze, [">= 0"])
|
|
65
|
-
s.add_development_dependency(%q<test_construct>.freeze, [">= 0"])
|
|
66
|
-
s.add_development_dependency(%q<libnotify>.freeze, [">= 0"])
|
|
67
|
-
s.add_development_dependency(%q<terminal-notifier-guard>.freeze, ["~> 1.7.0"])
|
|
68
|
-
s.add_development_dependency(%q<listen>.freeze, ["< 3"])
|
|
69
|
-
s.add_development_dependency(%q<rack>.freeze, ["< 2"])
|
|
70
|
-
else
|
|
71
|
-
s.add_dependency(%q<thor>.freeze, [">= 0.14.0"])
|
|
72
|
-
s.add_dependency(%q<capture-output>.freeze, ["~> 1.0.0"])
|
|
73
|
-
s.add_dependency(%q<coveralls>.freeze, [">= 0"])
|
|
74
|
-
s.add_dependency(%q<guard>.freeze, [">= 0"])
|
|
75
|
-
s.add_dependency(%q<guard-rspec>.freeze, [">= 0"])
|
|
76
|
-
s.add_dependency(%q<jeweler>.freeze, [">= 1.6.2"])
|
|
77
|
-
s.add_dependency(%q<rake>.freeze, [">= 0.8.7"])
|
|
78
|
-
s.add_dependency(%q<rb-readline>.freeze, ["~> 0.5.0"])
|
|
79
|
-
s.add_dependency(%q<rspec>.freeze, ["~> 3.5.0"])
|
|
80
|
-
s.add_dependency(%q<rubocop>.freeze, [">= 0"])
|
|
81
|
-
s.add_dependency(%q<test_construct>.freeze, [">= 0"])
|
|
82
|
-
s.add_dependency(%q<libnotify>.freeze, [">= 0"])
|
|
83
|
-
s.add_dependency(%q<terminal-notifier-guard>.freeze, ["~> 1.7.0"])
|
|
84
|
-
s.add_dependency(%q<listen>.freeze, ["< 3"])
|
|
85
|
-
s.add_dependency(%q<rack>.freeze, ["< 2"])
|
|
86
|
-
end
|
|
87
|
-
else
|
|
88
|
-
s.add_dependency(%q<thor>.freeze, [">= 0.14.0"])
|
|
89
|
-
s.add_dependency(%q<capture-output>.freeze, ["~> 1.0.0"])
|
|
90
|
-
s.add_dependency(%q<coveralls>.freeze, [">= 0"])
|
|
91
|
-
s.add_dependency(%q<guard>.freeze, [">= 0"])
|
|
92
|
-
s.add_dependency(%q<guard-rspec>.freeze, [">= 0"])
|
|
93
|
-
s.add_dependency(%q<jeweler>.freeze, [">= 1.6.2"])
|
|
94
|
-
s.add_dependency(%q<rake>.freeze, [">= 0.8.7"])
|
|
95
|
-
s.add_dependency(%q<rb-readline>.freeze, ["~> 0.5.0"])
|
|
96
|
-
s.add_dependency(%q<rspec>.freeze, ["~> 3.5.0"])
|
|
97
|
-
s.add_dependency(%q<rubocop>.freeze, [">= 0"])
|
|
98
|
-
s.add_dependency(%q<test_construct>.freeze, [">= 0"])
|
|
99
|
-
s.add_dependency(%q<libnotify>.freeze, [">= 0"])
|
|
100
|
-
s.add_dependency(%q<terminal-notifier-guard>.freeze, ["~> 1.7.0"])
|
|
101
|
-
s.add_dependency(%q<listen>.freeze, ["< 3"])
|
|
102
|
-
s.add_dependency(%q<rack>.freeze, ["< 2"])
|
|
103
|
-
end
|
|
104
|
-
end
|
|
24
|
+
s.add_dependency 'thor', '~> 1.0'
|
|
105
25
|
|
|
26
|
+
s.add_development_dependency 'bundler-audit', '~> 0.9'
|
|
27
|
+
s.add_development_dependency 'capture-output', '~> 1.0'
|
|
28
|
+
s.add_development_dependency 'mutant-rspec'
|
|
29
|
+
s.add_development_dependency 'rake'
|
|
30
|
+
s.add_development_dependency 'rspec', '~> 3.0'
|
|
31
|
+
s.add_development_dependency 'rubocop'
|
|
32
|
+
s.add_development_dependency 'rubocop-rake'
|
|
33
|
+
s.add_development_dependency 'test_construct'
|
|
34
|
+
end
|
|
@@ -1,18 +1,17 @@
|
|
|
1
|
-
#
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
2
3
|
module Homesick
|
|
3
4
|
module Actions
|
|
4
5
|
# File-related helper methods for Homesick
|
|
5
6
|
module FileActions
|
|
7
|
+
protected
|
|
8
|
+
|
|
6
9
|
def mv(source, destination)
|
|
7
10
|
source = Pathname.new(source)
|
|
8
11
|
destination = Pathname.new(destination + source.basename)
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
FileUtils.mv source, destination unless options[:pretend]
|
|
13
|
-
else
|
|
14
|
-
FileUtils.mv source, destination unless options[:pretend]
|
|
15
|
-
end
|
|
12
|
+
collision = destination.exist? && (options[:force] || shell.file_collision(destination) { source })
|
|
13
|
+
say_status :conflict, "#{destination} exists", :red if collision
|
|
14
|
+
FileUtils.mv source, destination unless options[:pretend]
|
|
16
15
|
end
|
|
17
16
|
|
|
18
17
|
def rm_rf(dir)
|
|
@@ -24,7 +23,7 @@ module Homesick
|
|
|
24
23
|
target = Pathname.new(target)
|
|
25
24
|
|
|
26
25
|
if target.symlink?
|
|
27
|
-
say_status :unlink,
|
|
26
|
+
say_status :unlink, target.expand_path.to_s, :green
|
|
28
27
|
FileUtils.rm_rf target
|
|
29
28
|
else
|
|
30
29
|
say_status :conflict, "#{target} is not a symlink", :red
|
|
@@ -42,45 +41,40 @@ module Homesick
|
|
|
42
41
|
end
|
|
43
42
|
|
|
44
43
|
def ln_s(source, destination)
|
|
45
|
-
source = Pathname.new(source).realpath
|
|
44
|
+
source = Pathname.new(source).realpath
|
|
46
45
|
destination = Pathname.new(destination)
|
|
47
46
|
FileUtils.mkdir_p destination.dirname
|
|
48
47
|
|
|
49
|
-
action =
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
elsif destination.exist?
|
|
54
|
-
:conflict
|
|
55
|
-
else
|
|
56
|
-
:success
|
|
57
|
-
end
|
|
48
|
+
action = :success
|
|
49
|
+
action = :identical if destination.symlink? && destination.readlink == source
|
|
50
|
+
action = :symlink_conflict if destination.symlink?
|
|
51
|
+
action = :conflict if destination.exist?
|
|
58
52
|
|
|
59
53
|
handle_symlink_action action, source, destination
|
|
60
54
|
end
|
|
61
55
|
|
|
62
56
|
def handle_symlink_action(action, source, destination)
|
|
63
|
-
|
|
64
|
-
when :identical
|
|
57
|
+
if action == :identical
|
|
65
58
|
say_status :identical, destination.expand_path, :blue
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
if collision_accepted?(destination, source)
|
|
75
|
-
FileUtils.rm_r destination, force: true unless options[:pretend]
|
|
76
|
-
FileUtils.ln_s source, destination, force: true unless options[:pretend]
|
|
77
|
-
end
|
|
59
|
+
return
|
|
60
|
+
end
|
|
61
|
+
message = generate_symlink_message action, source, destination
|
|
62
|
+
if %i[symlink_conflict conflict].include?(action)
|
|
63
|
+
say_status :conflict, message, :red
|
|
64
|
+
return unless collision_accepted?(destination, source)
|
|
65
|
+
|
|
66
|
+
FileUtils.rm_r destination, force: true unless options[:pretend]
|
|
78
67
|
else
|
|
79
|
-
say_status :symlink,
|
|
80
|
-
"#{source.expand_path} to #{destination.expand_path}",
|
|
81
|
-
:green
|
|
82
|
-
FileUtils.ln_s source, destination unless options[:pretend]
|
|
68
|
+
say_status :symlink, message, :green
|
|
83
69
|
end
|
|
70
|
+
FileUtils.ln_s source, destination, force: true unless options[:pretend]
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def generate_symlink_message(action, source, destination)
|
|
74
|
+
message = "#{source.expand_path} to #{destination.expand_path}"
|
|
75
|
+
message = "#{destination} exists and points to #{destination.readlink}" if action == :symlink_conflict
|
|
76
|
+
message = "#{destination} exists" if action == :conflict
|
|
77
|
+
message
|
|
84
78
|
end
|
|
85
79
|
end
|
|
86
80
|
end
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
#
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
2
3
|
module Homesick
|
|
3
4
|
module Actions
|
|
4
5
|
# Git-related helper methods for Homesick
|
|
@@ -8,35 +9,37 @@ module Homesick
|
|
|
8
9
|
major: 1,
|
|
9
10
|
minor: 8,
|
|
10
11
|
patch: 0
|
|
11
|
-
}
|
|
12
|
+
}.freeze
|
|
12
13
|
STRING = MIN_VERSION.values.join('.')
|
|
13
14
|
|
|
14
15
|
def git_version_correct?
|
|
15
16
|
info = `git --version`.scan(/(\d+)\.(\d+)\.(\d+)/).flatten.map(&:to_i)
|
|
16
17
|
return false unless info.count == 3
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
18
|
+
|
|
19
|
+
current_version = %i[major minor patch].zip(info).to_h
|
|
20
|
+
major_equals = current_version.eql?(MIN_VERSION)
|
|
21
|
+
major_greater = current_version[:major] > MIN_VERSION[:major]
|
|
22
|
+
minor_greater = current_version[:major] == MIN_VERSION[:major] &&
|
|
23
|
+
current_version[:minor] > MIN_VERSION[:minor]
|
|
24
|
+
patch_greater = current_version[:major] == MIN_VERSION[:major] &&
|
|
25
|
+
current_version[:minor] == MIN_VERSION[:minor] &&
|
|
26
|
+
current_version[:patch] >= MIN_VERSION[:patch]
|
|
27
|
+
|
|
28
|
+
major_equals || major_greater || minor_greater || patch_greater
|
|
23
29
|
end
|
|
24
30
|
|
|
25
|
-
# TODO: move this to be more like thor's template, empty_directory, etc
|
|
26
31
|
def git_clone(repo, config = {})
|
|
27
|
-
config ||= {}
|
|
28
32
|
destination = config[:destination] || File.basename(repo, '.git')
|
|
29
|
-
|
|
30
33
|
destination = Pathname.new(destination) unless destination.is_a?(Pathname)
|
|
31
34
|
FileUtils.mkdir_p destination.dirname
|
|
32
35
|
|
|
33
36
|
if destination.directory?
|
|
34
37
|
say_status :exist, destination.expand_path, :blue
|
|
35
38
|
else
|
|
36
|
-
say_status 'git clone',
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
39
|
+
say_status 'git clone', "#{repo} to #{destination.expand_path}", :green
|
|
40
|
+
unless options[:pretend]
|
|
41
|
+
system "git clone -q --config push.default=upstream --recursive #{repo} #{destination}"
|
|
42
|
+
end
|
|
40
43
|
end
|
|
41
44
|
end
|
|
42
45
|
|
data/lib/homesick/cli.rb
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
#
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
2
3
|
require 'fileutils'
|
|
3
4
|
require 'thor'
|
|
4
5
|
|
|
@@ -13,6 +14,10 @@ module Homesick
|
|
|
13
14
|
|
|
14
15
|
add_runtime_options!
|
|
15
16
|
|
|
17
|
+
def self.exit_on_failure?
|
|
18
|
+
true
|
|
19
|
+
end
|
|
20
|
+
|
|
16
21
|
map '-v' => :version
|
|
17
22
|
map '--version' => :version
|
|
18
23
|
# Retain a mapped version of the symlink command for compatibility.
|
|
@@ -22,45 +27,20 @@ module Homesick
|
|
|
22
27
|
super
|
|
23
28
|
# Check if git is installed
|
|
24
29
|
unless git_version_correct?
|
|
25
|
-
say_status :error,
|
|
30
|
+
say_status :error,
|
|
31
|
+
"Git version >= #{Homesick::Actions::GitActions::STRING} must be installed to use Homesick",
|
|
32
|
+
:red
|
|
26
33
|
exit(1)
|
|
27
34
|
end
|
|
28
|
-
|
|
29
|
-
# Also adds support for checking if destination or content is a directory
|
|
30
|
-
shell_metaclass = class << shell; self; end
|
|
31
|
-
shell_metaclass.send(:define_method, :show_diff) do |destination, source|
|
|
32
|
-
destination = Pathname.new(destination)
|
|
33
|
-
source = Pathname.new(source)
|
|
34
|
-
return 'Unable to create diff: destination or content is a directory' if destination.directory? || source.directory?
|
|
35
|
-
return super(destination, File.binread(source)) unless destination.symlink?
|
|
36
|
-
say "- #{destination.readlink}", :red, true
|
|
37
|
-
say "+ #{source.expand_path}", :green, true
|
|
38
|
-
end
|
|
35
|
+
configure_symlinks_diff
|
|
39
36
|
end
|
|
40
37
|
|
|
41
38
|
desc 'clone URI CASTLE_NAME', 'Clone +uri+ as a castle with name CASTLE_NAME for homesick'
|
|
42
|
-
def clone(uri, destination=nil)
|
|
39
|
+
def clone(uri, destination = nil)
|
|
43
40
|
destination = Pathname.new(destination) unless destination.nil?
|
|
44
41
|
|
|
45
42
|
inside repos_dir do
|
|
46
|
-
|
|
47
|
-
uri = Pathname.new(uri).expand_path
|
|
48
|
-
fail "Castle already cloned to #{uri}" if uri.to_s.start_with?(repos_dir.to_s)
|
|
49
|
-
|
|
50
|
-
destination = uri.basename if destination.nil?
|
|
51
|
-
|
|
52
|
-
ln_s uri, destination
|
|
53
|
-
elsif uri =~ GITHUB_NAME_REPO_PATTERN
|
|
54
|
-
destination = Pathname.new(uri).basename if destination.nil?
|
|
55
|
-
git_clone "https://github.com/#{Regexp.last_match[1]}.git",
|
|
56
|
-
destination: destination
|
|
57
|
-
elsif uri =~ /%r([^%r]*?)(\.git)?\Z/ || uri =~ /[^:]+:([^:]+)(\.git)?\Z/
|
|
58
|
-
destination = Pathname.new(Regexp.last_match[1].gsub(/\.git$/, '')).basename if destination.nil?
|
|
59
|
-
git_clone uri, destination: destination
|
|
60
|
-
else
|
|
61
|
-
fail "Unknown URI format: #{uri}"
|
|
62
|
-
end
|
|
63
|
-
|
|
43
|
+
destination = clone_from_uri(uri, destination)
|
|
64
44
|
setup_castle(destination)
|
|
65
45
|
end
|
|
66
46
|
end
|
|
@@ -75,11 +55,19 @@ module Homesick
|
|
|
75
55
|
destination = Pathname.new(name)
|
|
76
56
|
homesickrc = destination.join('.homesickrc').expand_path
|
|
77
57
|
return unless homesickrc.exist?
|
|
78
|
-
|
|
79
|
-
|
|
58
|
+
|
|
59
|
+
proceed = options[:force] ||
|
|
60
|
+
shell.yes?("#{name} has a .homesickrc. Proceed with evaling it? (This could be destructive)")
|
|
61
|
+
unless proceed
|
|
62
|
+
return say_status 'eval skip',
|
|
63
|
+
"not evaling #{homesickrc}, #{destination} may need manual configuration",
|
|
64
|
+
:blue
|
|
65
|
+
end
|
|
66
|
+
|
|
80
67
|
say_status 'eval', homesickrc
|
|
81
68
|
inside destination do
|
|
82
|
-
|
|
69
|
+
ctx = Homesick::RC::Context.new(destination.expand_path)
|
|
70
|
+
ctx.instance_eval(homesickrc.read, homesickrc.expand_path.to_s)
|
|
83
71
|
end
|
|
84
72
|
end
|
|
85
73
|
end
|
|
@@ -93,7 +81,7 @@ module Homesick
|
|
|
93
81
|
def pull(name = DEFAULT_CASTLE_NAME)
|
|
94
82
|
if options[:all]
|
|
95
83
|
inside_each_castle do |castle|
|
|
96
|
-
say castle.to_s.gsub(repos_dir
|
|
84
|
+
say "#{castle.to_s.gsub("#{repos_dir}/", '')}:"
|
|
97
85
|
update_castle castle
|
|
98
86
|
end
|
|
99
87
|
else
|
|
@@ -136,11 +124,12 @@ module Homesick
|
|
|
136
124
|
def link(name = DEFAULT_CASTLE_NAME)
|
|
137
125
|
check_castle_existance(name, 'symlink')
|
|
138
126
|
|
|
139
|
-
|
|
127
|
+
castle_path = castle_dir(name)
|
|
128
|
+
inside castle_path do
|
|
140
129
|
subdirs = subdirs(name)
|
|
141
130
|
|
|
142
131
|
# link files
|
|
143
|
-
symlink_each(name,
|
|
132
|
+
symlink_each(name, castle_path, subdirs)
|
|
144
133
|
|
|
145
134
|
# link files in subdirs
|
|
146
135
|
subdirs.each do |subdir|
|
|
@@ -160,22 +149,9 @@ module Homesick
|
|
|
160
149
|
castle_path = Pathname.new(castle_dir(castle)).join(relative_dir)
|
|
161
150
|
FileUtils.mkdir_p castle_path
|
|
162
151
|
|
|
163
|
-
# Are we already tracking this or anything inside it?
|
|
164
152
|
target = Pathname.new(castle_path.join(file.basename))
|
|
165
153
|
if target.exist?
|
|
166
|
-
|
|
167
|
-
move_dir_contents(target, absolute_path)
|
|
168
|
-
absolute_path.rmtree
|
|
169
|
-
subdir_remove(castle, relative_dir + file.basename)
|
|
170
|
-
|
|
171
|
-
elsif more_recent? absolute_path, target
|
|
172
|
-
target.delete
|
|
173
|
-
mv absolute_path, castle_path
|
|
174
|
-
else
|
|
175
|
-
say_status(:track,
|
|
176
|
-
"#{target} already exists, and is more recent than #{file}. Run 'homesick SYMLINK CASTLE' to create symlinks.",
|
|
177
|
-
:blue)
|
|
178
|
-
end
|
|
154
|
+
handle_existing_track_target(castle, absolute_path, castle_path, relative_dir, file, target)
|
|
179
155
|
else
|
|
180
156
|
mv absolute_path, castle_path
|
|
181
157
|
end
|
|
@@ -190,7 +166,6 @@ module Homesick
|
|
|
190
166
|
git_add absolute_path
|
|
191
167
|
end
|
|
192
168
|
|
|
193
|
-
# are we tracking something nested? Add the parent dir to the manifest
|
|
194
169
|
subdir_add(castle, relative_dir) unless relative_dir.eql?(Pathname.new('.'))
|
|
195
170
|
end
|
|
196
171
|
|
|
@@ -262,14 +237,14 @@ module Homesick
|
|
|
262
237
|
"Opening a new shell in castle '#{castle}'. To return to the original one exit from the new shell.",
|
|
263
238
|
:green
|
|
264
239
|
inside castle_dir do
|
|
265
|
-
system(ENV
|
|
240
|
+
system(ENV.fetch('SHELL', nil))
|
|
266
241
|
end
|
|
267
242
|
end
|
|
268
243
|
|
|
269
244
|
desc 'open CASTLE',
|
|
270
245
|
'Open your default editor in the root of the given castle'
|
|
271
246
|
def open(castle = DEFAULT_CASTLE_NAME)
|
|
272
|
-
unless ENV
|
|
247
|
+
unless ENV.fetch('EDITOR', nil)
|
|
273
248
|
say_status :error,
|
|
274
249
|
'The $EDITOR environment variable must be set to use this command',
|
|
275
250
|
:red
|
|
@@ -278,11 +253,11 @@ module Homesick
|
|
|
278
253
|
end
|
|
279
254
|
check_castle_existance castle, 'open'
|
|
280
255
|
castle_dir = repos_dir.join(castle)
|
|
281
|
-
say_status "#{castle_dir.realpath}: #{ENV
|
|
282
|
-
"Opening the root directory of castle '#{castle}' in editor '#{ENV
|
|
256
|
+
say_status "#{castle_dir.realpath}: #{ENV.fetch('EDITOR', nil)} .",
|
|
257
|
+
"Opening the root directory of castle '#{castle}' in editor '#{ENV.fetch('EDITOR', nil)}'.",
|
|
283
258
|
:green
|
|
284
259
|
inside castle_dir do
|
|
285
|
-
system("#{ENV
|
|
260
|
+
system("#{ENV.fetch('EDITOR', nil)} .")
|
|
286
261
|
end
|
|
287
262
|
end
|
|
288
263
|
|
|
@@ -290,15 +265,16 @@ module Homesick
|
|
|
290
265
|
'Execute a single shell command inside the root of a castle'
|
|
291
266
|
def exec(castle, *args)
|
|
292
267
|
check_castle_existance castle, 'exec'
|
|
293
|
-
unless args.
|
|
268
|
+
unless args.any?
|
|
294
269
|
say_status :error,
|
|
295
270
|
'You must pass a shell command to execute',
|
|
296
271
|
:red
|
|
297
272
|
exit(1)
|
|
298
273
|
end
|
|
299
274
|
full_command = args.join(' ')
|
|
275
|
+
action = options[:pretend] ? 'Would execute' : 'Executing command'
|
|
300
276
|
say_status "exec '#{full_command}'",
|
|
301
|
-
"#{
|
|
277
|
+
"#{action} '#{full_command}' in castle '#{castle}'",
|
|
302
278
|
:green
|
|
303
279
|
inside repos_dir.join(castle) do
|
|
304
280
|
system(full_command)
|
|
@@ -308,7 +284,7 @@ module Homesick
|
|
|
308
284
|
desc 'exec_all COMMAND',
|
|
309
285
|
'Execute a single shell command inside the root of every cloned castle'
|
|
310
286
|
def exec_all(*args)
|
|
311
|
-
unless args.
|
|
287
|
+
unless args.any?
|
|
312
288
|
say_status :error,
|
|
313
289
|
'You must pass a shell command to execute',
|
|
314
290
|
:red
|
|
@@ -316,8 +292,9 @@ module Homesick
|
|
|
316
292
|
end
|
|
317
293
|
full_command = args.join(' ')
|
|
318
294
|
inside_each_castle do |castle|
|
|
295
|
+
action = options[:pretend] ? 'Would execute' : 'Executing command'
|
|
319
296
|
say_status "exec '#{full_command}'",
|
|
320
|
-
"#{
|
|
297
|
+
"#{action} '#{full_command}' in castle '#{castle}'",
|
|
321
298
|
:green
|
|
322
299
|
system(full_command)
|
|
323
300
|
end
|
data/lib/homesick/rc.rb
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'pathname'
|
|
4
|
+
|
|
5
|
+
module Homesick
|
|
6
|
+
module RC
|
|
7
|
+
# Evaluation context for .homesickrc scripts.
|
|
8
|
+
#
|
|
9
|
+
# Runs castle setup scripts in a clean object rather than in the
|
|
10
|
+
# Homesick::CLI binding, so scripts cannot access CLI internals.
|
|
11
|
+
# Standard Ruby library methods (File, Dir, system, etc.) remain
|
|
12
|
+
# available to scripts.
|
|
13
|
+
class Context
|
|
14
|
+
# @param castle_path [Pathname, String] absolute path to the castle root
|
|
15
|
+
def initialize(castle_path)
|
|
16
|
+
@castle_path = Pathname.new(castle_path)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
# The absolute path of the castle being configured.
|
|
20
|
+
attr_reader :castle_path
|
|
21
|
+
|
|
22
|
+
# Execute a shell command.
|
|
23
|
+
# @param command [String]
|
|
24
|
+
# @return [Boolean] true if the command succeeded
|
|
25
|
+
def run(command)
|
|
26
|
+
system(command)
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|