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,39 @@
1
+ # frozen_string_literal: true
2
+ #
3
+ # Copyright (c) 2021 Hal Brodigan (postmodern.mod3 at gmail.com)
4
+ #
5
+ # ronin-repos is free software: you can redistribute it and/or modify
6
+ # it under the terms of the GNU Lesser General Public License as published
7
+ # by the Free Software Foundation, either version 3 of the License, or
8
+ # (at your option) any later version.
9
+ #
10
+ # ronin-repos is distributed in the hope that it will be useful,
11
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ # GNU Lesser General Public License for more details.
14
+ #
15
+ # You should have received a copy of the GNU Lesser General Public License
16
+ # along with ronin-repos. If not, see <https://www.gnu.org/licenses/>.
17
+ #
18
+
19
+ require 'ronin/repos/cli/command'
20
+
21
+ module Ronin
22
+ module Repos
23
+ class CLI
24
+ module Commands
25
+ class Purge < Command
26
+
27
+ description 'Removes all git repository from the cache directory'
28
+
29
+ man_page 'ronin-repos-download.1'
30
+
31
+ def run
32
+ cache_dir.purge
33
+ end
34
+
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,71 @@
1
+ # frozen_string_literal: true
2
+ #
3
+ # Copyright (c) 2021 Hal Brodigan (postmodern.mod3 at gmail.com)
4
+ #
5
+ # ronin-repos is free software: you can redistribute it and/or modify
6
+ # it under the terms of the GNU Lesser General Public License as published
7
+ # by the Free Software Foundation, either version 3 of the License, or
8
+ # (at your option) any later version.
9
+ #
10
+ # ronin-repos is distributed in the hope that it will be useful,
11
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ # GNU Lesser General Public License for more details.
14
+ #
15
+ # You should have received a copy of the GNU Lesser General Public License
16
+ # along with ronin-repos. If not, see <https://www.gnu.org/licenses/>.
17
+ #
18
+
19
+ require 'ronin/repos/cli/command'
20
+
21
+ module Ronin
22
+ module Repos
23
+ class CLI
24
+ module Commands
25
+ #
26
+ # Deletes a repository from the cache directory.
27
+ #
28
+ # ## Usage
29
+ #
30
+ # ronin-repos remove [options] NAME
31
+ #
32
+ # ## Options
33
+ #
34
+ # -C, --cache-dir DIR Overrides the default cache directory
35
+ # -h, --help Print help information
36
+ #
37
+ # ## Arguments
38
+ #
39
+ # REPO URI of the git repository
40
+ #
41
+ class Remove < Command
42
+
43
+ usage '[options] NAME'
44
+
45
+ argument :name, required: true,
46
+ usage: 'REPO',
47
+ desc: 'URI of the git repository'
48
+
49
+ description 'Deletes a repository from the cache directory'
50
+
51
+ man_page 'ronin-repos-remove.1'
52
+
53
+ #
54
+ # Runs the `ronin-repos remove` command.
55
+ #
56
+ # @param [String] name
57
+ # The repository name to remove.
58
+ #
59
+ def run(name)
60
+ repo = cache_dir[name]
61
+ repo.delete
62
+ rescue RepositoryNotFound => error
63
+ print_error(error.message)
64
+ exit(-1)
65
+ end
66
+
67
+ end
68
+ end
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,91 @@
1
+ # frozen_string_literal: true
2
+ #
3
+ # Copyright (c) 2021 Hal Brodigan (postmodern.mod3 at gmail.com)
4
+ #
5
+ # ronin-repos is free software: you can redistribute it and/or modify
6
+ # it under the terms of the GNU Lesser General Public License as published
7
+ # by the Free Software Foundation, either version 3 of the License, or
8
+ # (at your option) any later version.
9
+ #
10
+ # ronin-repos is distributed in the hope that it will be useful,
11
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ # GNU Lesser General Public License for more details.
14
+ #
15
+ # You should have received a copy of the GNU Lesser General Public License
16
+ # along with ronin-repos. If not, see <https://www.gnu.org/licenses/>.
17
+ #
18
+
19
+ require 'ronin/repos/cli/command'
20
+
21
+ require 'ronin/core/cli/logging'
22
+
23
+ module Ronin
24
+ module Repos
25
+ class CLI
26
+ module Commands
27
+ #
28
+ # Updates all or one repository from the cache directory.
29
+ #
30
+ # ## Usage
31
+ #
32
+ # ronin-repos update [options] [REPO]
33
+ #
34
+ # ## Options
35
+ #
36
+ # -C, --cache-dir DIR Overrides the default cache directory
37
+ # -h, --help Print help information
38
+ #
39
+ # ## Arguments
40
+ #
41
+ # [REPO] The repository to update
42
+ #
43
+ class Update < Command
44
+
45
+ include Core::CLI::Logging
46
+
47
+ usage '[options] [REPO]'
48
+
49
+ argument :name, required: false,
50
+ usage: 'REPO',
51
+ desc: 'The repository to update'
52
+
53
+ description 'Updates all or one repository from the cache directory'
54
+
55
+ man_page 'ronin-repos-update.1'
56
+
57
+ #
58
+ # Runs the `ronin-repos update` command.
59
+ #
60
+ # @param [String, nil] name
61
+ # The optional repository name to update.
62
+ #
63
+ def run(name=nil)
64
+ if name
65
+ begin
66
+ repo = cache_dir[name]
67
+
68
+ log_info "Updating repository #{repo} ..."
69
+ repo.update
70
+ rescue RepositoryNotFound, CommandFailed => error
71
+ log_error(error.message)
72
+ exit(-1)
73
+ end
74
+ else
75
+ cache_dir.each do |repo|
76
+ log_info "Updating repository #{repo} ..."
77
+
78
+ begin
79
+ repo.update
80
+ rescue CommandFailed => error
81
+ log_error("failed to update repository #{repo}: #{error.message}")
82
+ end
83
+ end
84
+ end
85
+ end
86
+
87
+ end
88
+ end
89
+ end
90
+ end
91
+ end
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+ #
3
+ # Copyright (c) 2021 Hal Brodigan (postmodern.mod3 at gmail.com)
4
+ #
5
+ # ronin-repos is free software: you can redistribute it and/or modify
6
+ # it under the terms of the GNU Lesser General Public License as published
7
+ # by the Free Software Foundation, either version 3 of the License, or
8
+ # (at your option) any later version.
9
+ #
10
+ # ronin-repos is distributed in the hope that it will be useful,
11
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ # GNU Lesser General Public License for more details.
14
+ #
15
+ # You should have received a copy of the GNU Lesser General Public License
16
+ # along with ronin-repos. If not, see <https://www.gnu.org/licenses/>.
17
+ #
18
+
19
+ require 'command_kit/commands'
20
+ require 'command_kit/commands/auto_load'
21
+
22
+ module Ronin
23
+ module Repos
24
+ #
25
+ # The `ronin-repos` command-line interface (CLI).
26
+ #
27
+ # @api private
28
+ #
29
+ class CLI
30
+
31
+ include CommandKit::Commands
32
+ include CommandKit::Commands::AutoLoad.new(
33
+ dir: "#{__dir__}/cli/commands",
34
+ namespace: "#{self}::Commands"
35
+ )
36
+
37
+ command_name 'ronin-repos'
38
+
39
+ command_aliases['ls'] = 'list'
40
+ command_aliases['up'] = 'update'
41
+ command_aliases['rm'] = 'remove'
42
+
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+ #
3
+ # Copyright (c) 2021 Hal Brodigan (postmodern.mod3 at gmail.com)
4
+ #
5
+ # ronin-repos is free software: you can redistribute it and/or modify
6
+ # it under the terms of the GNU Lesser General Public License as published
7
+ # by the Free Software Foundation, either version 3 of the License, or
8
+ # (at your option) any later version.
9
+ #
10
+ # ronin-repos is distributed in the hope that it will be useful,
11
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ # GNU Lesser General Public License for more details.
14
+ #
15
+ # You should have received a copy of the GNU Lesser General Public License
16
+ # along with ronin-repos. If not, see <https://www.gnu.org/licenses/>.
17
+ #
18
+
19
+ module Ronin
20
+ module Repos
21
+ class Exception < RuntimeError
22
+ end
23
+
24
+ class RepositoryNotFound < Exception
25
+ end
26
+
27
+ class CommandNotInstalled < Exception
28
+ end
29
+
30
+ class CommandFailed < Exception
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,343 @@
1
+ # frozen_string_literal: true
2
+ #
3
+ # Copyright (c) 2021 Hal Brodigan (postmodern.mod3 at gmail.com)
4
+ #
5
+ # ronin-repos is free software: you can redistribute it and/or modify
6
+ # it under the terms of the GNU Lesser General Public License as published
7
+ # by the Free Software Foundation, either version 3 of the License, or
8
+ # (at your option) any later version.
9
+ #
10
+ # ronin-repos is distributed in the hope that it will be useful,
11
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ # GNU Lesser General Public License for more details.
14
+ #
15
+ # You should have received a copy of the GNU Lesser General Public License
16
+ # along with ronin-repos. If not, see <https://www.gnu.org/licenses/>.
17
+ #
18
+
19
+ require 'ronin/repos/exceptions'
20
+
21
+ require 'fileutils'
22
+
23
+ module Ronin
24
+ module Repos
25
+ #
26
+ # Represents an installed repository.
27
+ #
28
+ # @api private
29
+ #
30
+ class Repository
31
+
32
+ # The path to the repository's directory.
33
+ #
34
+ # @return [String]
35
+ attr_reader :path
36
+
37
+ # The name of the repository.
38
+ #
39
+ # @return [String]
40
+ attr_reader :name
41
+
42
+ #
43
+ # Initializes the repository.
44
+ #
45
+ # @param [String] path
46
+ # The path to the repository.
47
+ #
48
+ # @raise [RepositoryNotFound]
49
+ # The path does not exist or does not point to a directory.
50
+ #
51
+ def initialize(path)
52
+ @path = File.expand_path(path)
53
+
54
+ unless File.exist?(@path)
55
+ raise(RepositoryNotFound,"repository does not exist: #{@path.inspect}")
56
+ end
57
+
58
+ unless File.directory?(@path)
59
+ raise(RepositoryNotFound,"path is not a directory: #{@path.inspect}")
60
+ end
61
+
62
+ @name = File.basename(@path)
63
+ end
64
+
65
+ #
66
+ # Clones a repository.
67
+ #
68
+ # @param [String, URI::HTTPS] uri
69
+ # The `https://` or `git@HOST:PATH` SSH URI
70
+ #
71
+ # @param [String] path
72
+ # The path to where the repository will be cloned to.
73
+ #
74
+ # @param [Integer, nil] depth
75
+ # The number of commits to clone.
76
+ #
77
+ # @return [Repository]
78
+ # The newly cloned repository.
79
+ #
80
+ # @raise [CommandFailed]
81
+ # The `git` command failed.
82
+ #
83
+ # @raise [CommandNotFailed]
84
+ # The `git` command is not installed.
85
+ #
86
+ def self.clone(uri,path, depth: nil)
87
+ path = path.to_s
88
+ args = []
89
+
90
+ if depth
91
+ args << '--depth' << depth.to_s
92
+ end
93
+
94
+ args << uri.to_s
95
+ args << path.to_s
96
+
97
+ case system('git','clone',*args)
98
+ when nil
99
+ raise(CommandNotInstalled,"git is not installed")
100
+ when false
101
+ raise(CommandFailed,"command failed: git clone #{args.join(' ')}")
102
+ end
103
+
104
+ return new(path)
105
+ end
106
+
107
+ #
108
+ # Clones and installs a repository from the URI and to the destination
109
+ # path.
110
+ #
111
+ # @param [String, URI::HTTPS] uri
112
+ # The `https://` or `git@HOST:PATH` SSH URI
113
+ #
114
+ # @param [String] path
115
+ # The path to where the repository will be cloned to.
116
+ #
117
+ # @param [String, nil] branch
118
+ # The git branch to pull.
119
+ #
120
+ # @param [Boolean] tag
121
+ # Controls whether to pull git tags in addition to the git commits.
122
+ #
123
+ # @param [Hash{Symbol => Object}] kwargs
124
+ # Additional keyword arguments for {clone}.
125
+ #
126
+ # @return [Repository]
127
+ # The newly cloned repository.
128
+ #
129
+ # @raise [CommandFailed]
130
+ #
131
+ def self.install(uri,path, branch: nil, tag: nil, **kwargs)
132
+ repo = clone(uri,path, **kwargs)
133
+
134
+ if branch || tag
135
+ repo.checkout(branch || tag)
136
+ end
137
+
138
+ return repo
139
+ end
140
+
141
+ #
142
+ # Pulls down new git commits.
143
+ #
144
+ # @param [String] remote
145
+ # The git remote to pull from.
146
+ #
147
+ # @param [String, nil] branch
148
+ # The git branch to pull.
149
+ #
150
+ # @param [Boolean] tags
151
+ # Controls whether to pull git tags in addition to the git commits.
152
+ #
153
+ # @return [true]
154
+ # Indicates that the `git` command executed successfully.
155
+ #
156
+ # @raise [CommandFailed]
157
+ #
158
+ def pull(remote: 'origin', branch: nil, tags: nil)
159
+ args = []
160
+ args << '--tags' if tags
161
+
162
+ args << remote.to_s
163
+ args << branch.to_s if branch
164
+
165
+ Dir.chdir(@path) do
166
+ case system('git','pull',*args)
167
+ when nil
168
+ raise(CommandNotInstalled,"git is not installed")
169
+ when false
170
+ raise(CommandFailed,"command failed: git pull #{args.join(' ')}")
171
+ end
172
+ end
173
+ end
174
+
175
+ #
176
+ # Checks out the git branch or tag.
177
+ #
178
+ # @param [String] branch_or_tag
179
+ # The branch or tag name to checkout.
180
+ #
181
+ # @return [true]
182
+ # Indicates that the `git` command executed successfully.
183
+ #
184
+ # @raise [CommandFailed]
185
+ #
186
+ def checkout(branch_or_tag)
187
+ Dir.chdir(@path) do
188
+ case system('git','checkout',branch_or_tag)
189
+ when nil
190
+ raise(CommandNotInstalled,"git is not installed")
191
+ when false
192
+ raise(CommandFailed,"command failed: git checkout #{branch_or_tag}")
193
+ end
194
+ end
195
+ end
196
+
197
+ #
198
+ # Updates the repository.
199
+ #
200
+ # @param [String, nil] branch
201
+ # The optional git branch to update from.
202
+ #
203
+ # @param [String, nil] tag
204
+ # The optional git tag to update to.
205
+ #
206
+ # @param [Hash{Symbol => Object}] kwargs
207
+ # Additional keyword arguments for {#pull}.
208
+ #
209
+ # @return [true]
210
+ # Indicates that the `git` commands executed successfully.
211
+ #
212
+ # @raise [CommandFailed]
213
+ # One of the `git` commands failed.
214
+ #
215
+ def update(branch: nil, tag: nil, **kwargs)
216
+ pull(branch: branch, tags: branch.nil?, **kwargs)
217
+
218
+ if branch || tag
219
+ checkout(branch || tag)
220
+ end
221
+ end
222
+
223
+ #
224
+ # Deletes the repository directory.
225
+ #
226
+ def delete
227
+ FileUtils.rm_rf(@path)
228
+ end
229
+
230
+ #
231
+ # Converts a relative path to an absolute path.
232
+ #
233
+ # @param [String] relative_path
234
+ # The relative path of the file.
235
+ #
236
+ # @return [String]
237
+ # The absolute path with respect to the repository.
238
+ #
239
+ def join(relative_path)
240
+ File.join(@path,relative_path)
241
+ end
242
+
243
+ #
244
+ # Determines if the repository contains the file.
245
+ #
246
+ # @param [String] relative_path
247
+ # The relative path of the file.
248
+ #
249
+ # @return [Boolean]
250
+ # Indicates whether the repository contains the file or not.
251
+ #
252
+ def has_file?(relative_path)
253
+ File.file?(join(relative_path))
254
+ end
255
+
256
+ #
257
+ # Determines if the repository contains the directory.
258
+ #
259
+ # @param [String] relative_path
260
+ # The relative path of the directory.
261
+ #
262
+ # @return [Boolean]
263
+ # Indicates whether the repository contains the directory or not.
264
+ #
265
+ def has_directory?(relative_path)
266
+ File.directory?(join(relative_path))
267
+ end
268
+
269
+ #
270
+ # Finds a file within the repository.
271
+ #
272
+ # @param [String] relative_path
273
+ # The relative path of the file.
274
+ #
275
+ # @return [String, nil]
276
+ # The absolute path of the matching file or `nil` if no matching file
277
+ # could be found.
278
+ #
279
+ # @example
280
+ # repo.find_file("wordlists/wordlist.txt")
281
+ # # => "/home/user/.cache/ronin-repos/foo-repo/wordlists/wordlist.txt"
282
+ #
283
+ def find_file(relative_path)
284
+ path = join(relative_path)
285
+
286
+ if File.file?(path)
287
+ return path
288
+ end
289
+ end
290
+
291
+ #
292
+ # Finds all files in the repository that matches the glob pattern.
293
+ #
294
+ # @param [String] pattern
295
+ # The file glob pattern to search for.
296
+ #
297
+ # @return [Array<String>]
298
+ # The absolute paths to the files that match the glob pattern.
299
+ #
300
+ # @example
301
+ # repo.glob("wordlists/*.txt")
302
+ # # => ["/home/user/.cache/ronin-repos/foo-repo/wordlists/cities.txt",
303
+ # # "/home/user/.cache/ronin-repos/foo-repo/wordlists/states.txt"]
304
+ #
305
+ def glob(pattern,&block)
306
+ path = join(pattern)
307
+ matches = Dir.glob(path).sort
308
+
309
+ if block then matches.each(&block)
310
+ else matches
311
+ end
312
+ end
313
+
314
+ #
315
+ # Lists the paths within the repository.
316
+ #
317
+ # @param [String] pattern
318
+ # The optional glob pattern to use to list specific files.
319
+ #
320
+ # @return [Array<String>]
321
+ # The matching paths within the repository.
322
+ #
323
+ # @example
324
+ # repo.list_files('exploits/{**/}*.rb')
325
+ # # => ["exploits/exploit1.rb", "exploits/exploit2.rb"]
326
+ #
327
+ def list_files(pattern='{**/}*.*')
328
+ Dir.glob(pattern, base: @path)
329
+ end
330
+
331
+ #
332
+ # Converts the repository to a String.
333
+ #
334
+ # @return [String]
335
+ # The name of the repository.
336
+ #
337
+ def to_s
338
+ @name
339
+ end
340
+
341
+ end
342
+ end
343
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+ #
3
+ # Copyright (c) 2021 Hal Brodigan (postmodern.mod3 at gmail.com)
4
+ #
5
+ # ronin-repos is free software: you can redistribute it and/or modify
6
+ # it under the terms of the GNU Lesser General Public License as published
7
+ # by the Free Software Foundation, either version 3 of the License, or
8
+ # (at your option) any later version.
9
+ #
10
+ # ronin-repos is distributed in the hope that it will be useful,
11
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ # GNU Lesser General Public License for more details.
14
+ #
15
+ # You should have received a copy of the GNU Lesser General Public License
16
+ # along with ronin-repos. If not, see <https://www.gnu.org/licenses/>.
17
+ #
18
+
19
+ module Ronin
20
+ module Repos
21
+ # Path to `ronin-repos` root directory.
22
+ #
23
+ # @api private
24
+ ROOT = File.expand_path(File.join(__dir__,'..','..','..'))
25
+ end
26
+ end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+ #
3
+ # Copyright (c) 2021 Hal Brodigan (postmodern.mod3 at gmail.com)
4
+ #
5
+ # ronin-repos is free software: you can redistribute it and/or modify
6
+ # it under the terms of the GNU Lesser General Public License as published
7
+ # by the Free Software Foundation, either version 3 of the License, or
8
+ # (at your option) any later version.
9
+ #
10
+ # ronin-repos is distributed in the hope that it will be useful,
11
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ # GNU Lesser General Public License for more details.
14
+ #
15
+ # You should have received a copy of the GNU Lesser General Public License
16
+ # along with ronin-repos. If not, see <https://www.gnu.org/licenses/>.
17
+ #
18
+
19
+ module Ronin
20
+ module Repos
21
+ # ronin-repos version
22
+ VERSION = '0.1.0.beta1'
23
+ end
24
+ end