ronin-repos 0.1.0.beta1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (61) hide show
  1. checksums.yaml +7 -0
  2. data/.document +5 -0
  3. data/.github/workflows/ruby.yml +27 -0
  4. data/.gitignore +13 -0
  5. data/.rspec +1 -0
  6. data/.ruby-version +1 -0
  7. data/.yardopts +1 -0
  8. data/COPYING.txt +165 -0
  9. data/ChangeLog.md +7 -0
  10. data/Gemfile +32 -0
  11. data/README.md +159 -0
  12. data/Rakefile +34 -0
  13. data/bin/ronin-repos +35 -0
  14. data/data/templates/repo/README.md.erb +11 -0
  15. data/gemspec.yml +36 -0
  16. data/lib/ronin/repos/cache_dir.rb +267 -0
  17. data/lib/ronin/repos/class_dir.rb +150 -0
  18. data/lib/ronin/repos/cli/command.rb +63 -0
  19. data/lib/ronin/repos/cli/commands/install.rb +71 -0
  20. data/lib/ronin/repos/cli/commands/list.rb +80 -0
  21. data/lib/ronin/repos/cli/commands/new.rb +83 -0
  22. data/lib/ronin/repos/cli/commands/purge.rb +39 -0
  23. data/lib/ronin/repos/cli/commands/remove.rb +71 -0
  24. data/lib/ronin/repos/cli/commands/update.rb +91 -0
  25. data/lib/ronin/repos/cli.rb +45 -0
  26. data/lib/ronin/repos/exceptions.rb +33 -0
  27. data/lib/ronin/repos/repository.rb +343 -0
  28. data/lib/ronin/repos/root.rb +26 -0
  29. data/lib/ronin/repos/version.rb +24 -0
  30. data/lib/ronin/repos.rb +81 -0
  31. data/man/ronin-repos-install.1 +64 -0
  32. data/man/ronin-repos-install.1.md +49 -0
  33. data/man/ronin-repos-list.1 +54 -0
  34. data/man/ronin-repos-list.1.md +41 -0
  35. data/man/ronin-repos-new.1 +37 -0
  36. data/man/ronin-repos-purge.1 +54 -0
  37. data/man/ronin-repos-purge.1.md +41 -0
  38. data/man/ronin-repos-remove.1 +60 -0
  39. data/man/ronin-repos-remove.1.md +46 -0
  40. data/man/ronin-repos-update.1 +64 -0
  41. data/man/ronin-repos-update.1.md +49 -0
  42. data/man/ronin-repos.1 +49 -0
  43. data/man/ronin-repos.1.md +37 -0
  44. data/ronin-repos.gemspec +62 -0
  45. data/spec/cache_dir_spec.rb +272 -0
  46. data/spec/class_dir_spec.rb +97 -0
  47. data/spec/fixtures/cache/repo1/dir/file1.txt +0 -0
  48. data/spec/fixtures/cache/repo1/file1.txt +0 -0
  49. data/spec/fixtures/cache/repo1/file2.txt +0 -0
  50. data/spec/fixtures/cache/repo2/dir/file1.txt +0 -0
  51. data/spec/fixtures/cache/repo2/dir/file2.txt +0 -0
  52. data/spec/fixtures/cache/repo2/file1.txt +0 -0
  53. data/spec/fixtures/cache/repo2/file2.txt +0 -0
  54. data/spec/fixtures/cache/repo2/only-exists-in-repo2.txt +0 -0
  55. data/spec/fixtures/class_dir/file1.rb +0 -0
  56. data/spec/fixtures/class_dir/file2.rb +0 -0
  57. data/spec/fixtures/class_dir/only_in_class_dir.rb +0 -0
  58. data/spec/repos_spec.rb +67 -0
  59. data/spec/repository_spec.rb +415 -0
  60. data/spec/spec_helper.rb +6 -0
  61. metadata +143 -0
@@ -0,0 +1,415 @@
1
+ require 'spec_helper'
2
+ require 'ronin/repos/repository'
3
+
4
+ describe Ronin::Repos::Repository do
5
+ let(:fixtures_dir) { File.expand_path(File.join(__dir__,'fixtures')) }
6
+
7
+ let(:name) { 'repo1' }
8
+ let(:path) { File.join(fixtures_dir,'cache',name) }
9
+
10
+ subject { described_class.new(path) }
11
+
12
+ describe "#initialize" do
13
+ it "must set #path" do
14
+ expect(subject.path).to eq(path)
15
+ end
16
+
17
+ it "must set #name based on #path" do
18
+ expect(subject.name).to eq(File.basename(path))
19
+ end
20
+
21
+ context "when the path does not exist" do
22
+ let(:path) { '/path/does/not/exist' }
23
+
24
+ it do
25
+ expect {
26
+ described_class.new(path)
27
+ }.to raise_error(RepositoryNotFound,"repository does not exist: #{path.inspect}")
28
+ end
29
+ end
30
+
31
+ context "when the path is not a directory" do
32
+ let(:path) { __FILE__ }
33
+
34
+ it do
35
+ expect {
36
+ described_class.new(path)
37
+ }.to raise_error(RepositoryNotFound,"path is not a directory: #{path.inspect}")
38
+ end
39
+ end
40
+ end
41
+
42
+ describe ".clone" do
43
+ let(:uri) { 'https://github.com/example/repo.git' }
44
+
45
+ subject { described_class }
46
+
47
+ it "must call `git clone` the URI to the given path and return a Repository" do
48
+ expect(subject).to receive(:system).with(
49
+ 'git', 'clone', uri, path
50
+ ).and_return(true)
51
+
52
+ repo = subject.clone(uri,path)
53
+
54
+ expect(repo).to be_kind_of(described_class)
55
+ expect(repo.path).to eq(path)
56
+ end
57
+
58
+ context "when a depth: keyword argument is given" do
59
+ let(:depth) { 1 }
60
+
61
+ it "must `git clone --depth` with the given depth and URI to the given path)" do
62
+ expect(subject).to receive(:system).with(
63
+ 'git', 'clone', '--depth', depth.to_s, uri, path
64
+ ).and_return(true)
65
+
66
+ subject.clone(uri,path, depth: depth)
67
+ end
68
+ end
69
+
70
+ context "when system() returns nil" do
71
+ it do
72
+ allow(subject).to receive(:system).and_return(nil)
73
+
74
+ expect {
75
+ subject.clone(uri,path)
76
+ }.to raise_error(CommandNotInstalled,"git is not installed")
77
+ end
78
+ end
79
+
80
+ context "when system() returns false" do
81
+ it do
82
+ allow(subject).to receive(:system).and_return(false)
83
+
84
+ expect {
85
+ subject.clone(uri,path)
86
+ }.to raise_error(CommandFailed,"command failed: git clone #{uri} #{path}")
87
+ end
88
+ end
89
+ end
90
+
91
+ describe ".install" do
92
+ let(:uri) { 'https://github.com/example/repo.git' }
93
+
94
+ subject { described_class }
95
+
96
+ it "must `git clone` the URI and the given path and return a Repository" do
97
+ expect(subject).to receive(:system).with(
98
+ 'git', 'clone', uri, path
99
+ ).and_return(true)
100
+
101
+ repo = subject.install(uri,path)
102
+
103
+ expect(repo).to be_kind_of(described_class)
104
+ expect(repo.path).to eq(path)
105
+ end
106
+
107
+ context "when the branch: keyword argument is given" do
108
+ let(:branch) { 'foo' }
109
+
110
+ it "must `git clone` the URI to the given path and then `git checkout` the branch)" do
111
+ expect(subject).to receive(:system).with(
112
+ 'git', 'clone', uri, path
113
+ ).and_return(true)
114
+
115
+ expect_any_instance_of(described_class).to receive(:system).with(
116
+ 'git', 'checkout', branch
117
+ ).and_return(true)
118
+
119
+ subject.install(uri,path, branch: branch)
120
+ end
121
+ end
122
+
123
+ context "when the tag: keyword argument is given" do
124
+ let(:tag) { 'v1.0.0' }
125
+
126
+ it "must `git clone` the URI to the given path and then `git checkout` the tag" do
127
+ expect(subject).to receive(:system).with(
128
+ 'git', 'clone', uri, path
129
+ ).and_return(true)
130
+
131
+ expect_any_instance_of(described_class).to receive(:system).with(
132
+ 'git', 'checkout', tag
133
+ ).and_return(true)
134
+
135
+ subject.install(uri,path, tag: tag)
136
+ end
137
+ end
138
+ end
139
+
140
+ describe "#pull" do
141
+ it "must `git pull` from 'origin'" do
142
+ expect(subject).to receive(:system).with(
143
+ 'git', 'pull', 'origin'
144
+ ).and_return(true)
145
+
146
+ subject.pull
147
+ end
148
+
149
+ context "when the remote: keyword argument is given" do
150
+ let(:remote) { :backup }
151
+
152
+ it "must `git pull` from the given remote" do
153
+ expect(subject).to receive(:system).with(
154
+ 'git', 'pull', remote.to_s
155
+ ).and_return(true)
156
+
157
+ subject.pull(remote: remote)
158
+ end
159
+ end
160
+
161
+ context "when the branch: keyword argument is given" do
162
+ let(:branch) { 'foo' }
163
+
164
+ it "must `git pull` from 'origin' and the given branch" do
165
+ expect(subject).to receive(:system).with(
166
+ 'git', 'pull', 'origin', branch
167
+ ).and_return(true)
168
+
169
+ subject.pull(branch: branch)
170
+ end
171
+ end
172
+
173
+ context "when the `tags: true` is given" do
174
+ it "must `git pull` from 'origin' and pull down any tags" do
175
+ expect(subject).to receive(:system).with(
176
+ 'git', 'pull', '--tags', 'origin'
177
+ ).and_return(true)
178
+
179
+ subject.pull(tags: true)
180
+ end
181
+ end
182
+
183
+ context "when system() returns nil" do
184
+ it do
185
+ allow(subject).to receive(:system).and_return(nil)
186
+
187
+ expect {
188
+ subject.pull
189
+ }.to raise_error(CommandNotInstalled,"git is not installed")
190
+ end
191
+ end
192
+
193
+ context "when system() returns false" do
194
+ it do
195
+ allow(subject).to receive(:system).and_return(false)
196
+
197
+ expect {
198
+ subject.pull
199
+ }.to raise_error(CommandFailed,"command failed: git pull origin")
200
+ end
201
+ end
202
+ end
203
+
204
+ describe "#checkout" do
205
+ let(:branch) { 'foo' }
206
+
207
+ it "must `git checkout` the given branch" do
208
+ expect(subject).to receive(:system).with(
209
+ 'git', 'checkout', branch
210
+ ).and_return(true)
211
+
212
+ subject.checkout(branch)
213
+ end
214
+
215
+ context "when system() returns nil" do
216
+ it do
217
+ allow(subject).to receive(:system).and_return(nil)
218
+
219
+ expect {
220
+ subject.checkout(branch)
221
+ }.to raise_error(CommandNotInstalled,"git is not installed")
222
+ end
223
+ end
224
+
225
+ context "when system() returns false" do
226
+ it do
227
+ allow(subject).to receive(:system).and_return(false)
228
+
229
+ expect {
230
+ subject.checkout(branch)
231
+ }.to raise_error(CommandFailed,"command failed: git checkout #{branch}")
232
+ end
233
+ end
234
+ end
235
+
236
+ describe "#update" do
237
+ it "must `git pull` from 'origin' and pull down any tags" do
238
+ expect(subject).to receive(:system).with(
239
+ 'git', 'pull', '--tags', 'origin'
240
+ ).and_return(true)
241
+
242
+ subject.update
243
+ end
244
+
245
+ context "when the branch: keyword argument is given" do
246
+ let(:branch) { 'foo' }
247
+
248
+ it "must `git pull` from 'origin' and the given branch and then `git checkout` the branch" do
249
+ expect(subject).to receive(:system).with(
250
+ 'git', 'pull', 'origin', branch
251
+ ).and_return(true)
252
+
253
+ expect(subject).to receive(:system).with(
254
+ 'git', 'checkout', branch
255
+ ).and_return(true)
256
+
257
+ subject.update(branch: branch)
258
+ end
259
+ end
260
+
261
+ context "when the tag: keyword argument is given" do
262
+ let(:tag) { 'v1.0.0' }
263
+
264
+ it "must `git pull --tags` from 'origin' and then `git checkout` the given tag" do
265
+ expect(subject).to receive(:system).with(
266
+ 'git', 'pull', '--tags', 'origin'
267
+ ).and_return(true)
268
+
269
+ expect(subject).to receive(:system).with(
270
+ 'git', 'checkout', tag
271
+ ).and_return(true)
272
+
273
+ subject.update(tag: tag)
274
+ end
275
+ end
276
+ end
277
+
278
+ describe "#delete" do
279
+ it "must call FileUtils.rm_rf on the path" do
280
+ expect(FileUtils).to receive(:rm_rf).with(path)
281
+
282
+ subject.delete
283
+ end
284
+ end
285
+
286
+ describe "#join" do
287
+ let(:relative_path) { 'file1.txt' }
288
+
289
+ it "must return the absolute path with respect to the repository" do
290
+ expect(subject.join(relative_path)).to eq(
291
+ File.join(path,relative_path)
292
+ )
293
+ end
294
+ end
295
+
296
+ describe "#has_file?" do
297
+ context "when the repository contains the file" do
298
+ let(:relative_path) { 'file1.txt' }
299
+
300
+ it "must return the absolute path to the file" do
301
+ expect(subject.has_file?(relative_path)).to be(true)
302
+ end
303
+ end
304
+
305
+ context "when the relative path does not exist within the repository" do
306
+ let(:relative_path) { 'does/not/exist.txt' }
307
+
308
+ it "must return false" do
309
+ expect(subject.has_file?(relative_path)).to be(false)
310
+ end
311
+ end
312
+ end
313
+
314
+ describe "#has_directory?" do
315
+ context "when the repository contains the directory" do
316
+ let(:relative_path) { 'dir' }
317
+
318
+ it "must return the absolute path to the directory" do
319
+ expect(subject.has_directory?(relative_path)).to be(true)
320
+ end
321
+ end
322
+
323
+ context "when the relative path does not exist within the repository" do
324
+ let(:relative_path) { 'does/not/exist' }
325
+
326
+ it "must return false" do
327
+ expect(subject.has_directory?(relative_path)).to be(false)
328
+ end
329
+ end
330
+ end
331
+
332
+ describe "#find_file" do
333
+ context "when the relative path exists within the repository" do
334
+ let(:relative_path) { 'file1.txt' }
335
+
336
+ it "must return the absolute path to the file" do
337
+ expect(subject.find_file(relative_path)).to eq(
338
+ File.join(path,relative_path)
339
+ )
340
+ end
341
+ end
342
+
343
+ context "when the relative path does not exist within the repository" do
344
+ let(:relative_path) { 'does/not/exist.txt' }
345
+
346
+ it "must return nil" do
347
+ expect(subject.find_file(relative_path)).to be(nil)
348
+ end
349
+ end
350
+ end
351
+
352
+ describe "#glob" do
353
+ context "when the pattern matches files within the repository" do
354
+ let(:pattern) { 'dir/*.txt' }
355
+
356
+ it "must return the absolute path to the file" do
357
+ expect(subject.glob(pattern)).to eq(
358
+ Dir[File.join(path,pattern)]
359
+ )
360
+ end
361
+
362
+ context "when a block is given" do
363
+ it "must yield the matching absolute paths" do
364
+ expect { |b|
365
+ subject.glob(pattern,&b)
366
+ }.to yield_successive_args(
367
+ *Dir[File.join(path,pattern)]
368
+ )
369
+ end
370
+ end
371
+ end
372
+
373
+ context "when the relative path does not exist within the repository" do
374
+ let(:pattern) { 'does/not/exist/*.txt' }
375
+
376
+ it "must return []" do
377
+ expect(subject.glob(pattern)).to eq([])
378
+ end
379
+
380
+ context "when a block is given" do
381
+ it "must not yield" do
382
+ expect { |b|
383
+ subject.glob(pattern,&b)
384
+ }.to_not yield_control
385
+ end
386
+ end
387
+ end
388
+ end
389
+
390
+ describe "#list_files" do
391
+ context "when given no arguments" do
392
+ it "must list every file within the repository's directory" do
393
+ expect(subject.list_files).to eq(
394
+ %w[
395
+ dir/file1.txt
396
+ file1.txt
397
+ file2.txt
398
+ ]
399
+ )
400
+ end
401
+ end
402
+
403
+ context "when given a glob pattern" do
404
+ it "must list only the files that match the glob pattern" do
405
+ expect(subject.list_files('dir/*.txt')).to eq(%w[dir/file1.txt])
406
+ end
407
+ end
408
+ end
409
+
410
+ describe "#to_s" do
411
+ it "must return the repository name" do
412
+ expect(subject.to_s).to eq(name)
413
+ end
414
+ end
415
+ end
@@ -0,0 +1,6 @@
1
+ require 'rspec'
2
+ require 'simplecov'
3
+ SimpleCov.start
4
+
5
+ require 'ronin/repos/version'
6
+ include Ronin::Repos
metadata ADDED
@@ -0,0 +1,143 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: ronin-repos
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0.beta1
5
+ platform: ruby
6
+ authors:
7
+ - Postmodern
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2023-01-01 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: ronin-core
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: 0.1.0.beta1
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: 0.1.0.beta1
27
+ - !ruby/object:Gem::Dependency
28
+ name: bundler
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '2.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '2.0'
41
+ description: ronin-repos provides a repository system for installing, managing, and
42
+ accessing third-party git repositories, which can contain code or other data.
43
+ email: postmodern.mod3@gmail.com
44
+ executables:
45
+ - ronin-repos
46
+ extensions: []
47
+ extra_rdoc_files:
48
+ - COPYING.txt
49
+ - ChangeLog.md
50
+ - README.md
51
+ files:
52
+ - ".document"
53
+ - ".github/workflows/ruby.yml"
54
+ - ".gitignore"
55
+ - ".rspec"
56
+ - ".ruby-version"
57
+ - ".yardopts"
58
+ - COPYING.txt
59
+ - ChangeLog.md
60
+ - Gemfile
61
+ - README.md
62
+ - Rakefile
63
+ - bin/ronin-repos
64
+ - data/templates/repo/README.md.erb
65
+ - gemspec.yml
66
+ - lib/ronin/repos.rb
67
+ - lib/ronin/repos/cache_dir.rb
68
+ - lib/ronin/repos/class_dir.rb
69
+ - lib/ronin/repos/cli.rb
70
+ - lib/ronin/repos/cli/command.rb
71
+ - lib/ronin/repos/cli/commands/install.rb
72
+ - lib/ronin/repos/cli/commands/list.rb
73
+ - lib/ronin/repos/cli/commands/new.rb
74
+ - lib/ronin/repos/cli/commands/purge.rb
75
+ - lib/ronin/repos/cli/commands/remove.rb
76
+ - lib/ronin/repos/cli/commands/update.rb
77
+ - lib/ronin/repos/exceptions.rb
78
+ - lib/ronin/repos/repository.rb
79
+ - lib/ronin/repos/root.rb
80
+ - lib/ronin/repos/version.rb
81
+ - man/ronin-repos-install.1
82
+ - man/ronin-repos-install.1.md
83
+ - man/ronin-repos-list.1
84
+ - man/ronin-repos-list.1.md
85
+ - man/ronin-repos-new.1
86
+ - man/ronin-repos-purge.1
87
+ - man/ronin-repos-purge.1.md
88
+ - man/ronin-repos-remove.1
89
+ - man/ronin-repos-remove.1.md
90
+ - man/ronin-repos-update.1
91
+ - man/ronin-repos-update.1.md
92
+ - man/ronin-repos.1
93
+ - man/ronin-repos.1.md
94
+ - ronin-repos.gemspec
95
+ - spec/cache_dir_spec.rb
96
+ - spec/class_dir_spec.rb
97
+ - spec/fixtures/cache/repo1/dir/file1.txt
98
+ - spec/fixtures/cache/repo1/file1.txt
99
+ - spec/fixtures/cache/repo1/file2.txt
100
+ - spec/fixtures/cache/repo2/dir/file1.txt
101
+ - spec/fixtures/cache/repo2/dir/file2.txt
102
+ - spec/fixtures/cache/repo2/file1.txt
103
+ - spec/fixtures/cache/repo2/file2.txt
104
+ - spec/fixtures/cache/repo2/only-exists-in-repo2.txt
105
+ - spec/fixtures/class_dir/file1.rb
106
+ - spec/fixtures/class_dir/file2.rb
107
+ - spec/fixtures/class_dir/only_in_class_dir.rb
108
+ - spec/repos_spec.rb
109
+ - spec/repository_spec.rb
110
+ - spec/spec_helper.rb
111
+ homepage: https://ronin-rb.dev
112
+ licenses:
113
+ - LGPL-3.0
114
+ metadata:
115
+ documentation_uri: https://rubydoc.info/gems/ronin-repos
116
+ source_code_uri: https://github.com/ronin-rb/ronin-repos
117
+ bug_tracker_uri: https://github.com/ronin-rb/ronin-repos/issues
118
+ changelog_uri: https://github.com/ronin-rb/ronin-repos/blob/main/ChangeLog.md
119
+ rubygems_mfa_required: 'true'
120
+ post_install_message:
121
+ rdoc_options: []
122
+ require_paths:
123
+ - lib
124
+ required_ruby_version: !ruby/object:Gem::Requirement
125
+ requirements:
126
+ - - ">="
127
+ - !ruby/object:Gem::Version
128
+ version: 3.0.0
129
+ required_rubygems_version: !ruby/object:Gem::Requirement
130
+ requirements:
131
+ - - ">="
132
+ - !ruby/object:Gem::Version
133
+ version: '0'
134
+ requirements: []
135
+ rubygems_version: 3.3.26
136
+ signing_key:
137
+ specification_version: 4
138
+ summary: Third-party git repository support for ronin.
139
+ test_files:
140
+ - spec/cache_dir_spec.rb
141
+ - spec/class_dir_spec.rb
142
+ - spec/repos_spec.rb
143
+ - spec/repository_spec.rb