ronin-repos 0.1.0.beta1

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.
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