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,267 @@
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
+ require 'ronin/repos/repository'
21
+ require 'ronin/core/home'
22
+
23
+ require 'set'
24
+
25
+ module Ronin
26
+ module Repos
27
+ #
28
+ # Manages the `~/.cache/ronin-repos/` directory and the repositories
29
+ # contained within.
30
+ #
31
+ # @api private
32
+ #
33
+ class CacheDir
34
+
35
+ include Enumerable
36
+
37
+ # The ~/.cache/ronin-repos/ directory where all repos are stored.
38
+ PATH = Core::Home.cache_dir('ronin-repos')
39
+
40
+ # The path to the cache directory.
41
+ #
42
+ # @return [String]
43
+ attr_reader :path
44
+
45
+ #
46
+ # Initializes the repository cache.
47
+ #
48
+ # @param [String] path
49
+ # The path to the repository cache directory.
50
+ #
51
+ def initialize(path=PATH)
52
+ @path = path
53
+ end
54
+
55
+ #
56
+ # Accesses a repository from the cache directory.
57
+ #
58
+ # @param [String] name
59
+ # The name of the repository.
60
+ #
61
+ # @return [Repository]
62
+ # The repository from the cache.
63
+ #
64
+ # @raise [RepositoryNotFound]
65
+ # No repository exists with the given name in the cache directory.
66
+ #
67
+ def [](name)
68
+ path = File.join(@path,name.to_s)
69
+
70
+ unless File.directory?(path)
71
+ raise(RepositoryNotFound,"repository not found: #{name.inspect}")
72
+ end
73
+
74
+ return Repository.new(path)
75
+ end
76
+
77
+ #
78
+ # Enumerates through every repository in the cache directory.
79
+ #
80
+ # @yield [repo]
81
+ # The given block will be passed each repository.
82
+ #
83
+ # @yieldparam [Repository] repo
84
+ # A repository from the cache directory.
85
+ #
86
+ # @return [Enumerator]
87
+ # If no block is given, an Enumerator will be returned.
88
+ #
89
+ def each
90
+ return enum_for unless block_given?
91
+
92
+ each_child_directory do |path|
93
+ yield Repository.new(path)
94
+ end
95
+ end
96
+
97
+ #
98
+ # Clones and installs a repository into the cache directory.
99
+ #
100
+ # @param [String, URI::HTTPS] uri
101
+ # The URI to clone the repository from.
102
+ #
103
+ # @param [String, nil] name
104
+ # The explicit name of the repository to use. Defaults to the base-name
105
+ # of the URI's path, sans any `.git` extension.
106
+ #
107
+ # @return [Repository]
108
+ # The newly installed repository.
109
+ #
110
+ # @raise [CommandFailed]
111
+ # One of the `git` commands failed.
112
+ #
113
+ # @raise [CommandNotInstalled]
114
+ # The `git` command is not installed.
115
+ #
116
+ def install(uri,name=nil)
117
+ uri = uri.to_s
118
+ name ||= File.basename(uri,File.extname(uri))
119
+ path = File.join(@path,name)
120
+
121
+ return Repository.install(uri,path)
122
+ end
123
+
124
+ #
125
+ # Updates all repositories in the cache directory.
126
+ #
127
+ # @raise [CommandNotInstalled]
128
+ # The `git` command is not installed.
129
+ #
130
+ def update
131
+ each do |repo|
132
+ begin
133
+ repo.update
134
+ rescue CommandFailed
135
+ end
136
+ end
137
+ end
138
+
139
+ #
140
+ # Removes a repository from the cache directory.
141
+ #
142
+ # @param [String] name
143
+ # The repository name to find and delete.
144
+ #
145
+ # @raise [RepositoryNotFound]
146
+ # The repository with the given name does not exist in the cache
147
+ # directory.
148
+ #
149
+ def remove(name)
150
+ self[name].delete
151
+ end
152
+
153
+ #
154
+ # Deletes all repositories in the cache directory.
155
+ #
156
+ def purge
157
+ each(&:delete)
158
+ end
159
+
160
+ #
161
+ # Finds the first matching file.
162
+ #
163
+ # @param [String] path
164
+ # The relative path of the file.
165
+ #
166
+ # @return [String, nil]
167
+ # The absolute path of the matching file or `nil` if no matching file
168
+ # could be found.
169
+ #
170
+ # @example
171
+ # repos.find_file("wordlists/wordlist.txt")
172
+ # # => "/home/user/.cache/ronin-repos/foo-repo/wordlists/wordlist.txt"
173
+ #
174
+ def find_file(path)
175
+ each do |repo|
176
+ if (file = repo.find_file(path))
177
+ return file
178
+ end
179
+ end
180
+ end
181
+
182
+ #
183
+ # Finds all files in all repos that matches the glob pattern.
184
+ #
185
+ # @param [String] pattern
186
+ # The file glob pattern to search for.
187
+ #
188
+ # @return [Array<String>]
189
+ # The absolute paths to the files that match the glob pattern.
190
+ #
191
+ # @example
192
+ # repos.glob("wordlists/*.txt")
193
+ # # => ["/home/user/.cache/ronin-repos/foo-repo/wordlists/cities.txt",
194
+ # # "/home/user/.cache/ronin-repos/foo-repo/wordlists/states.txt",
195
+ # # "/home/user/.cache/ronin-repos/bar-repo/wordlists/bands.txt",
196
+ # # "/home/user/.cache/ronin-repos/bar-repo/wordlists/beers.txt"]
197
+ #
198
+ def glob(pattern,&block)
199
+ return enum_for(__method__,pattern).to_a unless block_given?
200
+
201
+ each do |repo|
202
+ repo.glob(pattern,&block)
203
+ end
204
+ end
205
+
206
+ #
207
+ # Lists all files across all repos installed in the cache directory.
208
+ #
209
+ # @param [String] pattern
210
+ # The optional glob pattern to use to list specific files.
211
+ #
212
+ # @return [Set<String>]
213
+ # The matching paths within the repository.
214
+ #
215
+ # @example
216
+ # repos.list_files('exploits/{**/}*.rb')
217
+ # # => #<Set: {"exploits/exploit1.rb", "exploits/exploit2.rb"}>
218
+ #
219
+ def list_files(pattern='{**/}*.*')
220
+ each_with_object(Set.new) do |repo,files|
221
+ files.merge(repo.list_files(pattern))
222
+ end
223
+ end
224
+
225
+ #
226
+ # Converts the cache directory to a String.
227
+ #
228
+ # @return [String]
229
+ # The path to the cache directory.
230
+ #
231
+ def to_s
232
+ @path
233
+ end
234
+
235
+ private
236
+
237
+ #
238
+ # Enumerates over each directory in the cache directory.
239
+ #
240
+ # @yield [dir]
241
+ # The given block will be passed each repository's directory path.
242
+ #
243
+ # @yieldparam [String] dir
244
+ # A path to a repository directory within the cache directory.
245
+ #
246
+ # @return [Enumerator]
247
+ # If no block is given, an Enumerator will be returned.
248
+ #
249
+ def each_child_directory
250
+ return enum_for(__method__) unless block_given?
251
+
252
+ if File.directory?(@path)
253
+ Dir.children(@path).sort.each do |name|
254
+ path = File.join(@path,name)
255
+
256
+ if File.directory?(path)
257
+ yield path
258
+ end
259
+ end
260
+ end
261
+
262
+ return nil
263
+ end
264
+
265
+ end
266
+ end
267
+ end
@@ -0,0 +1,150 @@
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'
20
+ require 'ronin/core/class_registry'
21
+
22
+ require 'set'
23
+
24
+ module Ronin
25
+ module Repos
26
+ #
27
+ # Adds the ability to load classes from directories within installed
28
+ # repositories.
29
+ #
30
+ # ## Example
31
+ #
32
+ # `lib/ronin/exploits.rb`:
33
+ #
34
+ # require 'ronin/core/module_registry'
35
+ # require 'ronin/repos/class_dir'
36
+ #
37
+ # module Ronin
38
+ # module Exploits
39
+ # include Ronin::Core::ClassRegistry
40
+ # include Ronin::Repos::ClassDir
41
+ #
42
+ # class_dir "#{__dir__}/classes"
43
+ # repo_class_dir "exploits"
44
+ # end
45
+ # end
46
+ #
47
+ # `lib/ronin/exploits/exploit.rb`:
48
+ #
49
+ # module Ronin
50
+ # module Exploits
51
+ # class Exploit
52
+ #
53
+ # def self.register(name)
54
+ # Exploits.register(name,self)
55
+ # end
56
+ #
57
+ # end
58
+ # end
59
+ # end
60
+ #
61
+ # `~/.cache/ronin-repos/repo1/exploits/my_exploit.rb`:
62
+ #
63
+ # require 'ronin/exploits/exploit'
64
+ #
65
+ # module Ronin
66
+ # module Exploits
67
+ # class MyExploit < Exploit
68
+ #
69
+ # register 'my_exploit'
70
+ #
71
+ # end
72
+ # end
73
+ # end
74
+ #
75
+ # @api semipublic
76
+ #
77
+ module ClassDir
78
+ #
79
+ # Includes `Ronin::Core::ClassRegistry` and adds {ClassMethods}.
80
+ #
81
+ # @param [Module] namespace
82
+ # The module that is including {ClassDir}.
83
+ #
84
+ # @api private
85
+ #
86
+ def self.included(namespace)
87
+ namespace.send :include, Core::ClassRegistry
88
+ namespace.extend ClassMethods
89
+ end
90
+
91
+ module ClassMethods
92
+ #
93
+ # Gets or sets the repository module directory name.
94
+ #
95
+ # @param [String, nil] new_dir
96
+ # The new module directory path.
97
+ #
98
+ # @return [String]
99
+ # The repository module directory name.
100
+ #
101
+ # @raise [NotImplementedError]
102
+ # The `repo_class_dir` method was not defined in the module.
103
+ #
104
+ # @example
105
+ # repo_class_dir "exploits"
106
+ #
107
+ def repo_class_dir(new_dir=nil)
108
+ if new_dir
109
+ @repo_class_dir = new_dir
110
+ else
111
+ @repo_class_dir || raise(NotImplementedError,"#{self} did not define a repo_class_dir")
112
+ end
113
+ end
114
+
115
+ #
116
+ # List the module names within the `class_dir` and within
117
+ # {#repo_class_dir} across all installed repositories.
118
+ #
119
+ # @return [Array<String>]
120
+ #
121
+ def list_files
122
+ modules = Set.new(super)
123
+ pattern = File.join(repo_class_dir,"{**/}*.rb")
124
+
125
+ Repos.list_files(pattern).each do |path|
126
+ modules << path.chomp('.rb')
127
+ end
128
+
129
+ return modules.to_a
130
+ end
131
+
132
+ #
133
+ # Finds a module within `class_dir` or within `repo_class_dir`
134
+ # in one of the installed repositories.
135
+ #
136
+ # @param [String] name
137
+ # The module name to lookup.
138
+ #
139
+ # @return [String, nil]
140
+ # The path to the module or `nil` if the module could not be found
141
+ # in `class_dir` or any of the installed repositories.
142
+ #
143
+ def path_for(name)
144
+ super(name) ||
145
+ Repos.find_file(File.join(repo_class_dir,"#{name}.rb"))
146
+ end
147
+ end
148
+ end
149
+ end
150
+ end
@@ -0,0 +1,63 @@
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/root'
20
+ require 'ronin/repos/cache_dir'
21
+
22
+ require 'ronin/core/cli/command'
23
+
24
+ module Ronin
25
+ module Repos
26
+ class CLI
27
+ class Command < Core::CLI::Command
28
+
29
+ man_dir File.join(ROOT,'man')
30
+
31
+ bug_report_url 'https://github.com/ronin-rb/ronin-repos/issues/new'
32
+
33
+ option :cache_dir, short: '-C',
34
+ value: {
35
+ type: String,
36
+ usage: 'DIR'
37
+ },
38
+ desc: 'Overrides the default cache directory' do |dir|
39
+ @cache_dir = CacheDir.new(dir)
40
+ end
41
+
42
+
43
+ # The ronin-repos cache directory.
44
+ #
45
+ # @return [CacheDir]
46
+ attr_reader :cache_dir
47
+
48
+ #
49
+ # Initializes the command.
50
+ #
51
+ # @param [Hash{Symbol => Object}] kwargs
52
+ # Additional keyword arguments for `initialize`.
53
+ #
54
+ def initialize(**kwargs)
55
+ super(**kwargs)
56
+
57
+ @cache_dir = CacheDir.new
58
+ end
59
+
60
+ end
61
+ end
62
+ end
63
+ 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
+ # Installs a git repository into the cache directory.
27
+ #
28
+ # ## Usage
29
+ #
30
+ # ronin-repos install [options] [REPO]
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
+ # URI URI of the git repository
40
+ #
41
+ class Install < Command
42
+
43
+ usage '[options] URI'
44
+
45
+ argument :uri, required: true,
46
+ usage: 'URI',
47
+ desc: 'URI of the git repository'
48
+
49
+ description 'Installs a git repository into the cache directory'
50
+
51
+ man_page 'ronin-repos-install.1'
52
+
53
+ #
54
+ # Runs the `ronin-repos install` command.
55
+ #
56
+ # @param [String] uri
57
+ # The repository's git URI to install from.
58
+ #
59
+ def run(uri)
60
+ log_info "Installing repository from #{uri} ..."
61
+ cache_dir.download(uri)
62
+ rescue CommandFailed => 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,80 @@
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
+ # Lists all repositories in the cache directory.
27
+ #
28
+ # ## Usage
29
+ #
30
+ # ronin-repos list [options] [REPO]
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] Optional repository name to list
40
+ #
41
+ class List < Command
42
+
43
+ usage '[options] [REPO]'
44
+
45
+ argument :name, required: false,
46
+ usage: 'REPO',
47
+ desc: 'Optional repository name to list'
48
+
49
+ description 'Lists all repositories in the cache directory'
50
+
51
+ man_page 'ronin-repos-list.1'
52
+
53
+ #
54
+ # Runs the `ronin-repos list` command.
55
+ #
56
+ # @param [String, nil] name
57
+ # The optional repo name to list.
58
+ #
59
+ def run(name=nil)
60
+ if name
61
+ begin
62
+ repo = cache_dir[name]
63
+
64
+ puts " #{repo}"
65
+ rescue RepositoryNotFound => error
66
+ print_error(error.message)
67
+ exit(-1)
68
+ end
69
+ else
70
+ cache_dir.each do |repo|
71
+ puts " #{repo}"
72
+ end
73
+ end
74
+ end
75
+
76
+ end
77
+ end
78
+ end
79
+ end
80
+ end
@@ -0,0 +1,83 @@
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
+ require 'ronin/repos/root'
21
+
22
+ require 'ronin/core/cli/generator'
23
+ require 'ronin/core/git'
24
+
25
+ module Ronin
26
+ module Repos
27
+ class CLI
28
+ module Commands
29
+ #
30
+ # Creates a new git repository.
31
+ #
32
+ # ## Usage
33
+ #
34
+ # ronin-repos new [options] PATH
35
+ #
36
+ # ## Options
37
+ #
38
+ # -C, --cache-dir DIR Overrides the default cache directory
39
+ # -h, --help Print help information
40
+ #
41
+ # ## Arguments
42
+ #
43
+ # PATH The path to the new repository
44
+ #
45
+ class New < Command
46
+
47
+ include Core::CLI::Generator
48
+
49
+ template_dir File.join(ROOT,'data','templates','repo')
50
+
51
+ usage '[options] PATH'
52
+
53
+ argument :path, desc: 'The path to the new repository'
54
+
55
+ description 'Creates a new git repository'
56
+
57
+ man_page 'ronin-repos.1'
58
+
59
+ #
60
+ # Runs the `ronin-repos new` command.
61
+ #
62
+ # @param [String] path
63
+ # The path to the new repo directory to create.
64
+ #
65
+ def run(path)
66
+ @name = File.basename(path)
67
+ @github_user = Core::Git.github_user || ENV['USER']
68
+
69
+ mkdir path
70
+ erb 'README.md.erb', File.join(path,'README.md')
71
+
72
+ Dir.chdir(path) do
73
+ sh 'git', 'init', '-q', '-b', 'main'
74
+ sh 'git', 'add', 'README.md'
75
+ sh 'git', 'commit', '-q', '-m', 'Initial commit.'
76
+ end
77
+ end
78
+
79
+ end
80
+ end
81
+ end
82
+ end
83
+ end