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
data/lib/homesick/shell.rb
CHANGED
@@ -1,7 +1,8 @@
|
|
1
|
-
|
1
|
+
require 'thor'
|
2
|
+
|
3
|
+
module Homesick
|
2
4
|
# Hack in support for diffing symlinks
|
3
5
|
class Shell < Thor::Shell::Color
|
4
|
-
|
5
6
|
def show_diff(destination, content)
|
6
7
|
destination = Pathname.new(destination)
|
7
8
|
|
@@ -12,6 +13,5 @@ class Homesick
|
|
12
13
|
super
|
13
14
|
end
|
14
15
|
end
|
15
|
-
|
16
16
|
end
|
17
17
|
end
|
@@ -0,0 +1,216 @@
|
|
1
|
+
# -*- encoding : utf-8 -*-
|
2
|
+
module Homesick
|
3
|
+
# Various utility methods that are used by Homesick
|
4
|
+
module Utils
|
5
|
+
QUIETABLE = ['say_status']
|
6
|
+
|
7
|
+
PRETENDABLE = ['system']
|
8
|
+
|
9
|
+
QUIETABLE.each do |method_name|
|
10
|
+
define_method(method_name) do |*args|
|
11
|
+
super(*args) unless options[:quiet]
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
PRETENDABLE.each do |method_name|
|
16
|
+
define_method(method_name) do |*args|
|
17
|
+
super(*args) unless options[:pretend]
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
protected
|
22
|
+
|
23
|
+
def home_dir
|
24
|
+
@home_dir ||= Pathname.new(ENV['HOME'] || '~').expand_path
|
25
|
+
end
|
26
|
+
|
27
|
+
def repos_dir
|
28
|
+
@repos_dir ||= home_dir.join('.homesick', 'repos').expand_path
|
29
|
+
end
|
30
|
+
|
31
|
+
def castle_dir(name)
|
32
|
+
repos_dir.join(name, 'home')
|
33
|
+
end
|
34
|
+
|
35
|
+
def check_castle_existance(name, action)
|
36
|
+
unless castle_dir(name).exist?
|
37
|
+
say_status :error,
|
38
|
+
"Could not #{action} #{name}, expected #{castle_dir(name)} exist and contain dotfiles",
|
39
|
+
:red
|
40
|
+
exit(1)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def all_castles
|
45
|
+
dirs = Pathname.glob("#{repos_dir}/**/.git", File::FNM_DOTMATCH)
|
46
|
+
# reject paths that lie inside another castle, like git submodules
|
47
|
+
dirs.reject do |dir|
|
48
|
+
dirs.any? do |other|
|
49
|
+
dir != other && dir.fnmatch(other.parent.join('*').to_s)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def inside_each_castle(&block)
|
55
|
+
all_castles.each do |git_dir|
|
56
|
+
castle = git_dir.dirname
|
57
|
+
Dir.chdir castle do # so we can call git config from the right contxt
|
58
|
+
yield castle
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def update_castle(castle)
|
64
|
+
check_castle_existance(castle, 'pull')
|
65
|
+
inside repos_dir.join(castle) do
|
66
|
+
git_pull
|
67
|
+
git_submodule_init
|
68
|
+
git_submodule_update
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def commit_castle(castle, message)
|
73
|
+
check_castle_existance(castle, 'commit')
|
74
|
+
inside repos_dir.join(castle) do
|
75
|
+
git_commit_all message: message
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
def push_castle(castle)
|
80
|
+
check_castle_existance(castle, 'push')
|
81
|
+
inside repos_dir.join(castle) do
|
82
|
+
git_push
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
def subdir_file(castle)
|
87
|
+
repos_dir.join(castle, SUBDIR_FILENAME)
|
88
|
+
end
|
89
|
+
|
90
|
+
def subdirs(castle)
|
91
|
+
subdir_filepath = subdir_file(castle)
|
92
|
+
subdirs = []
|
93
|
+
if subdir_filepath.exist?
|
94
|
+
subdir_filepath.readlines.each do |subdir|
|
95
|
+
subdirs.push(subdir.chomp)
|
96
|
+
end
|
97
|
+
end
|
98
|
+
subdirs
|
99
|
+
end
|
100
|
+
|
101
|
+
def subdir_add(castle, path)
|
102
|
+
subdir_filepath = subdir_file(castle)
|
103
|
+
File.open(subdir_filepath, 'a+') do |subdir|
|
104
|
+
subdir.puts path unless subdir.readlines.reduce(false) do |memo, line|
|
105
|
+
line.eql?("#{path}\n") || memo
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
inside castle_dir(castle) do
|
110
|
+
git_add subdir_filepath
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
def subdir_remove(castle, path)
|
115
|
+
subdir_filepath = subdir_file(castle)
|
116
|
+
if subdir_filepath.exist?
|
117
|
+
lines = IO.readlines(subdir_filepath).delete_if do |line|
|
118
|
+
line == "#{path}\n"
|
119
|
+
end
|
120
|
+
File.open(subdir_filepath, 'w') { |manfile| manfile.puts lines }
|
121
|
+
end
|
122
|
+
|
123
|
+
inside castle_dir(castle) do
|
124
|
+
git_add subdir_filepath
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
def move_dir_contents(target, dir_path)
|
129
|
+
child_files = dir_path.children
|
130
|
+
child_files.each do |child|
|
131
|
+
|
132
|
+
target_path = target.join(child.basename)
|
133
|
+
if target_path.exist?
|
134
|
+
if more_recent?(child, target_path) && target.file?
|
135
|
+
target_path.delete
|
136
|
+
mv child, target
|
137
|
+
end
|
138
|
+
next
|
139
|
+
end
|
140
|
+
|
141
|
+
mv child, target
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
def more_recent?(first, second)
|
146
|
+
first_p = Pathname.new(first)
|
147
|
+
second_p = Pathname.new(second)
|
148
|
+
first_p.mtime > second_p.mtime && !first_p.symlink?
|
149
|
+
end
|
150
|
+
|
151
|
+
def collision_accepted?(destination)
|
152
|
+
fail "Argument must be an instance of Pathname, #{destination.class.name} given" unless destination.instance_of?(Pathname)
|
153
|
+
options[:force] || shell.file_collision(destination) { source }
|
154
|
+
end
|
155
|
+
|
156
|
+
def each_file(castle, basedir, subdirs)
|
157
|
+
absolute_basedir = Pathname.new(basedir).expand_path
|
158
|
+
inside basedir do
|
159
|
+
files = Pathname.glob('{.*,*}').reject do |a|
|
160
|
+
['.', '..'].include?(a.to_s)
|
161
|
+
end
|
162
|
+
files.each do |path|
|
163
|
+
absolute_path = path.expand_path
|
164
|
+
castle_home = castle_dir(castle)
|
165
|
+
|
166
|
+
# make ignore dirs
|
167
|
+
ignore_dirs = []
|
168
|
+
subdirs.each do |subdir|
|
169
|
+
# ignore all parent of each line in subdir file
|
170
|
+
Pathname.new(subdir).ascend do |p|
|
171
|
+
ignore_dirs.push(p)
|
172
|
+
end
|
173
|
+
end
|
174
|
+
|
175
|
+
# ignore dirs written in subdir file
|
176
|
+
matched = false
|
177
|
+
ignore_dirs.uniq.each do |ignore_dir|
|
178
|
+
if absolute_path == castle_home.join(ignore_dir)
|
179
|
+
matched = true
|
180
|
+
break
|
181
|
+
end
|
182
|
+
end
|
183
|
+
next if matched
|
184
|
+
|
185
|
+
relative_dir = absolute_basedir.relative_path_from(castle_home)
|
186
|
+
home_path = home_dir.join(relative_dir).join(path)
|
187
|
+
|
188
|
+
yield(absolute_path, home_path)
|
189
|
+
end
|
190
|
+
end
|
191
|
+
end
|
192
|
+
|
193
|
+
def unsymlink_each(castle, basedir, subdirs)
|
194
|
+
each_file(castle, basedir, subdirs) do |absolute_path, home_path|
|
195
|
+
rm_link home_path
|
196
|
+
end
|
197
|
+
end
|
198
|
+
|
199
|
+
def symlink_each(castle, basedir, subdirs)
|
200
|
+
each_file(castle, basedir, subdirs) do |absolute_path, home_path|
|
201
|
+
ln_s absolute_path, home_path
|
202
|
+
end
|
203
|
+
end
|
204
|
+
|
205
|
+
def setup_castle(path)
|
206
|
+
if path.join('.gitmodules').exist?
|
207
|
+
inside path do
|
208
|
+
git_submodule_init
|
209
|
+
git_submodule_update
|
210
|
+
end
|
211
|
+
end
|
212
|
+
|
213
|
+
rc(path)
|
214
|
+
end
|
215
|
+
end
|
216
|
+
end
|
data/lib/homesick/version.rb
CHANGED
@@ -1,10 +1,12 @@
|
|
1
1
|
# -*- encoding : utf-8 -*-
|
2
|
-
|
2
|
+
module Homesick
|
3
|
+
# A representation of Homesick's version number in constants, including a
|
4
|
+
# String of the entire version number
|
3
5
|
module Version
|
4
6
|
MAJOR = 1
|
5
|
-
MINOR =
|
7
|
+
MINOR = 1
|
6
8
|
PATCH = 0
|
7
9
|
|
8
|
-
STRING =
|
10
|
+
STRING = [MAJOR, MINOR, PATCH].compact.join('.')
|
9
11
|
end
|
10
12
|
end
|
@@ -0,0 +1,787 @@
|
|
1
|
+
# -*- encoding : utf-8 -*-
|
2
|
+
require 'spec_helper'
|
3
|
+
require 'capture-output'
|
4
|
+
|
5
|
+
describe Homesick::CLI do
|
6
|
+
let(:home) { create_construct }
|
7
|
+
after { home.destroy! }
|
8
|
+
|
9
|
+
let(:castles) { home.directory('.homesick/repos') }
|
10
|
+
|
11
|
+
let(:homesick) { Homesick::CLI.new }
|
12
|
+
|
13
|
+
before { allow(homesick).to receive(:repos_dir).and_return(castles) }
|
14
|
+
|
15
|
+
describe 'clone' do
|
16
|
+
context 'has a .homesickrc' do
|
17
|
+
it 'runs the .homesickrc' do
|
18
|
+
somewhere = create_construct
|
19
|
+
local_repo = somewhere.directory('some_repo')
|
20
|
+
local_repo.file('.homesickrc') do |file|
|
21
|
+
file << "File.open(Dir.pwd + '/testing', 'w') do |f|
|
22
|
+
f.print 'testing'
|
23
|
+
end"
|
24
|
+
end
|
25
|
+
|
26
|
+
expect_any_instance_of(Thor::Shell::Basic).to receive(:yes?).with(be_a(String)).and_return(true)
|
27
|
+
expect(homesick).to receive(:say_status).with('eval', kind_of(Pathname))
|
28
|
+
homesick.clone local_repo
|
29
|
+
|
30
|
+
expect(castles.join('some_repo').join('testing')).to exist
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
context 'of a file' do
|
35
|
+
it 'symlinks existing directories' do
|
36
|
+
somewhere = create_construct
|
37
|
+
local_repo = somewhere.directory('wtf')
|
38
|
+
|
39
|
+
homesick.clone local_repo
|
40
|
+
|
41
|
+
expect(castles.join('wtf').readlink).to eq(local_repo)
|
42
|
+
end
|
43
|
+
|
44
|
+
context 'when it exists in a repo directory' do
|
45
|
+
before do
|
46
|
+
existing_castle = given_castle('existing_castle')
|
47
|
+
@existing_dir = existing_castle.parent
|
48
|
+
end
|
49
|
+
|
50
|
+
it 'raises an error' do
|
51
|
+
expect(homesick).not_to receive(:git_clone)
|
52
|
+
expect { homesick.clone @existing_dir.to_s }.to raise_error(/already cloned/i)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
it 'clones git repo like file:///path/to.git' do
|
58
|
+
bare_repo = File.join(create_construct.to_s, 'dotfiles.git')
|
59
|
+
system "git init --bare #{bare_repo} >/dev/null 2>&1"
|
60
|
+
|
61
|
+
# Capture stderr to suppress message about cloning an empty repo.
|
62
|
+
Capture.stderr do
|
63
|
+
homesick.clone "file://#{bare_repo}"
|
64
|
+
end
|
65
|
+
expect(File.directory?(File.join(home.to_s, '.homesick/repos/dotfiles')))
|
66
|
+
.to be_true
|
67
|
+
end
|
68
|
+
|
69
|
+
it 'clones git repo like git://host/path/to.git' do
|
70
|
+
expect(homesick).to receive(:git_clone)
|
71
|
+
.with('git://github.com/technicalpickles/pickled-vim.git')
|
72
|
+
|
73
|
+
homesick.clone 'git://github.com/technicalpickles/pickled-vim.git'
|
74
|
+
end
|
75
|
+
|
76
|
+
it 'clones git repo like git@host:path/to.git' do
|
77
|
+
expect(homesick).to receive(:git_clone)
|
78
|
+
.with('git@github.com:technicalpickles/pickled-vim.git')
|
79
|
+
|
80
|
+
homesick.clone 'git@github.com:technicalpickles/pickled-vim.git'
|
81
|
+
end
|
82
|
+
|
83
|
+
it 'clones git repo like http://host/path/to.git' do
|
84
|
+
expect(homesick).to receive(:git_clone)
|
85
|
+
.with('http://github.com/technicalpickles/pickled-vim.git')
|
86
|
+
|
87
|
+
homesick.clone 'http://github.com/technicalpickles/pickled-vim.git'
|
88
|
+
end
|
89
|
+
|
90
|
+
it 'clones git repo like http://host/path/to' do
|
91
|
+
expect(homesick).to receive(:git_clone)
|
92
|
+
.with('http://github.com/technicalpickles/pickled-vim')
|
93
|
+
|
94
|
+
homesick.clone 'http://github.com/technicalpickles/pickled-vim'
|
95
|
+
end
|
96
|
+
|
97
|
+
it 'clones git repo like host-alias:repos.git' do
|
98
|
+
expect(homesick).to receive(:git_clone).with('gitolite:pickled-vim.git')
|
99
|
+
|
100
|
+
homesick.clone 'gitolite:pickled-vim.git'
|
101
|
+
end
|
102
|
+
|
103
|
+
it 'throws an exception when trying to clone a malformed uri like malformed' do
|
104
|
+
expect(homesick).not_to receive(:git_clone)
|
105
|
+
expect { homesick.clone 'malformed' }.to raise_error
|
106
|
+
end
|
107
|
+
|
108
|
+
it 'clones a github repo' do
|
109
|
+
expect(homesick).to receive(:git_clone)
|
110
|
+
.with('https://github.com/wfarr/dotfiles.git',
|
111
|
+
destination: Pathname.new('dotfiles'))
|
112
|
+
|
113
|
+
homesick.clone 'wfarr/dotfiles'
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
describe 'rc' do
|
118
|
+
let(:castle) { given_castle('glencairn') }
|
119
|
+
|
120
|
+
context 'when told to do so' do
|
121
|
+
before do
|
122
|
+
expect_any_instance_of(Thor::Shell::Basic).to receive(:yes?).with(be_a(String)).and_return(true)
|
123
|
+
end
|
124
|
+
|
125
|
+
it 'executes the .homesickrc' do
|
126
|
+
castle.file('.homesickrc') do |file|
|
127
|
+
file << "File.open(Dir.pwd + '/testing', 'w') do |f|
|
128
|
+
f.print 'testing'
|
129
|
+
end"
|
130
|
+
end
|
131
|
+
|
132
|
+
expect(homesick).to receive(:say_status).with('eval', kind_of(Pathname))
|
133
|
+
homesick.rc castle
|
134
|
+
|
135
|
+
expect(castle.join('testing')).to exist
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
context 'when told not to do so' do
|
140
|
+
before do
|
141
|
+
expect_any_instance_of(Thor::Shell::Basic).to receive(:yes?).with(be_a(String)).and_return(false)
|
142
|
+
end
|
143
|
+
|
144
|
+
it 'does not execute the .homesickrc' do
|
145
|
+
castle.file('.homesickrc') do |file|
|
146
|
+
file << "File.open(Dir.pwd + '/testing', 'w') do |f|
|
147
|
+
f.print 'testing'
|
148
|
+
end"
|
149
|
+
end
|
150
|
+
|
151
|
+
expect(homesick).to receive(:say_status).with('eval skip', /not evaling.+/, :blue)
|
152
|
+
homesick.rc castle
|
153
|
+
|
154
|
+
expect(castle.join('testing')).not_to exist
|
155
|
+
end
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
describe 'link' do
|
160
|
+
let(:castle) { given_castle('glencairn') }
|
161
|
+
|
162
|
+
it 'links dotfiles from a castle to the home folder' do
|
163
|
+
dotfile = castle.file('.some_dotfile')
|
164
|
+
|
165
|
+
homesick.link('glencairn')
|
166
|
+
|
167
|
+
expect(home.join('.some_dotfile').readlink).to eq(dotfile)
|
168
|
+
end
|
169
|
+
|
170
|
+
it 'links non-dotfiles from a castle to the home folder' do
|
171
|
+
dotfile = castle.file('bin')
|
172
|
+
|
173
|
+
homesick.link('glencairn')
|
174
|
+
|
175
|
+
expect(home.join('bin').readlink).to eq(dotfile)
|
176
|
+
end
|
177
|
+
|
178
|
+
context 'when forced' do
|
179
|
+
let(:homesick) { Homesick::CLI.new [], force: true }
|
180
|
+
|
181
|
+
it 'can override symlinks to directories' do
|
182
|
+
somewhere_else = create_construct
|
183
|
+
existing_dotdir_link = home.join('.vim')
|
184
|
+
FileUtils.ln_s somewhere_else, existing_dotdir_link
|
185
|
+
|
186
|
+
dotdir = castle.directory('.vim')
|
187
|
+
|
188
|
+
homesick.link('glencairn')
|
189
|
+
|
190
|
+
expect(existing_dotdir_link.readlink).to eq(dotdir)
|
191
|
+
end
|
192
|
+
|
193
|
+
it 'can override existing directory' do
|
194
|
+
existing_dotdir = home.directory('.vim')
|
195
|
+
|
196
|
+
dotdir = castle.directory('.vim')
|
197
|
+
|
198
|
+
homesick.link('glencairn')
|
199
|
+
|
200
|
+
expect(existing_dotdir.readlink).to eq(dotdir)
|
201
|
+
end
|
202
|
+
end
|
203
|
+
|
204
|
+
context "with '.config' in .homesick_subdir" do
|
205
|
+
let(:castle) { given_castle('glencairn', ['.config']) }
|
206
|
+
it 'can symlink in sub directory' do
|
207
|
+
dotdir = castle.directory('.config')
|
208
|
+
dotfile = dotdir.file('.some_dotfile')
|
209
|
+
|
210
|
+
homesick.link('glencairn')
|
211
|
+
|
212
|
+
home_dotdir = home.join('.config')
|
213
|
+
expect(home_dotdir.symlink?).to eq(false)
|
214
|
+
expect(home_dotdir.join('.some_dotfile').readlink).to eq(dotfile)
|
215
|
+
end
|
216
|
+
end
|
217
|
+
|
218
|
+
context "with '.config/appA' in .homesick_subdir" do
|
219
|
+
let(:castle) { given_castle('glencairn', ['.config/appA']) }
|
220
|
+
it 'can symlink in nested sub directory' do
|
221
|
+
dotdir = castle.directory('.config').directory('appA')
|
222
|
+
dotfile = dotdir.file('.some_dotfile')
|
223
|
+
|
224
|
+
homesick.link('glencairn')
|
225
|
+
|
226
|
+
home_dotdir = home.join('.config').join('appA')
|
227
|
+
expect(home_dotdir.symlink?).to eq(false)
|
228
|
+
expect(home_dotdir.join('.some_dotfile').readlink).to eq(dotfile)
|
229
|
+
end
|
230
|
+
end
|
231
|
+
|
232
|
+
context "with '.config' and '.config/someapp' in .homesick_subdir" do
|
233
|
+
let(:castle) do
|
234
|
+
given_castle('glencairn', ['.config', '.config/someapp'])
|
235
|
+
end
|
236
|
+
it 'can symlink under both of .config and .config/someapp' do
|
237
|
+
config_dir = castle.directory('.config')
|
238
|
+
config_dotfile = config_dir.file('.some_dotfile')
|
239
|
+
someapp_dir = config_dir.directory('someapp')
|
240
|
+
someapp_dotfile = someapp_dir.file('.some_appfile')
|
241
|
+
|
242
|
+
homesick.link('glencairn')
|
243
|
+
|
244
|
+
home_config_dir = home.join('.config')
|
245
|
+
home_someapp_dir = home_config_dir.join('someapp')
|
246
|
+
expect(home_config_dir.symlink?).to eq(false)
|
247
|
+
expect(home_config_dir.join('.some_dotfile').readlink)
|
248
|
+
.to eq(config_dotfile)
|
249
|
+
expect(home_someapp_dir.symlink?).to eq(false)
|
250
|
+
expect(home_someapp_dir.join('.some_appfile').readlink)
|
251
|
+
.to eq(someapp_dotfile)
|
252
|
+
end
|
253
|
+
end
|
254
|
+
|
255
|
+
context 'when call with no castle name' do
|
256
|
+
let(:castle) { given_castle('dotfiles') }
|
257
|
+
it 'using default castle name: "dotfiles"' do
|
258
|
+
dotfile = castle.file('.some_dotfile')
|
259
|
+
|
260
|
+
homesick.link
|
261
|
+
|
262
|
+
expect(home.join('.some_dotfile').readlink).to eq(dotfile)
|
263
|
+
end
|
264
|
+
end
|
265
|
+
end
|
266
|
+
|
267
|
+
describe 'unlink' do
|
268
|
+
let(:castle) { given_castle('glencairn') }
|
269
|
+
|
270
|
+
it 'unlinks dotfiles in the home folder' do
|
271
|
+
castle.file('.some_dotfile')
|
272
|
+
|
273
|
+
homesick.link('glencairn')
|
274
|
+
homesick.unlink('glencairn')
|
275
|
+
|
276
|
+
expect(home.join('.some_dotfile')).not_to exist
|
277
|
+
end
|
278
|
+
|
279
|
+
it 'unlinks non-dotfiles from the home folder' do
|
280
|
+
castle.file('bin')
|
281
|
+
|
282
|
+
homesick.link('glencairn')
|
283
|
+
homesick.unlink('glencairn')
|
284
|
+
|
285
|
+
expect(home.join('bin')).not_to exist
|
286
|
+
end
|
287
|
+
|
288
|
+
context "with '.config' in .homesick_subdir" do
|
289
|
+
let(:castle) { given_castle('glencairn', ['.config']) }
|
290
|
+
|
291
|
+
it 'can unlink sub directories' do
|
292
|
+
castle.directory('.config').file('.some_dotfile')
|
293
|
+
|
294
|
+
homesick.link('glencairn')
|
295
|
+
homesick.unlink('glencairn')
|
296
|
+
|
297
|
+
home_dotdir = home.join('.config')
|
298
|
+
expect(home_dotdir).to exist
|
299
|
+
expect(home_dotdir.join('.some_dotfile')).not_to exist
|
300
|
+
end
|
301
|
+
end
|
302
|
+
|
303
|
+
context "with '.config/appA' in .homesick_subdir" do
|
304
|
+
let(:castle) { given_castle('glencairn', ['.config/appA']) }
|
305
|
+
|
306
|
+
it 'can unsymlink in nested sub directory' do
|
307
|
+
castle.directory('.config').directory('appA').file('.some_dotfile')
|
308
|
+
|
309
|
+
homesick.link('glencairn')
|
310
|
+
homesick.unlink('glencairn')
|
311
|
+
|
312
|
+
home_dotdir = home.join('.config').join('appA')
|
313
|
+
expect(home_dotdir).to exist
|
314
|
+
expect(home_dotdir.join('.some_dotfile')).not_to exist
|
315
|
+
end
|
316
|
+
end
|
317
|
+
|
318
|
+
context "with '.config' and '.config/someapp' in .homesick_subdir" do
|
319
|
+
let(:castle) do
|
320
|
+
given_castle('glencairn', ['.config', '.config/someapp'])
|
321
|
+
end
|
322
|
+
|
323
|
+
it 'can unsymlink under both of .config and .config/someapp' do
|
324
|
+
config_dir = castle.directory('.config')
|
325
|
+
config_dir.file('.some_dotfile')
|
326
|
+
config_dir.directory('someapp').file('.some_appfile')
|
327
|
+
|
328
|
+
homesick.link('glencairn')
|
329
|
+
homesick.unlink('glencairn')
|
330
|
+
|
331
|
+
home_config_dir = home.join('.config')
|
332
|
+
home_someapp_dir = home_config_dir.join('someapp')
|
333
|
+
expect(home_config_dir).to exist
|
334
|
+
expect(home_config_dir.join('.some_dotfile')).not_to exist
|
335
|
+
expect(home_someapp_dir).to exist
|
336
|
+
expect(home_someapp_dir.join('.some_appfile')).not_to exist
|
337
|
+
end
|
338
|
+
end
|
339
|
+
|
340
|
+
context 'when call with no castle name' do
|
341
|
+
let(:castle) { given_castle('dotfiles') }
|
342
|
+
|
343
|
+
it 'using default castle name: "dotfiles"' do
|
344
|
+
castle.file('.some_dotfile')
|
345
|
+
|
346
|
+
homesick.link
|
347
|
+
homesick.unlink
|
348
|
+
|
349
|
+
expect(home.join('.some_dotfile')).not_to exist
|
350
|
+
end
|
351
|
+
end
|
352
|
+
end
|
353
|
+
|
354
|
+
describe 'list' do
|
355
|
+
it 'says each castle in the castle directory' do
|
356
|
+
given_castle('zomg')
|
357
|
+
given_castle('wtf/zomg')
|
358
|
+
|
359
|
+
expect(homesick).to receive(:say_status)
|
360
|
+
.with('zomg',
|
361
|
+
'git://github.com/technicalpickles/zomg.git',
|
362
|
+
:cyan)
|
363
|
+
expect(homesick).to receive(:say_status)
|
364
|
+
.with('wtf/zomg',
|
365
|
+
'git://github.com/technicalpickles/zomg.git',
|
366
|
+
:cyan)
|
367
|
+
|
368
|
+
homesick.list
|
369
|
+
end
|
370
|
+
end
|
371
|
+
|
372
|
+
describe 'status' do
|
373
|
+
it 'says "nothing to commit" when there are no changes' do
|
374
|
+
given_castle('castle_repo')
|
375
|
+
text = Capture.stdout { homesick.status('castle_repo') }
|
376
|
+
expect(text).to match(/nothing to commit \(create\/copy files and use "git add" to track\)$/)
|
377
|
+
end
|
378
|
+
|
379
|
+
it 'says "Changes to be committed" when there are changes' do
|
380
|
+
given_castle('castle_repo')
|
381
|
+
some_rc_file = home.file '.some_rc_file'
|
382
|
+
homesick.track(some_rc_file.to_s, 'castle_repo')
|
383
|
+
text = Capture.stdout { homesick.status('castle_repo') }
|
384
|
+
expect(text).to match(
|
385
|
+
/Changes to be committed:.*new file:\s*home\/.some_rc_file/m
|
386
|
+
)
|
387
|
+
end
|
388
|
+
end
|
389
|
+
|
390
|
+
describe 'diff' do
|
391
|
+
it 'outputs an empty message when there are no changes to commit' do
|
392
|
+
given_castle('castle_repo')
|
393
|
+
some_rc_file = home.file '.some_rc_file'
|
394
|
+
homesick.track(some_rc_file.to_s, 'castle_repo')
|
395
|
+
Capture.stdout do
|
396
|
+
homesick.commit 'castle_repo', 'Adding a file to the test'
|
397
|
+
end
|
398
|
+
text = Capture.stdout { homesick.diff('castle_repo') }
|
399
|
+
expect(text).to eq('')
|
400
|
+
end
|
401
|
+
|
402
|
+
it 'outputs a diff message when there are changes to commit' do
|
403
|
+
given_castle('castle_repo')
|
404
|
+
some_rc_file = home.file '.some_rc_file'
|
405
|
+
homesick.track(some_rc_file.to_s, 'castle_repo')
|
406
|
+
Capture.stdout do
|
407
|
+
homesick.commit 'castle_repo', 'Adding a file to the test'
|
408
|
+
end
|
409
|
+
File.open(some_rc_file.to_s, 'w') do |file|
|
410
|
+
file.puts 'Some test text'
|
411
|
+
end
|
412
|
+
text = Capture.stdout { homesick.diff('castle_repo') }
|
413
|
+
expect(text).to match(/diff --git.+Some test text$/m)
|
414
|
+
end
|
415
|
+
end
|
416
|
+
|
417
|
+
describe 'show_path' do
|
418
|
+
it 'says the path of a castle' do
|
419
|
+
castle = given_castle('castle_repo')
|
420
|
+
|
421
|
+
expect(homesick).to receive(:say).with(castle.dirname)
|
422
|
+
|
423
|
+
homesick.show_path('castle_repo')
|
424
|
+
end
|
425
|
+
end
|
426
|
+
|
427
|
+
describe 'pull' do
|
428
|
+
it 'performs a pull, submodule init and update when the given castle exists' do
|
429
|
+
given_castle('castle_repo')
|
430
|
+
allow(homesick).to receive(:system).once.with('git pull --quiet')
|
431
|
+
allow(homesick).to receive(:system).once.with('git submodule --quiet init')
|
432
|
+
allow(homesick).to receive(:system).once.with('git submodule --quiet update --init --recursive >/dev/null 2>&1')
|
433
|
+
homesick.pull 'castle_repo'
|
434
|
+
end
|
435
|
+
|
436
|
+
it 'prints an error message when trying to pull a non-existant castle' do
|
437
|
+
expect(homesick).to receive('say_status').once
|
438
|
+
.with(:error,
|
439
|
+
/Could not pull castle_repo, expected .* exist and contain dotfiles/,
|
440
|
+
:red)
|
441
|
+
expect { homesick.pull 'castle_repo' }.to raise_error(SystemExit)
|
442
|
+
end
|
443
|
+
|
444
|
+
describe '--all' do
|
445
|
+
it 'pulls each castle when invoked with --all' do
|
446
|
+
given_castle('castle_repo')
|
447
|
+
given_castle('glencairn')
|
448
|
+
allow(homesick).to receive(:system).exactly(2).times.with('git pull --quiet')
|
449
|
+
allow(homesick).to receive(:system).exactly(2).times
|
450
|
+
.with('git submodule --quiet init')
|
451
|
+
allow(homesick).to receive(:system).exactly(2).times
|
452
|
+
.with('git submodule --quiet update --init --recursive >/dev/null 2>&1')
|
453
|
+
Capture.stdout do
|
454
|
+
Capture.stderr { homesick.invoke 'pull', [], all: true }
|
455
|
+
end
|
456
|
+
end
|
457
|
+
end
|
458
|
+
|
459
|
+
end
|
460
|
+
|
461
|
+
describe 'push' do
|
462
|
+
it 'performs a git push on the given castle' do
|
463
|
+
given_castle('castle_repo')
|
464
|
+
allow(homesick).to receive(:system).once.with('git push')
|
465
|
+
homesick.push 'castle_repo'
|
466
|
+
end
|
467
|
+
|
468
|
+
it 'prints an error message when trying to push a non-existant castle' do
|
469
|
+
expect(homesick).to receive('say_status').once
|
470
|
+
.with(:error,
|
471
|
+
/Could not push castle_repo, expected .* exist and contain dotfiles/,
|
472
|
+
:red)
|
473
|
+
expect { homesick.push 'castle_repo' }.to raise_error(SystemExit)
|
474
|
+
end
|
475
|
+
end
|
476
|
+
|
477
|
+
describe 'track' do
|
478
|
+
it 'moves the tracked file into the castle' do
|
479
|
+
castle = given_castle('castle_repo')
|
480
|
+
|
481
|
+
some_rc_file = home.file '.some_rc_file'
|
482
|
+
|
483
|
+
homesick.track(some_rc_file.to_s, 'castle_repo')
|
484
|
+
|
485
|
+
tracked_file = castle.join('.some_rc_file')
|
486
|
+
expect(tracked_file).to exist
|
487
|
+
|
488
|
+
expect(some_rc_file.readlink).to eq(tracked_file)
|
489
|
+
end
|
490
|
+
|
491
|
+
it 'handles files with parens' do
|
492
|
+
castle = given_castle('castle_repo')
|
493
|
+
|
494
|
+
some_rc_file = home.file 'Default (Linux).sublime-keymap'
|
495
|
+
|
496
|
+
homesick.track(some_rc_file.to_s, 'castle_repo')
|
497
|
+
|
498
|
+
tracked_file = castle.join('Default (Linux).sublime-keymap')
|
499
|
+
expect(tracked_file).to exist
|
500
|
+
|
501
|
+
expect(some_rc_file.readlink).to eq(tracked_file)
|
502
|
+
end
|
503
|
+
|
504
|
+
it 'tracks a file in nested folder structure' do
|
505
|
+
castle = given_castle('castle_repo')
|
506
|
+
|
507
|
+
some_nested_file = home.file('some/nested/file.txt')
|
508
|
+
homesick.track(some_nested_file.to_s, 'castle_repo')
|
509
|
+
|
510
|
+
tracked_file = castle.join('some/nested/file.txt')
|
511
|
+
expect(tracked_file).to exist
|
512
|
+
expect(some_nested_file.readlink).to eq(tracked_file)
|
513
|
+
end
|
514
|
+
|
515
|
+
it 'tracks a nested directory' do
|
516
|
+
castle = given_castle('castle_repo')
|
517
|
+
|
518
|
+
some_nested_dir = home.directory('some/nested/directory/')
|
519
|
+
homesick.track(some_nested_dir.to_s, 'castle_repo')
|
520
|
+
|
521
|
+
tracked_file = castle.join('some/nested/directory/')
|
522
|
+
expect(tracked_file).to exist
|
523
|
+
expect(some_nested_dir.realpath).to eq(tracked_file.realpath)
|
524
|
+
end
|
525
|
+
|
526
|
+
context 'when call with no castle name' do
|
527
|
+
it 'using default castle name: "dotfiles"' do
|
528
|
+
castle = given_castle('dotfiles')
|
529
|
+
|
530
|
+
some_rc_file = home.file '.some_rc_file'
|
531
|
+
|
532
|
+
homesick.track(some_rc_file.to_s)
|
533
|
+
|
534
|
+
tracked_file = castle.join('.some_rc_file')
|
535
|
+
expect(tracked_file).to exist
|
536
|
+
|
537
|
+
expect(some_rc_file.readlink).to eq(tracked_file)
|
538
|
+
end
|
539
|
+
end
|
540
|
+
|
541
|
+
describe 'commit' do
|
542
|
+
it 'has a commit message when the commit succeeds' do
|
543
|
+
given_castle('castle_repo')
|
544
|
+
some_rc_file = home.file '.a_random_rc_file'
|
545
|
+
homesick.track(some_rc_file.to_s, 'castle_repo')
|
546
|
+
text = Capture.stdout do
|
547
|
+
homesick.commit('castle_repo', 'Test message')
|
548
|
+
end
|
549
|
+
expect(text).to match(/^\[master \(root-commit\) \w+\] Test message/)
|
550
|
+
end
|
551
|
+
end
|
552
|
+
|
553
|
+
# Note that this is a test for the subdir_file related feature of track,
|
554
|
+
# not for the subdir_file method itself.
|
555
|
+
describe 'subdir_file' do
|
556
|
+
|
557
|
+
it 'adds the nested files parent to the subdir_file' do
|
558
|
+
castle = given_castle('castle_repo')
|
559
|
+
|
560
|
+
some_nested_file = home.file('some/nested/file.txt')
|
561
|
+
homesick.track(some_nested_file.to_s, 'castle_repo')
|
562
|
+
|
563
|
+
subdir_file = castle.parent.join(Homesick::SUBDIR_FILENAME)
|
564
|
+
File.open(subdir_file, 'r') do |f|
|
565
|
+
expect(f.readline).to eq("some/nested\n")
|
566
|
+
end
|
567
|
+
end
|
568
|
+
|
569
|
+
it 'does NOT add anything if the files parent is already listed' do
|
570
|
+
castle = given_castle('castle_repo')
|
571
|
+
|
572
|
+
some_nested_file = home.file('some/nested/file.txt')
|
573
|
+
other_nested_file = home.file('some/nested/other.txt')
|
574
|
+
homesick.track(some_nested_file.to_s, 'castle_repo')
|
575
|
+
homesick.track(other_nested_file.to_s, 'castle_repo')
|
576
|
+
|
577
|
+
subdir_file = castle.parent.join(Homesick::SUBDIR_FILENAME)
|
578
|
+
File.open(subdir_file, 'r') do |f|
|
579
|
+
expect(f.readlines.size).to eq(1)
|
580
|
+
end
|
581
|
+
end
|
582
|
+
|
583
|
+
it 'removes the parent of a tracked file from the subdir_file if the parent itself is tracked' do
|
584
|
+
castle = given_castle('castle_repo')
|
585
|
+
|
586
|
+
some_nested_file = home.file('some/nested/file.txt')
|
587
|
+
nested_parent = home.directory('some/nested/')
|
588
|
+
homesick.track(some_nested_file.to_s, 'castle_repo')
|
589
|
+
homesick.track(nested_parent.to_s, 'castle_repo')
|
590
|
+
|
591
|
+
subdir_file = castle.parent.join(Homesick::SUBDIR_FILENAME)
|
592
|
+
File.open(subdir_file, 'r') do |f|
|
593
|
+
f.each_line { |line| expect(line).not_to eq("some/nested\n") }
|
594
|
+
end
|
595
|
+
end
|
596
|
+
end
|
597
|
+
end
|
598
|
+
|
599
|
+
describe 'destroy' do
|
600
|
+
it 'removes the symlink files' do
|
601
|
+
expect_any_instance_of(Thor::Shell::Basic).to receive(:yes?).and_return('y')
|
602
|
+
given_castle('stronghold')
|
603
|
+
some_rc_file = home.file '.some_rc_file'
|
604
|
+
homesick.track(some_rc_file.to_s, 'stronghold')
|
605
|
+
homesick.destroy('stronghold')
|
606
|
+
|
607
|
+
expect(some_rc_file).not_to be_exist
|
608
|
+
end
|
609
|
+
|
610
|
+
it 'deletes the cloned repository' do
|
611
|
+
expect_any_instance_of(Thor::Shell::Basic).to receive(:yes?).and_return('y')
|
612
|
+
castle = given_castle('stronghold')
|
613
|
+
some_rc_file = home.file '.some_rc_file'
|
614
|
+
homesick.track(some_rc_file.to_s, 'stronghold')
|
615
|
+
homesick.destroy('stronghold')
|
616
|
+
|
617
|
+
expect(castle).not_to be_exist
|
618
|
+
end
|
619
|
+
end
|
620
|
+
|
621
|
+
describe 'cd' do
|
622
|
+
it "cd's to the root directory of the given castle" do
|
623
|
+
given_castle('castle_repo')
|
624
|
+
expect(homesick).to receive('inside').once.with(kind_of(Pathname)).and_yield
|
625
|
+
expect(homesick).to receive('system').once.with(ENV['SHELL'])
|
626
|
+
Capture.stdout { homesick.cd 'castle_repo' }
|
627
|
+
end
|
628
|
+
|
629
|
+
it 'returns an error message when the given castle does not exist' do
|
630
|
+
expect(homesick).to receive('say_status').once
|
631
|
+
.with(:error,
|
632
|
+
/Could not cd castle_repo, expected .* exist and contain dotfiles/,
|
633
|
+
:red)
|
634
|
+
expect { homesick.cd 'castle_repo' }.to raise_error(SystemExit)
|
635
|
+
end
|
636
|
+
end
|
637
|
+
|
638
|
+
describe 'open' do
|
639
|
+
it 'opens the system default editor in the root of the given castle' do
|
640
|
+
# Make sure calls to ENV use default values for most things...
|
641
|
+
allow(ENV).to receive(:[]).and_call_original
|
642
|
+
# Set a default value for 'EDITOR' just in case none is set
|
643
|
+
allow(ENV).to receive(:[]).with('EDITOR').and_return('vim')
|
644
|
+
given_castle 'castle_repo'
|
645
|
+
expect(homesick).to receive('inside').once.with(kind_of(Pathname)).and_yield
|
646
|
+
expect(homesick).to receive('system').once.with('vim')
|
647
|
+
Capture.stdout { homesick.open 'castle_repo' }
|
648
|
+
end
|
649
|
+
|
650
|
+
it 'returns an error message when the $EDITOR environment variable is not set' do
|
651
|
+
# Set the default editor to make sure it fails.
|
652
|
+
allow(ENV).to receive(:[]).with('EDITOR').and_return(nil)
|
653
|
+
expect(homesick).to receive('say_status').once
|
654
|
+
.with(:error,
|
655
|
+
'The $EDITOR environment variable must be set to use this command',
|
656
|
+
:red)
|
657
|
+
expect { homesick.open 'castle_repo' }.to raise_error(SystemExit)
|
658
|
+
end
|
659
|
+
|
660
|
+
it 'returns an error message when the given castle does not exist' do
|
661
|
+
# Set a default just in case none is set
|
662
|
+
allow(ENV).to receive(:[]).with('EDITOR').and_return('vim')
|
663
|
+
allow(homesick).to receive('say_status').once
|
664
|
+
.with(:error,
|
665
|
+
/Could not open castle_repo, expected .* exist and contain dotfiles/,
|
666
|
+
:red)
|
667
|
+
expect { homesick.open 'castle_repo' }.to raise_error(SystemExit)
|
668
|
+
end
|
669
|
+
end
|
670
|
+
|
671
|
+
describe 'version' do
|
672
|
+
it 'prints the current version of homesick' do
|
673
|
+
text = Capture.stdout { homesick.version }
|
674
|
+
expect(text.chomp).to match(/\d+\.\d+\.\d+/)
|
675
|
+
end
|
676
|
+
end
|
677
|
+
|
678
|
+
describe 'exec' do
|
679
|
+
before do
|
680
|
+
given_castle 'castle_repo'
|
681
|
+
end
|
682
|
+
it 'executes a single command with no arguments inside a given castle' do
|
683
|
+
allow(homesick).to receive('inside').once.with(kind_of(Pathname)).and_yield
|
684
|
+
allow(homesick).to receive('say_status').once
|
685
|
+
.with(be_a(String),
|
686
|
+
be_a(String),
|
687
|
+
:green)
|
688
|
+
allow(homesick).to receive('system').once.with('ls')
|
689
|
+
Capture.stdout { homesick.exec 'castle_repo', 'ls' }
|
690
|
+
end
|
691
|
+
|
692
|
+
it 'executes a single command with arguments inside a given castle' do
|
693
|
+
allow(homesick).to receive('inside').once.with(kind_of(Pathname)).and_yield
|
694
|
+
allow(homesick).to receive('say_status').once
|
695
|
+
.with(be_a(String),
|
696
|
+
be_a(String),
|
697
|
+
:green)
|
698
|
+
allow(homesick).to receive('system').once.with('ls -la')
|
699
|
+
Capture.stdout { homesick.exec 'castle_repo', 'ls', '-la' }
|
700
|
+
end
|
701
|
+
|
702
|
+
it 'raises an error when the method is called without a command' do
|
703
|
+
allow(homesick).to receive('say_status').once
|
704
|
+
.with(:error,
|
705
|
+
be_a(String),
|
706
|
+
:red)
|
707
|
+
allow(homesick).to receive('exit').once.with(1)
|
708
|
+
Capture.stdout { homesick.exec 'castle_repo' }
|
709
|
+
end
|
710
|
+
|
711
|
+
context 'pretend' do
|
712
|
+
it 'does not execute a command when the pretend option is passed' do
|
713
|
+
allow(homesick).to receive('say_status').once
|
714
|
+
.with(be_a(String),
|
715
|
+
match(/.*Would execute.*/),
|
716
|
+
:green)
|
717
|
+
expect(homesick).to receive('system').never
|
718
|
+
Capture.stdout { homesick.invoke 'exec', %w(castle_repo ls -la), pretend: true }
|
719
|
+
end
|
720
|
+
end
|
721
|
+
|
722
|
+
context 'quiet' do
|
723
|
+
it 'does not print status information when quiet is passed' do
|
724
|
+
expect(homesick).to receive('say_status').never
|
725
|
+
allow(homesick).to receive('system').once
|
726
|
+
.with('ls -la')
|
727
|
+
Capture.stdout { homesick.invoke 'exec', %w(castle_repo ls -la), quiet: true }
|
728
|
+
end
|
729
|
+
end
|
730
|
+
end
|
731
|
+
|
732
|
+
describe 'exec_all' do
|
733
|
+
before do
|
734
|
+
given_castle 'castle_repo'
|
735
|
+
given_castle 'another_castle_repo'
|
736
|
+
end
|
737
|
+
|
738
|
+
it 'executes a command without arguments inside the root of each cloned castle' do
|
739
|
+
allow(homesick).to receive('inside_each_castle').exactly(:twice).and_yield('castle_repo').and_yield('another_castle_repo')
|
740
|
+
allow(homesick).to receive('say_status').at_least(:once)
|
741
|
+
.with(be_a(String),
|
742
|
+
be_a(String),
|
743
|
+
:green)
|
744
|
+
allow(homesick).to receive('system').at_least(:once).with('ls')
|
745
|
+
Capture.stdout { homesick.exec_all 'ls' }
|
746
|
+
end
|
747
|
+
|
748
|
+
it 'executes a command with arguments inside the root of each cloned castle' do
|
749
|
+
allow(homesick).to receive('inside_each_castle').exactly(:twice).and_yield('castle_repo').and_yield('another_castle_repo')
|
750
|
+
allow(homesick).to receive('say_status').at_least(:once)
|
751
|
+
.with(be_a(String),
|
752
|
+
be_a(String),
|
753
|
+
:green)
|
754
|
+
allow(homesick).to receive('system').at_least(:once).with('ls -la')
|
755
|
+
Capture.stdout { homesick.exec_all 'ls', '-la' }
|
756
|
+
end
|
757
|
+
|
758
|
+
it 'raises an error when the method is called without a command' do
|
759
|
+
allow(homesick).to receive('say_status').once
|
760
|
+
.with(:error,
|
761
|
+
be_a(String),
|
762
|
+
:red)
|
763
|
+
allow(homesick).to receive('exit').once.with(1)
|
764
|
+
Capture.stdout { homesick.exec_all }
|
765
|
+
end
|
766
|
+
|
767
|
+
context 'pretend' do
|
768
|
+
it 'does not execute a command when the pretend option is passed' do
|
769
|
+
allow(homesick).to receive('say_status').at_least(:once)
|
770
|
+
.with(be_a(String),
|
771
|
+
match(/.*Would execute.*/),
|
772
|
+
:green)
|
773
|
+
expect(homesick).to receive('system').never
|
774
|
+
Capture.stdout { homesick.invoke 'exec_all', %w(ls -la), pretend: true }
|
775
|
+
end
|
776
|
+
end
|
777
|
+
|
778
|
+
context 'quiet' do
|
779
|
+
it 'does not print status information when quiet is passed' do
|
780
|
+
expect(homesick).to receive('say_status').never
|
781
|
+
allow(homesick).to receive('system').at_least(:once)
|
782
|
+
.with('ls -la')
|
783
|
+
Capture.stdout { homesick.invoke 'exec_all', %w(ls -la), quiet: true }
|
784
|
+
end
|
785
|
+
end
|
786
|
+
end
|
787
|
+
end
|