homesick 1.0.0 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,621 +0,0 @@
1
- # -*- encoding : utf-8 -*-
2
- require 'spec_helper'
3
- require 'capture-output'
4
-
5
- describe 'homesick' do
6
- let(:home) { create_construct }
7
- after { home.destroy! }
8
-
9
- let(:castles) { home.directory('.homesick/repos') }
10
-
11
- let(:homesick) { Homesick.new }
12
-
13
- before { homesick.stub(:repos_dir).and_return(castles) }
14
-
15
- describe 'clone' do
16
- context 'has a .homesickrc' do
17
- it 'should run 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') { |f| f.print 'testing' }"
22
- end
23
-
24
- expect($stdout).to receive(:print)
25
- expect($stdin).to receive(:gets).and_return('y')
26
- expect_any_instance_of(Thor::Shell::Basic).to receive(:say_status).with('eval', kind_of(Pathname))
27
- homesick.clone local_repo
28
-
29
- castles.join('some_repo').join('testing').should exist
30
- end
31
- end
32
-
33
- context 'of a file' do
34
- it 'should symlink existing directories' do
35
- somewhere = create_construct
36
- local_repo = somewhere.directory('wtf')
37
-
38
- homesick.clone local_repo
39
-
40
- castles.join('wtf').readlink.should == local_repo
41
- end
42
-
43
- context 'when it exists in a repo directory' do
44
- before do
45
- existing_castle = given_castle('existing_castle')
46
- @existing_dir = existing_castle.parent
47
- end
48
-
49
- it 'should raise an error' do
50
- homesick.should_not_receive(:git_clone)
51
- expect { homesick.clone @existing_dir.to_s }.to raise_error(/already cloned/i)
52
- end
53
- end
54
- end
55
-
56
- it 'should clone git repo like file:///path/to.git' do
57
- bare_repo = File.join(create_construct.to_s, 'dotfiles.git')
58
- system "git init --bare #{bare_repo} >/dev/null 2>&1"
59
- # Capture stderr to suppress message about cloning an empty repo.
60
- Capture.stderr do
61
- homesick.clone "file://#{bare_repo}"
62
- end
63
- File.directory?(File.join(home.to_s, '.homesick/repos/dotfiles')).should be_true
64
- end
65
-
66
- it 'should clone git repo like git://host/path/to.git' do
67
- homesick.should_receive(:git_clone).with('git://github.com/technicalpickles/pickled-vim.git')
68
-
69
- homesick.clone 'git://github.com/technicalpickles/pickled-vim.git'
70
- end
71
-
72
- it 'should clone git repo like git@host:path/to.git' do
73
- homesick.should_receive(:git_clone).with('git@github.com:technicalpickles/pickled-vim.git')
74
-
75
- homesick.clone 'git@github.com:technicalpickles/pickled-vim.git'
76
- end
77
-
78
- it 'should clone git repo like http://host/path/to.git' do
79
- homesick.should_receive(:git_clone).with('http://github.com/technicalpickles/pickled-vim.git')
80
-
81
- homesick.clone 'http://github.com/technicalpickles/pickled-vim.git'
82
- end
83
-
84
- it 'should clone git repo like http://host/path/to' do
85
- homesick.should_receive(:git_clone).with('http://github.com/technicalpickles/pickled-vim')
86
-
87
- homesick.clone 'http://github.com/technicalpickles/pickled-vim'
88
- end
89
-
90
- it 'should clone git repo like host-alias:repos.git' do
91
- homesick.should_receive(:git_clone).with('gitolite:pickled-vim.git')
92
-
93
- homesick.clone 'gitolite:pickled-vim.git'
94
- end
95
-
96
- it 'should throw an exception when trying to clone a malformed uri like malformed' do
97
- homesick.should_not_receive(:git_clone)
98
- expect { homesick.clone 'malformed' }.to raise_error
99
- end
100
-
101
- it 'should clone a github repo' do
102
- homesick.should_receive(:git_clone).with('https://github.com/wfarr/dotfiles.git', :destination => Pathname.new('dotfiles'))
103
-
104
- homesick.clone 'wfarr/dotfiles'
105
- end
106
- end
107
-
108
- describe 'rc' do
109
- let(:castle) { given_castle('glencairn') }
110
-
111
- context 'when told to do so' do
112
- before do
113
- expect($stdout).to receive(:print)
114
- expect($stdin).to receive(:gets).and_return('y')
115
- end
116
-
117
- it 'executes the .homesickrc' do
118
- castle.file('.homesickrc') do |file|
119
- file << "File.open(Dir.pwd + '/testing', 'w') { |f| f.print 'testing' }"
120
- end
121
-
122
- expect_any_instance_of(Thor::Shell::Basic).to receive(:say_status).with('eval', kind_of(Pathname))
123
- homesick.rc castle
124
-
125
- castle.join('testing').should exist
126
- end
127
- end
128
-
129
- context 'when told not to do so' do
130
- before do
131
- expect($stdout).to receive(:print)
132
- expect($stdin).to receive(:gets).and_return('n')
133
- end
134
-
135
- it 'does not execute the .homesickrc' do
136
- castle.file('.homesickrc') do |file|
137
- file << "File.open(Dir.pwd + '/testing', 'w') { |f| f.print 'testing' }"
138
- end
139
-
140
- expect_any_instance_of(Thor::Shell::Basic).to receive(:say_status).with('eval skip', /not evaling.+/, :blue)
141
- homesick.rc castle
142
-
143
- castle.join('testing').should_not exist
144
- end
145
- end
146
- end
147
-
148
- describe 'symlink' do
149
- let(:castle) { given_castle('glencairn') }
150
-
151
- it 'links dotfiles from a castle to the home folder' do
152
- dotfile = castle.file('.some_dotfile')
153
-
154
- homesick.symlink('glencairn')
155
-
156
- home.join('.some_dotfile').readlink.should == dotfile
157
- end
158
-
159
- it 'links non-dotfiles from a castle to the home folder' do
160
- dotfile = castle.file('bin')
161
-
162
- homesick.symlink('glencairn')
163
-
164
- home.join('bin').readlink.should == dotfile
165
- end
166
-
167
- context 'when forced' do
168
- let(:homesick) { Homesick.new [], :force => true }
169
-
170
- it 'can override symlinks to directories' do
171
- somewhere_else = create_construct
172
- existing_dotdir_link = home.join('.vim')
173
- FileUtils.ln_s somewhere_else, existing_dotdir_link
174
-
175
- dotdir = castle.directory('.vim')
176
-
177
- homesick.symlink('glencairn')
178
-
179
- existing_dotdir_link.readlink.should == dotdir
180
- end
181
-
182
- it 'can override existing directory' do
183
- existing_dotdir = home.directory('.vim')
184
-
185
- dotdir = castle.directory('.vim')
186
-
187
- homesick.symlink('glencairn')
188
-
189
- existing_dotdir.readlink.should == dotdir
190
- end
191
- end
192
-
193
- context "with '.config' in .homesick_subdir" do
194
- let(:castle) { given_castle('glencairn', ['.config']) }
195
- it 'can symlink in sub directory' do
196
- dotdir = castle.directory('.config')
197
- dotfile = dotdir.file('.some_dotfile')
198
-
199
- homesick.symlink('glencairn')
200
-
201
- home_dotdir = home.join('.config')
202
- home_dotdir.symlink?.should be == false
203
- home_dotdir.join('.some_dotfile').readlink.should == dotfile
204
- end
205
- end
206
-
207
- context "with '.config/appA' in .homesick_subdir" do
208
- let(:castle) { given_castle('glencairn', ['.config/appA']) }
209
- it 'can symlink in nested sub directory' do
210
- dotdir = castle.directory('.config').directory('appA')
211
- dotfile = dotdir.file('.some_dotfile')
212
-
213
- homesick.symlink('glencairn')
214
-
215
- home_dotdir = home.join('.config').join('appA')
216
- home_dotdir.symlink?.should be == false
217
- home_dotdir.join('.some_dotfile').readlink.should == dotfile
218
- end
219
- end
220
-
221
- context "with '.config' and '.config/someapp' in .homesick_subdir" do
222
- let(:castle) { given_castle('glencairn', ['.config', '.config/someapp']) }
223
- it 'can symlink under both of .config and .config/someapp' do
224
- config_dir = castle.directory('.config')
225
- config_dotfile = config_dir.file('.some_dotfile')
226
- someapp_dir = config_dir.directory('someapp')
227
- someapp_dotfile = someapp_dir.file('.some_appfile')
228
-
229
- homesick.symlink('glencairn')
230
-
231
- home_config_dir = home.join('.config')
232
- home_someapp_dir = home_config_dir.join('someapp')
233
- home_config_dir.symlink?.should be == false
234
- home_config_dir.join('.some_dotfile').readlink.should be == config_dotfile
235
- home_someapp_dir.symlink?.should be == false
236
- home_someapp_dir.join('.some_appfile').readlink.should == someapp_dotfile
237
- end
238
- end
239
-
240
- context "when call with no castle name" do
241
- let(:castle) { given_castle('dotfiles') }
242
- it 'using default castle name: "dotfiles"' do
243
- dotfile = castle.file('.some_dotfile')
244
-
245
- homesick.symlink
246
-
247
- home.join('.some_dotfile').readlink.should == dotfile
248
- end
249
- end
250
- end
251
-
252
- describe 'unlink' do
253
- let(:castle) { given_castle('glencairn') }
254
-
255
- it 'unlinks dotfiles in the home folder' do
256
- castle.file('.some_dotfile')
257
-
258
- homesick.symlink('glencairn')
259
- homesick.unlink('glencairn')
260
-
261
- home.join('.some_dotfile').should_not exist
262
- end
263
-
264
- it 'unlinks non-dotfiles from the home folder' do
265
- castle.file('bin')
266
-
267
- homesick.symlink('glencairn')
268
- homesick.unlink('glencairn')
269
-
270
- home.join('bin').should_not exist
271
- end
272
-
273
- context "with '.config' in .homesick_subdir" do
274
- let(:castle) { given_castle('glencairn', ['.config']) }
275
-
276
- it 'can unlink sub directories' do
277
- castle.directory('.config').file('.some_dotfile')
278
-
279
- homesick.symlink('glencairn')
280
- homesick.unlink('glencairn')
281
-
282
- home_dotdir = home.join('.config')
283
- home_dotdir.should exist
284
- home_dotdir.join('.some_dotfile').should_not exist
285
- end
286
- end
287
-
288
- context "with '.config/appA' in .homesick_subdir" do
289
- let(:castle) { given_castle('glencairn', ['.config/appA']) }
290
-
291
- it 'can unsymlink in nested sub directory' do
292
- castle.directory('.config').directory('appA').file('.some_dotfile')
293
-
294
- homesick.symlink('glencairn')
295
- homesick.unlink('glencairn')
296
-
297
- home_dotdir = home.join('.config').join('appA')
298
- home_dotdir.should exist
299
- home_dotdir.join('.some_dotfile').should_not exist
300
- end
301
- end
302
-
303
- context "with '.config' and '.config/someapp' in .homesick_subdir" do
304
- let(:castle) { given_castle('glencairn', ['.config', '.config/someapp']) }
305
-
306
- it 'can unsymlink under both of .config and .config/someapp' do
307
- config_dir = castle.directory('.config')
308
- config_dir.file('.some_dotfile')
309
- config_dir.directory('someapp').file('.some_appfile')
310
-
311
- homesick.symlink('glencairn')
312
- homesick.unlink('glencairn')
313
-
314
- home_config_dir = home.join('.config')
315
- home_someapp_dir = home_config_dir.join('someapp')
316
- home_config_dir.should exist
317
- home_config_dir.join('.some_dotfile').should_not exist
318
- home_someapp_dir.should exist
319
- home_someapp_dir.join('.some_appfile').should_not exist
320
- end
321
- end
322
-
323
- context "when call with no castle name" do
324
- let(:castle) { given_castle('dotfiles') }
325
-
326
- it 'using default castle name: "dotfiles"' do
327
- castle.file('.some_dotfile')
328
-
329
- homesick.symlink
330
- homesick.unlink
331
-
332
- home.join('.some_dotfile').should_not exist
333
- end
334
- end
335
- end
336
-
337
- describe 'list' do
338
- it 'should say each castle in the castle directory' do
339
- given_castle('zomg')
340
- given_castle('wtf/zomg')
341
-
342
- homesick.should_receive(:say_status).with('zomg', 'git://github.com/technicalpickles/zomg.git', :cyan)
343
- homesick.should_receive(:say_status).with('wtf/zomg', 'git://github.com/technicalpickles/zomg.git', :cyan)
344
-
345
- homesick.list
346
- end
347
- end
348
-
349
- describe 'status' do
350
- it 'should say "nothing to commit" when there are no changes' do
351
- given_castle('castle_repo')
352
- text = Capture.stdout { homesick.status('castle_repo') }
353
- text.should =~ /nothing to commit \(create\/copy files and use "git add" to track\)$/
354
- end
355
-
356
- it 'should say "Changes to be committed" when there are changes' do
357
- given_castle('castle_repo')
358
- some_rc_file = home.file '.some_rc_file'
359
- homesick.track(some_rc_file.to_s, 'castle_repo')
360
- text = Capture.stdout { homesick.status('castle_repo') }
361
- text.should =~ /Changes to be committed:.*new file:\s*home\/.some_rc_file/m
362
- end
363
- end
364
-
365
- describe 'diff' do
366
- it 'should output an empty message when there are no changes to commit' do
367
- given_castle('castle_repo')
368
- some_rc_file = home.file '.some_rc_file'
369
- homesick.track(some_rc_file.to_s, 'castle_repo')
370
- Capture.stdout { homesick.commit 'castle_repo', 'Adding a file to the test' }
371
- text = Capture.stdout { homesick.diff('castle_repo') }
372
- text.should eq('')
373
- end
374
-
375
- it 'should output a diff message when there are changes to commit' do
376
- given_castle('castle_repo')
377
- some_rc_file = home.file '.some_rc_file'
378
- homesick.track(some_rc_file.to_s, 'castle_repo')
379
- Capture.stdout { homesick.commit 'castle_repo', 'Adding a file to the test' }
380
- File.open(some_rc_file.to_s, 'w') do |file|
381
- file.puts "Some test text"
382
- end
383
- text = Capture.stdout { homesick.diff('castle_repo') }
384
- text.should =~ /diff --git.+Some test text$/m
385
- end
386
- end
387
-
388
- describe 'show_path' do
389
- it 'should say the path of a castle' do
390
- castle = given_castle('castle_repo')
391
-
392
- homesick.should_receive(:say).with(castle.dirname)
393
-
394
- homesick.show_path('castle_repo')
395
- end
396
- end
397
-
398
- describe 'pull' do
399
- it 'should perform a pull, submodule init and update when the given castle exists' do
400
- given_castle('castle_repo')
401
- homesick.stub(:system).once.with('git pull --quiet')
402
- homesick.stub(:system).once.with('git submodule --quiet init')
403
- homesick.stub(:system).once.with('git submodule --quiet update --init --recursive >/dev/null 2>&1')
404
- homesick.pull 'castle_repo'
405
- end
406
-
407
- it 'should print an error message when trying to pull a non-existant castle' do
408
- homesick.should_receive("say_status").once.with(:error, /Could not pull castle_repo, expected \/tmp\/construct_container.* exist and contain dotfiles/, :red)
409
- expect { homesick.pull "castle_repo" }.to raise_error(SystemExit)
410
- end
411
-
412
- describe '--all' do
413
- it 'should pull each castle when invoked with --all' do
414
- given_castle('castle_repo')
415
- given_castle('glencairn')
416
- homesick.stub(:system).exactly(2).times.with('git pull --quiet')
417
- homesick.stub(:system).exactly(2).times.with('git submodule --quiet init')
418
- homesick.stub(:system).exactly(2).times.with('git submodule --quiet update --init --recursive >/dev/null 2>&1')
419
- Capture.stdout { Capture.stderr { homesick.invoke 'pull', [], all: true } }
420
- end
421
- end
422
-
423
- end
424
-
425
- describe 'push' do
426
- it 'should perform a git push on the given castle' do
427
- given_castle('castle_repo')
428
- homesick.stub(:system).once.with('git push')
429
- homesick.push 'castle_repo'
430
- end
431
-
432
- it 'should print an error message when trying to push a non-existant castle' do
433
- homesick.should_receive("say_status").once.with(:error, /Could not push castle_repo, expected \/tmp\/construct_container.* exist and contain dotfiles/, :red)
434
- expect { homesick.push "castle_repo" }.to raise_error(SystemExit)
435
- end
436
- end
437
-
438
- describe 'track' do
439
- it 'should move the tracked file into the castle' do
440
- castle = given_castle('castle_repo')
441
-
442
- some_rc_file = home.file '.some_rc_file'
443
-
444
- homesick.track(some_rc_file.to_s, 'castle_repo')
445
-
446
- tracked_file = castle.join('.some_rc_file')
447
- tracked_file.should exist
448
-
449
- some_rc_file.readlink.should == tracked_file
450
- end
451
-
452
- it 'should handle files with parens' do
453
- castle = given_castle('castle_repo')
454
-
455
- some_rc_file = home.file 'Default (Linux).sublime-keymap'
456
-
457
- homesick.track(some_rc_file.to_s, 'castle_repo')
458
-
459
- tracked_file = castle.join('Default (Linux).sublime-keymap')
460
- tracked_file.should exist
461
-
462
- some_rc_file.readlink.should == tracked_file
463
- end
464
-
465
- it 'should track a file in nested folder structure' do
466
- castle = given_castle('castle_repo')
467
-
468
- some_nested_file = home.file('some/nested/file.txt')
469
- homesick.track(some_nested_file.to_s, 'castle_repo')
470
-
471
- tracked_file = castle.join('some/nested/file.txt')
472
- tracked_file.should exist
473
- some_nested_file.readlink.should == tracked_file
474
- end
475
-
476
- it 'should track a nested directory' do
477
- castle = given_castle('castle_repo')
478
-
479
- some_nested_dir = home.directory('some/nested/directory/')
480
- homesick.track(some_nested_dir.to_s, 'castle_repo')
481
-
482
- tracked_file = castle.join('some/nested/directory/')
483
- tracked_file.should exist
484
- some_nested_dir.realpath.should == tracked_file.realpath
485
- end
486
-
487
- context "when call with no castle name" do
488
- it 'using default castle name: "dotfiles"' do
489
- castle = given_castle('dotfiles')
490
-
491
- some_rc_file = home.file '.some_rc_file'
492
-
493
- homesick.track(some_rc_file.to_s)
494
-
495
- tracked_file = castle.join('.some_rc_file')
496
- tracked_file.should exist
497
-
498
- some_rc_file.readlink.should == tracked_file
499
- end
500
- end
501
-
502
- describe 'commit' do
503
- it 'should have a commit message when the commit succeeds' do
504
- given_castle('castle_repo')
505
- some_rc_file = home.file '.a_random_rc_file'
506
- homesick.track(some_rc_file.to_s, 'castle_repo')
507
- text = Capture.stdout { homesick.commit('castle_repo', 'Test message') }
508
- text.should =~ /^\[master \(root-commit\) \w+\] Test message/
509
- end
510
- end
511
-
512
- describe 'subdir_file' do
513
-
514
- it 'should add the nested files parent to the subdir_file' do
515
- castle = given_castle('castle_repo')
516
-
517
- some_nested_file = home.file('some/nested/file.txt')
518
- homesick.track(some_nested_file.to_s, 'castle_repo')
519
-
520
- subdir_file = castle.parent.join(Homesick::SUBDIR_FILENAME)
521
- File.open(subdir_file, 'r') do |f|
522
- f.readline.should == "some/nested\n"
523
- end
524
- end
525
-
526
- it 'should NOT add anything if the files parent is already listed' do
527
- castle = given_castle('castle_repo')
528
-
529
- some_nested_file = home.file('some/nested/file.txt')
530
- other_nested_file = home.file('some/nested/other.txt')
531
- homesick.track(some_nested_file.to_s, 'castle_repo')
532
- homesick.track(other_nested_file.to_s, 'castle_repo')
533
-
534
- subdir_file = castle.parent.join(Homesick::SUBDIR_FILENAME)
535
- File.open(subdir_file, 'r') do |f|
536
- f.readlines.size.should == 1
537
- end
538
- end
539
-
540
- it 'should remove the parent of a tracked file from the subdir_file if the parent itself is tracked' do
541
- castle = given_castle('castle_repo')
542
-
543
- some_nested_file = home.file('some/nested/file.txt')
544
- nested_parent = home.directory('some/nested/')
545
- homesick.track(some_nested_file.to_s, 'castle_repo')
546
- homesick.track(nested_parent.to_s, 'castle_repo')
547
-
548
- subdir_file = castle.parent.join(Homesick::SUBDIR_FILENAME)
549
- File.open(subdir_file, 'r') do |f|
550
- f.each_line { |line| line.should_not == "some/nested\n" }
551
- end
552
- end
553
- end
554
- end
555
-
556
- describe "destroy" do
557
- it "removes the symlink files" do
558
- expect_any_instance_of(Thor::Shell::Basic).to receive(:yes?).and_return('y')
559
- given_castle("stronghold")
560
- some_rc_file = home.file '.some_rc_file'
561
- homesick.track(some_rc_file.to_s, "stronghold")
562
- homesick.destroy('stronghold')
563
-
564
- some_rc_file.should_not be_exist
565
- end
566
-
567
- it "deletes the cloned repository" do
568
- expect_any_instance_of(Thor::Shell::Basic).to receive(:yes?).and_return('y')
569
- castle = given_castle("stronghold")
570
- some_rc_file = home.file '.some_rc_file'
571
- homesick.track(some_rc_file.to_s, "stronghold")
572
- homesick.destroy('stronghold')
573
-
574
- castle.should_not be_exist
575
- end
576
- end
577
-
578
- describe "cd" do
579
- it "cd's to the root directory of the given castle" do
580
- given_castle('castle_repo')
581
- homesick.should_receive("inside").once.with(kind_of(Pathname)).and_yield
582
- homesick.should_receive("system").once.with(ENV["SHELL"])
583
- Capture.stdout { homesick.cd 'castle_repo' }
584
- end
585
-
586
- it "returns an error message when the given castle does not exist" do
587
- homesick.should_receive("say_status").once.with(:error, /Could not cd castle_repo, expected \/tmp\/construct_container.* exist and contain dotfiles/, :red)
588
- expect { homesick.cd "castle_repo" }.to raise_error(SystemExit)
589
- end
590
- end
591
-
592
- describe "open" do
593
- it "opens the system default editor in the root of the given castle" do
594
- ENV.stub(:[]).and_call_original # Make sure calls to ENV use default values for most things...
595
- ENV.stub(:[]).with('EDITOR').and_return('vim') # Set a default value for 'EDITOR' just in case none is set
596
- given_castle 'castle_repo'
597
- homesick.should_receive("inside").once.with(kind_of(Pathname)).and_yield
598
- homesick.should_receive("system").once.with('vim')
599
- Capture.stdout { homesick.open 'castle_repo' }
600
- end
601
-
602
- it "returns an error message when the $EDITOR environment variable is not set" do
603
- ENV.stub(:[]).with('EDITOR').and_return(nil) # Set the default editor to make sure it fails.
604
- homesick.should_receive("say_status").once.with(:error, "The $EDITOR environment variable must be set to use this command", :red)
605
- expect { homesick.open "castle_repo" }.to raise_error(SystemExit)
606
- end
607
-
608
- it "returns an error message when the given castle does not exist" do
609
- ENV.stub(:[]).with('EDITOR').and_return('vim') # Set a default just in case none is set
610
- homesick.should_receive("say_status").once.with(:error, /Could not open castle_repo, expected \/tmp\/construct_container.* exist and contain dotfiles/, :red)
611
- expect { homesick.open "castle_repo" }.to raise_error(SystemExit)
612
- end
613
- end
614
-
615
- describe 'version' do
616
- it 'should print the current version of homesick' do
617
- text = Capture.stdout { homesick.version }
618
- text.chomp.should =~ /\d+\.\d+\.\d+/
619
- end
620
- end
621
- end