dotty 0.0.1
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.
- data/.gitignore +5 -0
- data/Gemfile +4 -0
- data/README.md +110 -0
- data/Rakefile +2 -0
- data/bin/dotty +5 -0
- data/dotty.gemspec +27 -0
- data/lib/dotty/app.rb +150 -0
- data/lib/dotty/helpers.rb +19 -0
- data/lib/dotty/profile.rb +57 -0
- data/lib/dotty/repository.rb +141 -0
- data/lib/dotty/repository_actions.rb +110 -0
- data/lib/dotty/version.rb +3 -0
- data/lib/dotty.rb +18 -0
- data/spec/app_spec.rb +328 -0
- data/spec/profile_spec.rb +188 -0
- data/spec/repository_actions_spec.rb +204 -0
- data/spec/repository_spec.rb +303 -0
- data/spec/spec_helper.rb +62 -0
- data/spec/support/shared_contexts.rb +61 -0
- data/templates/README.md +41 -0
- metadata +124 -0
@@ -0,0 +1,204 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
2
|
+
|
3
|
+
describe Dotty::RepositoryActions do
|
4
|
+
|
5
|
+
describe "#create" do
|
6
|
+
before do
|
7
|
+
@repo = Dotty::Repository.new('repo', 'git://github.com/user/repo.git')
|
8
|
+
suppress_output do
|
9
|
+
subject.create @repo
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
it "should initialize an empty git repository" do
|
14
|
+
Dir.exist?(File.join @repo.local_path, '.git').should be_true
|
15
|
+
end
|
16
|
+
|
17
|
+
it "should create a git remote called origin with the specified url" do
|
18
|
+
output = nil
|
19
|
+
suppress_output do
|
20
|
+
output = `cd #{@repo.local_path}; git remote -v`
|
21
|
+
end
|
22
|
+
output.should == "origin\tgit://github.com/user/repo.git (fetch)\norigin\tgit://github.com/user/repo.git (push)\n"
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
describe "#checkout" do
|
27
|
+
it "should check out the git repository" do
|
28
|
+
@repo = Dotty::Repository.new('repo', 'url')
|
29
|
+
subject.stub!(:run)
|
30
|
+
subject.should_receive(:run).once.with('git clone url /tmp/dotty-testing-root/default/repo')
|
31
|
+
suppress_output do
|
32
|
+
subject.checkout @repo
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
it "should update the fetch the repository submodules" do
|
37
|
+
@repo = Dotty::Repository.new('repo', 'url')
|
38
|
+
subject.stub!(:run)
|
39
|
+
subject.should_receive(:run).once.with('git submodule update --init')
|
40
|
+
suppress_output do
|
41
|
+
subject.checkout @repo
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
describe "#destroy" do
|
47
|
+
include_context "bootstrapped repository"
|
48
|
+
|
49
|
+
it "should remove the local repository directory" do
|
50
|
+
suppress_output do
|
51
|
+
@actions.invoke :destroy, [@repo]
|
52
|
+
end
|
53
|
+
Dir.exist?(@repo.local_path).should be_false
|
54
|
+
end
|
55
|
+
|
56
|
+
it "should invoke #implode" do
|
57
|
+
@actions.stub!(:implode)
|
58
|
+
@actions.should_receive(:implode).with(@repo)
|
59
|
+
suppress_output do
|
60
|
+
@actions.destroy @repo
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
describe "#implode" do
|
66
|
+
include_context "bootstrapped repository"
|
67
|
+
|
68
|
+
it "should remove symlinks defined in dotty-symlinks.yml" do
|
69
|
+
suppress_output do
|
70
|
+
@actions.implode(@repo)
|
71
|
+
end
|
72
|
+
File.symlink?(File.join Dotty::RepositoryActions::USER_HOME, 'aa').should be_false
|
73
|
+
File.symlink?(File.join Dotty::RepositoryActions::USER_HOME, 'bb').should be_false
|
74
|
+
end
|
75
|
+
|
76
|
+
it "should try to run repository specific implode action if dotty-repository.thor exists" do
|
77
|
+
%x(touch #{@repo.local_path}/dotty-repository.thor)
|
78
|
+
@actions.stub!(:run)
|
79
|
+
@actions.should_receive(:run).once.with('thor dotty_repository:implode')
|
80
|
+
suppress_output do
|
81
|
+
@actions.implode(@repo)
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
it "should not try to run a repository specific implode action if dotty-repository.thor does not exist" do
|
86
|
+
@actions.stub!(:run)
|
87
|
+
@actions.should_not_receive(:run).with('thor dotty_repository:implode')
|
88
|
+
suppress_output do
|
89
|
+
@actions.implode(@repo)
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
end
|
94
|
+
|
95
|
+
describe "#bootstrap" do
|
96
|
+
include_context "added repository"
|
97
|
+
|
98
|
+
it "should create symlinks returned from repository#symlinks" do
|
99
|
+
@repo.stub!(:symlinks).and_return({ 'a' => '.a', 'b' => '.b' })
|
100
|
+
suppress_output do
|
101
|
+
@actions.bootstrap(@repo)
|
102
|
+
end
|
103
|
+
File.symlink?(File.join Dotty::RepositoryActions::USER_HOME, '.b').should be_true
|
104
|
+
File.symlink?(File.join Dotty::RepositoryActions::USER_HOME, '.a').should be_true
|
105
|
+
end
|
106
|
+
|
107
|
+
it "should make directories for the symlinks if needed" do
|
108
|
+
@repo.stub!(:symlinks).and_return({ 'b' => 'other/dir/b' })
|
109
|
+
suppress_output do
|
110
|
+
@actions.bootstrap(@repo)
|
111
|
+
end
|
112
|
+
File.directory?(File.join Dotty::RepositoryActions::USER_HOME, 'other/dir').should be_true
|
113
|
+
File.symlink?(File.join Dotty::RepositoryActions::USER_HOME, 'other/dir/b').should be_true
|
114
|
+
end
|
115
|
+
|
116
|
+
it "should try to run repository specific bootstrap action if dotty-repository.thor exists" do
|
117
|
+
%x(touch #{@repo.local_path}/dotty-repository.thor)
|
118
|
+
@actions.stub!(:run)
|
119
|
+
@actions.should_receive(:run).once.with('thor dotty_repository:bootstrap')
|
120
|
+
suppress_output do
|
121
|
+
@actions.bootstrap(@repo)
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
it "should not try to run a repository specific bootstrap action if dotty-repository.thor does not exist" do
|
126
|
+
@actions.stub!(:run)
|
127
|
+
@actions.should_not_receive(:run).with('thor dotty_repository:bootstrap')
|
128
|
+
suppress_output do
|
129
|
+
@actions.bootstrap(@repo)
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
describe "#update" do
|
135
|
+
include_context "bootstrapped repository"
|
136
|
+
|
137
|
+
it "should run git commands to update repo" do
|
138
|
+
@actions.stub!(:run)
|
139
|
+
@actions.should_receive(:run).once.with('git fetch && git pull && git submodule update --init')
|
140
|
+
suppress_output do
|
141
|
+
@actions.update @repo
|
142
|
+
end
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
describe "#update_submodules" do
|
147
|
+
include_context "bootstrapped repository"
|
148
|
+
|
149
|
+
before do
|
150
|
+
# TODO: Find a better way of testing thor invocations with options
|
151
|
+
@default_method_options = { :commit => true, :commit_message => 'Updated submodules' }
|
152
|
+
@actions.stub!(:options).and_return(@default_method_options)
|
153
|
+
@actions.stub!(:run).and_return("")
|
154
|
+
end
|
155
|
+
|
156
|
+
it "should by default update pull submodules and commit changes to the dotty repository" do
|
157
|
+
@actions.should_receive(:run).once.with("git submodule update --init && git submodule foreach git pull origin master && git commit -am 'Updated submodules'")
|
158
|
+
suppress_output do
|
159
|
+
@actions.update_submodules @repo
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
163
|
+
it "should not commit if commit option is false" do
|
164
|
+
@actions.stub!(:options).and_return @default_method_options.merge(:commit => false)
|
165
|
+
@actions.should_receive(:run).once.with('git submodule update --init && git submodule foreach git pull origin master')
|
166
|
+
suppress_output do
|
167
|
+
@actions.update_submodules @repo
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
it "should push if push option is true" do
|
172
|
+
@actions.stub!(:options).and_return @default_method_options.merge(:push => true)
|
173
|
+
@actions.should_receive(:run).once.with(/git push/)
|
174
|
+
suppress_output do
|
175
|
+
@actions.update_submodules @repo
|
176
|
+
end
|
177
|
+
end
|
178
|
+
|
179
|
+
it "should raise error if the repository is not in a clean state" do
|
180
|
+
@actions.stub!(:run).and_return("?? dirty")
|
181
|
+
expect {
|
182
|
+
suppress_output { @actions.update_submodules @repo }
|
183
|
+
}.to raise_error Dotty::Error, "Repository 'repo' is not in a clean state - cannot commit updated submodules"
|
184
|
+
end
|
185
|
+
|
186
|
+
it "should not raise error if the repository is not in a clean state but --no-commit is supplied" do
|
187
|
+
@actions.stub!(:run).and_return("?? dirty")
|
188
|
+
expect {
|
189
|
+
suppress_output { @actions.invoke :update_submodules, [@repo], :commit => false }
|
190
|
+
}.to_not raise_error Dotty::Error, "Repository 'repo' is not in a clean state - cannot commit updated submodules"
|
191
|
+
end
|
192
|
+
|
193
|
+
it "should not raise an error when repository is not in clean state but --ignore_dirty is given" do
|
194
|
+
@actions.stub!(:run).and_return("?? dirty")
|
195
|
+
@actions.stub!(:options).and_return @default_method_options.merge(:ignoredirty => true)
|
196
|
+
expect {
|
197
|
+
suppress_output { @actions.update_submodules @repo }
|
198
|
+
}.to_not raise_error Dotty::Error, "Repository 'repo' is not in a clean state - cannot commit updated submodules"
|
199
|
+
end
|
200
|
+
|
201
|
+
end
|
202
|
+
|
203
|
+
end
|
204
|
+
|
@@ -0,0 +1,303 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
2
|
+
|
3
|
+
describe Dotty::Repository do
|
4
|
+
|
5
|
+
describe ".add_repository" do
|
6
|
+
include_context "profile data"
|
7
|
+
|
8
|
+
it "should add it to the repositories list" do
|
9
|
+
suppress_output do
|
10
|
+
Dotty::Repository.add_repository("new_repo", "git://github.com/user/repo1.git")
|
11
|
+
end
|
12
|
+
Dotty::Repository.repositories.size.should == 3
|
13
|
+
end
|
14
|
+
|
15
|
+
it "should return the new repository" do
|
16
|
+
suppress_output do
|
17
|
+
@repo = Dotty::Repository.add_repository("new_repo", "git://github.com/user/repo1.git")
|
18
|
+
end
|
19
|
+
@repo.should be_kind_of Dotty::Repository
|
20
|
+
end
|
21
|
+
|
22
|
+
it "should invoke Dotty::Profile.write_yaml" do
|
23
|
+
Dotty::Profile.should_receive(:write_yaml)
|
24
|
+
Dotty::Repository.add_repository("new_repo", "git://github.com/user/repo1.git")
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
describe ".add_existing_repository" do
|
29
|
+
it "should trigger .add_repository" do
|
30
|
+
new_repo = Dotty::Repository.new('new_repo_name', 'url')
|
31
|
+
Dotty::Repository.should_receive(:add_repository).once.with('new_repo_name', 'url').and_return(new_repo)
|
32
|
+
suppress_output do
|
33
|
+
@repo = Dotty::Repository.add_existing_repository('new_repo_name', 'url')
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
it "should trigger the repository checkout action" do
|
38
|
+
Dotty::Repository.actions.should_receive(:checkout).once.with(instance_of Dotty::Repository)
|
39
|
+
suppress_output do
|
40
|
+
@repo = Dotty::Repository.add_existing_repository("existing_repo", "url")
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
it "should trigger the bootstrap repository action" do
|
45
|
+
Dotty::Repository.actions.stub!(:bootstrap)
|
46
|
+
Dotty::Repository.actions.should_receive(:bootstrap)
|
47
|
+
suppress_output do
|
48
|
+
Dotty::Repository.add_existing_repository("existing_repo", "git://github.com/user/repo1.git")
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
describe ".create_repository" do
|
54
|
+
include_context "bootstrapped repository"
|
55
|
+
|
56
|
+
it "should trigger the create repository action" do
|
57
|
+
@actions.stub!(:create)
|
58
|
+
@actions.should_receive(:create)
|
59
|
+
|
60
|
+
suppress_output do
|
61
|
+
Dotty::Repository.create_repository("new_repo", "git://github.com/user/repo1.git")
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
it "should trigger .add_repository" do
|
66
|
+
Dotty::Repository.stub!(:add_repository).and_return(Dotty::Repository.new("new_repo", "url"))
|
67
|
+
Dotty::Repository.should_receive(:add_repository)
|
68
|
+
|
69
|
+
suppress_output do
|
70
|
+
Dotty::Repository.create_repository("new_repo", "git://github.com/user/repo1.git")
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
describe ".import" do
|
76
|
+
it "should invoke .add for all repositories in the given yaml file" do
|
77
|
+
yaml_path = Tempfile.new("dotty-test-import").path
|
78
|
+
File.open(yaml_path, 'w') do |f|
|
79
|
+
f.write({
|
80
|
+
'repo1' => { 'url' => 'url1' },
|
81
|
+
'repo2' => { 'url' => 'url2' }
|
82
|
+
}.to_yaml)
|
83
|
+
end
|
84
|
+
Dotty::Repository.stub(:add_existing_repository)
|
85
|
+
Dotty::Repository.should_receive(:add_existing_repository).once.with('repo1', 'url1')
|
86
|
+
Dotty::Repository.should_receive(:add_existing_repository).once.with('repo2', 'url2')
|
87
|
+
Dotty::Repository.import yaml_path
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
describe ".list" do
|
92
|
+
it "should return an empty array when Profile.current_profile_data is empty" do
|
93
|
+
Dotty::Profile.stub!(:current_profile_data).and_return({})
|
94
|
+
Dotty::Repository.list.should == []
|
95
|
+
end
|
96
|
+
|
97
|
+
context "with profile data" do
|
98
|
+
include_context "profile data"
|
99
|
+
|
100
|
+
it "should return an array with the same number of repository instances as in profile_data" do
|
101
|
+
Dotty::Repository.list.size.should == 2
|
102
|
+
end
|
103
|
+
|
104
|
+
it "should return an array consisting of Dotty::Repository instances" do
|
105
|
+
Dotty::Repository.list.collect(&:class).uniq.should == [Dotty::Repository]
|
106
|
+
end
|
107
|
+
|
108
|
+
it "should have objects with the correct name value" do
|
109
|
+
Dotty::Repository.list.collect(&:name).should == %w(my_repo other_repo)
|
110
|
+
end
|
111
|
+
|
112
|
+
it "should have objects with the correct url" do
|
113
|
+
Dotty::Repository.list.collect(&:url).should == %w(git://github.com/me/my_repo git://github.com/me/other_repo)
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
describe ".find" do
|
119
|
+
include_context "profile data"
|
120
|
+
|
121
|
+
it "should return the correct repository given a name that exists" do
|
122
|
+
repo = Dotty::Repository.find('my_repo')
|
123
|
+
repo.name.should == 'my_repo'
|
124
|
+
repo.url.should == 'git://github.com/me/my_repo'
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
describe "#initialize" do
|
129
|
+
it "should return a Dotty::Repository instance given valid attributes" do
|
130
|
+
Dotty::Repository.new('repo1', 'git://github.com/user/repo1.git').should be_instance_of Dotty::Repository
|
131
|
+
end
|
132
|
+
|
133
|
+
it "should raise an error if the name is not valid" do
|
134
|
+
expect {
|
135
|
+
Dotty::Repository.new('repo a', 'sdfsdf')
|
136
|
+
}.to raise_error Dotty::InvalidRepositoryNameError, "Repository name can only contain letters, numbers and the following characters: .-_"
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
describe "#destroy" do
|
141
|
+
include_context "bootstrapped repository"
|
142
|
+
|
143
|
+
it "should return the instance" do
|
144
|
+
suppress_output do
|
145
|
+
@repo.destroy.should == @repo
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
it "should remove the repository from the list" do
|
150
|
+
repositories = Dotty::Repository.list
|
151
|
+
suppress_output do
|
152
|
+
@repo.destroy
|
153
|
+
end
|
154
|
+
Dotty::Repository.repositories.should == repositories - [@repo]
|
155
|
+
end
|
156
|
+
|
157
|
+
it "should invoke Dotty::Profile.write_yaml" do
|
158
|
+
Dotty::Profile.should_receive(:write_yaml)
|
159
|
+
suppress_output do
|
160
|
+
@repo.destroy
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
it "should invoke Dotty::RepositoryActions#destroy" do
|
165
|
+
@actions.stub!(:destroy)
|
166
|
+
@actions.should_receive(:destroy).with(@repo)
|
167
|
+
suppress_output do
|
168
|
+
@repo.destroy
|
169
|
+
end
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
173
|
+
describe "#git_status" do
|
174
|
+
include_context "bootstrapped repository"
|
175
|
+
|
176
|
+
before do
|
177
|
+
@repo.stub(:git_status_output).and_return(" D gvimrc\n?? a\n")
|
178
|
+
end
|
179
|
+
|
180
|
+
it "should return an hash with the changes" do
|
181
|
+
@repo.git_status.should == { 'gvimrc' => ' D', 'a' => '??' }
|
182
|
+
end
|
183
|
+
end
|
184
|
+
|
185
|
+
describe "#unpushed_changes?" do
|
186
|
+
include_context "bootstrapped repository"
|
187
|
+
|
188
|
+
it "should return false when there are no unpushed commits" do
|
189
|
+
@repo.unpushed_changes?.should == false
|
190
|
+
end
|
191
|
+
|
192
|
+
# TODO find a good way to test this
|
193
|
+
#it "should should return true if git repo has commits that haven't been pushed" do
|
194
|
+
#end
|
195
|
+
end
|
196
|
+
|
197
|
+
context "with a @repo" do
|
198
|
+
before do
|
199
|
+
@repo = Dotty::Repository.new('repo1', 'git://github.com/user/repo1.git')
|
200
|
+
FileUtils.mkdir_p @repo.local_path
|
201
|
+
end
|
202
|
+
|
203
|
+
describe "#local_path" do
|
204
|
+
it "should return the correct local path" do
|
205
|
+
@repo.local_path.should == '/tmp/dotty-testing-root/default/repo1'
|
206
|
+
end
|
207
|
+
end
|
208
|
+
|
209
|
+
describe "#url" do
|
210
|
+
it "should return the correct url" do
|
211
|
+
@repo.url.should == 'git://github.com/user/repo1.git'
|
212
|
+
end
|
213
|
+
end
|
214
|
+
|
215
|
+
describe "#name" do
|
216
|
+
it "should return the correct name" do
|
217
|
+
@repo.name.should == 'repo1'
|
218
|
+
end
|
219
|
+
end
|
220
|
+
|
221
|
+
describe "#symlinks_from_dotfiles_directories" do
|
222
|
+
before do
|
223
|
+
@dotfile_dirs = {
|
224
|
+
:default => File.join(@repo.local_path, 'dotfiles'),
|
225
|
+
:other => File.join(@repo.local_path, 'other_dotfiles')
|
226
|
+
}
|
227
|
+
@dotfile_dirs.each_pair do |name, path|
|
228
|
+
FileUtils.mkdir_p(path)
|
229
|
+
end
|
230
|
+
end
|
231
|
+
|
232
|
+
it "should return the correct symlinks for regular files in dotfiles/" do
|
233
|
+
%x(touch #{@dotfile_dirs[:default]}/.a && touch #{@dotfile_dirs[:default]}/b)
|
234
|
+
@repo.symlinks_from_dotfiles_directories.should == { 'dotfiles/.a' => '.a', 'dotfiles/b' => 'b' }
|
235
|
+
end
|
236
|
+
|
237
|
+
it "should handle files in the dotfiles root correctly" do
|
238
|
+
FileUtils.mkdir(File.join @dotfile_dirs[:default], '.a')
|
239
|
+
FileUtils.mkdir(File.join @dotfile_dirs[:default], 'b')
|
240
|
+
@repo.symlinks_from_dotfiles_directories.should == { 'dotfiles/.a' => '.a', 'dotfiles/b' => 'b' }
|
241
|
+
end
|
242
|
+
|
243
|
+
it "should handle files and directories within in+XXX directories" do
|
244
|
+
FileUtils.mkdir_p(File.join @dotfile_dirs[:default], 'in+.other_dir/b')
|
245
|
+
%x(touch #{@dotfile_dirs[:default]}/in+.other_dir/.a)
|
246
|
+
@repo.symlinks_from_dotfiles_directories.should == { 'dotfiles/in+.other_dir/.a' => '.other_dir/.a', 'dotfiles/in+.other_dir/b' => '.other_dir/b' }
|
247
|
+
end
|
248
|
+
|
249
|
+
it "should handle nested in+XXX dirs" do
|
250
|
+
FileUtils.mkdir_p(File.join @dotfile_dirs[:default], 'in+first/in+second/a')
|
251
|
+
%x(touch #{@dotfile_dirs[:default]}/in+first/b)
|
252
|
+
%x(touch #{@dotfile_dirs[:default]}/in+first/in+second/c)
|
253
|
+
@repo.symlinks_from_dotfiles_directories.should == {
|
254
|
+
'dotfiles/in+first/in+second/a' => 'first/second/a',
|
255
|
+
'dotfiles/in+first/b' => 'first/b',
|
256
|
+
'dotfiles/in+first/in+second/c' => 'first/second/c'
|
257
|
+
}
|
258
|
+
end
|
259
|
+
|
260
|
+
it "should not include stuff in dirs without the in+XXX convention" do
|
261
|
+
FileUtils.mkdir_p(File.join @dotfile_dirs[:default], 'main/sub')
|
262
|
+
@repo.symlinks_from_dotfiles_directories.should == {
|
263
|
+
'dotfiles/main' => 'main'
|
264
|
+
}
|
265
|
+
|
266
|
+
end
|
267
|
+
end
|
268
|
+
|
269
|
+
describe "#symlinks_from_yaml" do
|
270
|
+
it "should return an empty hash if there is no dotty-symlinks.yml file or dotfiles/* in the repo" do
|
271
|
+
@repo.symlinks.should == {}
|
272
|
+
end
|
273
|
+
|
274
|
+
it "should return a hash with the correct symlinks if dotty-symlinks.yml file exists" do
|
275
|
+
expected_symlinks = { 'a' => 'aa', 'b' => 'bb' }
|
276
|
+
File.open File.join(@repo.local_path, 'dotty-symlinks.yml'), 'w' do |f|
|
277
|
+
f.write expected_symlinks.to_yaml
|
278
|
+
end
|
279
|
+
@repo.symlinks_from_yaml.should == expected_symlinks
|
280
|
+
end
|
281
|
+
end
|
282
|
+
|
283
|
+
describe "#symlinks" do
|
284
|
+
it "should return #symlinks_from_dotfiles_directories merged with #symlinks_from_yaml" do
|
285
|
+
@repo.stub!(:symlinks_from_dotfiles_directories).and_return({ :a => 1, :b => 2})
|
286
|
+
@repo.stub!(:symlinks_from_yaml).and_return({ :b => 3, :c => 4})
|
287
|
+
@repo.symlinks.should == { :a => 1, :b => 3, :c => 4 }
|
288
|
+
end
|
289
|
+
end
|
290
|
+
|
291
|
+
describe "#has_thor_task?" do
|
292
|
+
it "should return true when dotty-repository.thor is present in the repo" do
|
293
|
+
%x{touch #{@repo.local_path}/dotty-repository.thor}
|
294
|
+
@repo.has_thor_task?.should === true
|
295
|
+
end
|
296
|
+
|
297
|
+
it "should return false when there is no dotty-repository.thor present in the repo" do
|
298
|
+
@repo.has_thor_task?.should === false
|
299
|
+
end
|
300
|
+
end
|
301
|
+
end
|
302
|
+
|
303
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,62 @@
|
|
1
|
+
$:.unshift File.join(File.dirname(__FILE__), "..", "lib")
|
2
|
+
|
3
|
+
require 'simplecov'
|
4
|
+
SimpleCov.start
|
5
|
+
|
6
|
+
require 'dotty'
|
7
|
+
require 'support/shared_contexts'
|
8
|
+
require 'tempfile'
|
9
|
+
|
10
|
+
Dotty::App.send(:remove_const, :ROOT_PATH)
|
11
|
+
Dotty::App.const_set :ROOT_PATH, '/tmp/dotty-testing-root'
|
12
|
+
|
13
|
+
Dotty::Profile.send(:remove_const, :YAML_PATH)
|
14
|
+
Dotty::Profile.const_set :YAML_PATH, Tempfile.new('dotty-profiles-test').path
|
15
|
+
|
16
|
+
Dotty::RepositoryActions.send(:remove_const, :USER_HOME)
|
17
|
+
Dotty::RepositoryActions.const_set :USER_HOME, '/tmp/dotty-testing-user-home'
|
18
|
+
|
19
|
+
RSpec.configure do |config|
|
20
|
+
config.before(:each) do
|
21
|
+
end
|
22
|
+
|
23
|
+
config.after(:each) do
|
24
|
+
clean_dotty
|
25
|
+
end
|
26
|
+
|
27
|
+
def clean_dotty
|
28
|
+
[Dotty::RepositoryActions::USER_HOME, Dotty::App::ROOT_PATH].each do |p|
|
29
|
+
system "rm -rf #{p}" if File.exist?(p)
|
30
|
+
FileUtils.mkdir_p p
|
31
|
+
end
|
32
|
+
system "rm #{Dotty::Profile::YAML_PATH}" if File.exist?(Dotty::Profile::YAML_PATH)
|
33
|
+
Dotty::Profile.profile_data = nil
|
34
|
+
Dotty::Profile.current_profile = nil
|
35
|
+
Dotty::Repository.repositories = nil
|
36
|
+
end
|
37
|
+
|
38
|
+
def capture(stream)
|
39
|
+
begin
|
40
|
+
stream = stream.to_s
|
41
|
+
eval "$#{stream} = StringIO.new"
|
42
|
+
yield
|
43
|
+
result = eval("$#{stream}").string
|
44
|
+
ensure
|
45
|
+
eval("$#{stream} = #{stream.upcase}")
|
46
|
+
end
|
47
|
+
result
|
48
|
+
end
|
49
|
+
|
50
|
+
def suppress_output
|
51
|
+
begin
|
52
|
+
orig_stderr = $stderr.clone
|
53
|
+
orig_stdout = $stdout.clone
|
54
|
+
$stdout.reopen("/dev/null", "w")
|
55
|
+
$stderr.reopen("/dev/null", "w")
|
56
|
+
yield
|
57
|
+
ensure
|
58
|
+
$stdout.reopen(orig_stdout)
|
59
|
+
$stderr.reopen(orig_stderr)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
shared_context "added repository" do
|
2
|
+
before do
|
3
|
+
@repo = Dotty::Repository.new('repo', { :url => 'git://github.com/user/repo.git' })
|
4
|
+
Dotty::Repository.list << @repo
|
5
|
+
FileUtils.mkdir_p @repo.local_path
|
6
|
+
@actions = Dotty::Repository.actions
|
7
|
+
|
8
|
+
%x{touch #{File.join @repo.local_path, 'temp'}}
|
9
|
+
@symlinks = { 'a' => 'aa', 'b' => 'bb' }
|
10
|
+
File.open File.join(@repo.local_path, 'dotty-symlinks.yml'), 'w' do |f|
|
11
|
+
f.write @symlinks.to_yaml
|
12
|
+
end
|
13
|
+
%x(git init #{@repo.local_path})
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
shared_context "bootstrapped repository" do
|
18
|
+
include_context "added repository"
|
19
|
+
before do
|
20
|
+
@symlinks.each do |source_name, dest_name|
|
21
|
+
source_path = File.join @repo.local_path, source_name
|
22
|
+
destination_path = File.join Dotty::RepositoryActions::USER_HOME, dest_name
|
23
|
+
%x{touch #{source_path}}
|
24
|
+
%x{ln -s #{source_path} #{destination_path}} unless File.exist?(destination_path)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
|
30
|
+
shared_context "two in memory repositories" do
|
31
|
+
before do
|
32
|
+
@repo1 = Dotty::Repository.new('repo1name', 'url')
|
33
|
+
@repo2 = Dotty::Repository.new('repo2name', 'url2')
|
34
|
+
Dotty::Repository.repositories = [@repo1, @repo2]
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
shared_context "profile data" do
|
39
|
+
before do
|
40
|
+
@profile_data = {
|
41
|
+
'current_profile' => 'my_profile',
|
42
|
+
'profiles' => {
|
43
|
+
'my_profile' => {
|
44
|
+
'repositories' => {
|
45
|
+
'my_repo' => { 'url' => 'git://github.com/me/my_repo' },
|
46
|
+
'other_repo' => { 'url' => 'git://github.com/me/other_repo' }
|
47
|
+
}
|
48
|
+
},
|
49
|
+
'other_profile' => {
|
50
|
+
'repositories' => {
|
51
|
+
'my_repo' => { 'url' => 'git://github.com/me/my_repo' },
|
52
|
+
'other_repo' => { 'url' => 'git://github.com/me/other_repo' }
|
53
|
+
}
|
54
|
+
}
|
55
|
+
}
|
56
|
+
}
|
57
|
+
File.open(Dotty::Profile::YAML_PATH, 'w') do |f|
|
58
|
+
f.write(@profile_data.to_yaml)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
data/templates/README.md
ADDED
@@ -0,0 +1,41 @@
|
|
1
|
+
# Dotty repository
|
2
|
+
|
3
|
+
## dotfiles/
|
4
|
+
|
5
|
+
Dotty will symlink files and directories in the root your repos dotfiles/ directory, relative to ~.
|
6
|
+
You can symlink stuff to sub directories of ~ by using the in+subdir directory naming convention.
|
7
|
+
|
8
|
+
### Examples
|
9
|
+
|
10
|
+
dotfiles/.vim => ~/.vim
|
11
|
+
dotfiles/in+.ssh/config => ~/.ssh/config
|
12
|
+
dotfiles/in+a/in+b/c => ~/a/b/c
|
13
|
+
|
14
|
+
## dotty-symlink.yml
|
15
|
+
|
16
|
+
If you want more control over the symlinking, you can create a dotty-symlink.yml in the repo root.
|
17
|
+
|
18
|
+
### Example
|
19
|
+
|
20
|
+
file_in_repo:.in_home_dir
|
21
|
+
|
22
|
+
## dotty-repository.thor
|
23
|
+
|
24
|
+
If you want to do more than symlinking, you can create a dotty-repository.thor that implements the 'bootstrap' and 'implode' thor tasks.
|
25
|
+
The class must be named "DottyRepository".
|
26
|
+
|
27
|
+
### Example
|
28
|
+
|
29
|
+
class DottyRepository < Thor
|
30
|
+
include Thor::Actions
|
31
|
+
|
32
|
+
desc "bootstrap", "Bootstrap this repo"
|
33
|
+
def bootstrap
|
34
|
+
# Do stuff here
|
35
|
+
end
|
36
|
+
|
37
|
+
desc "implode", "Implode this repo"
|
38
|
+
def implode
|
39
|
+
# Do stuff here
|
40
|
+
end
|
41
|
+
end
|