pcli 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (53) hide show
  1. checksums.yaml +7 -0
  2. data/.rubocop.yml +13 -0
  3. data/CHANGELOG.md +5 -0
  4. data/Gemfile +12 -0
  5. data/Gemfile.lock +176 -0
  6. data/Rakefile +12 -0
  7. data/exe/pcli +6 -0
  8. data/lib/pcli/api_request.rb +60 -0
  9. data/lib/pcli/api_response.rb +82 -0
  10. data/lib/pcli/command_output.rb +23 -0
  11. data/lib/pcli/container.rb +54 -0
  12. data/lib/pcli/depends.rb +43 -0
  13. data/lib/pcli/main.rb +22 -0
  14. data/lib/pcli/options.rb +41 -0
  15. data/lib/pcli/output/padded.rb +32 -0
  16. data/lib/pcli/output/server_error.rb +24 -0
  17. data/lib/pcli/output.rb +6 -0
  18. data/lib/pcli/pl.rb +15 -0
  19. data/lib/pcli/services/all_commands.rb +52 -0
  20. data/lib/pcli/services/all_steps.rb +23 -0
  21. data/lib/pcli/services/api.rb +82 -0
  22. data/lib/pcli/services/api_manager.rb +28 -0
  23. data/lib/pcli/services/app.rb +31 -0
  24. data/lib/pcli/services/authenticate.rb +60 -0
  25. data/lib/pcli/services/client.rb +24 -0
  26. data/lib/pcli/services/cmd.rb +13 -0
  27. data/lib/pcli/services/commander.rb +38 -0
  28. data/lib/pcli/services/commands/login.rb +22 -0
  29. data/lib/pcli/services/commands/logout.rb +24 -0
  30. data/lib/pcli/services/commands/templates/change.rb +95 -0
  31. data/lib/pcli/services/commands/templates/list.rb +52 -0
  32. data/lib/pcli/services/commands/user/change.rb +114 -0
  33. data/lib/pcli/services/commands/user/password.rb +77 -0
  34. data/lib/pcli/services/commands/user/show.rb +47 -0
  35. data/lib/pcli/services/commands/user/totp.rb +78 -0
  36. data/lib/pcli/services/commands/users/change.rb +134 -0
  37. data/lib/pcli/services/commands/users/create.rb +67 -0
  38. data/lib/pcli/services/commands/users/list.rb +52 -0
  39. data/lib/pcli/services/commands/users/remove.rb +85 -0
  40. data/lib/pcli/services/prompt.rb +21 -0
  41. data/lib/pcli/services/qr.rb +18 -0
  42. data/lib/pcli/services/steps/authenticate.rb +17 -0
  43. data/lib/pcli/services/steps/connect.rb +35 -0
  44. data/lib/pcli/services/steps/greeting.rb +18 -0
  45. data/lib/pcli/services/steps/main.rb +51 -0
  46. data/lib/pcli/services/steps/valediction.rb +21 -0
  47. data/lib/pcli/simple_spinner_bar.rb +38 -0
  48. data/lib/pcli/step.rb +69 -0
  49. data/lib/pcli/util/cli.rb +32 -0
  50. data/lib/pcli/util/hash.rb +25 -0
  51. data/lib/pcli/version.rb +5 -0
  52. data/lib/pcli.rb +24 -0
  53. metadata +389 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: af2b54a95a2b2ae5b14f0d296eef6efc1b66a5e3ce49846f9a11a93d3082a386
4
+ data.tar.gz: fb20b79e673b7147bda3e338a1ab286c27892c6393797c1acf89b792f5d47369
5
+ SHA512:
6
+ metadata.gz: f1097c95cd45552bffaf25f6f0e8a1597a704d121cdeddd3c03ace1410930de6f61f27e4e46c042079640cc8f942e7f64d5eb848e2f3bd7199478595be36572d
7
+ data.tar.gz: bd92a2ee5cd06e2eff2feca4595abc742e1726a1734835f3067c15313664b99771a2ff2ed4e31fa67ee287136da1e9a892123b51e7bcc4d51cedcdb686e723d9
data/.rubocop.yml ADDED
@@ -0,0 +1,13 @@
1
+ AllCops:
2
+ TargetRubyVersion: 2.6
3
+
4
+ Style/StringLiterals:
5
+ Enabled: true
6
+ EnforcedStyle: single_quotes
7
+
8
+ Style/StringLiteralsInInterpolation:
9
+ Enabled: true
10
+ EnforcedStyle: single_quotes
11
+
12
+ Layout/LineLength:
13
+ Max: 120
data/CHANGELOG.md ADDED
@@ -0,0 +1,5 @@
1
+ ## [Unreleased]
2
+
3
+ ## [0.1.0] - 2023-04-02
4
+
5
+ - Initial release
data/Gemfile ADDED
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ source 'https://rubygems.org'
4
+
5
+ # Specify your gem's dependencies in pcli.gemspec
6
+ gemspec
7
+
8
+ gem 'rake', '~> 13.0'
9
+
10
+ gem 'rspec', '~> 3.0'
11
+
12
+ gem 'rubocop', '~> 1.21'
data/Gemfile.lock ADDED
@@ -0,0 +1,176 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ pcli (0.1.0)
5
+ actionview (~> 7.0)
6
+ activesupport (~> 7.0)
7
+ dry-cli (~> 1.0)
8
+ http (~> 5.1)
9
+ pastel (~> 0.8.0)
10
+ rqrcode (~> 2.0)
11
+ tty-command (~> 0.10.1)
12
+ tty-cursor (~> 0.7.1)
13
+ tty-editor (~> 0.7.0)
14
+ tty-option (~> 0.2.0)
15
+ tty-progressbar (~> 0.18.2)
16
+ tty-prompt (~> 0.23.1)
17
+ tty-screen (~> 0.8.1)
18
+ tty-spinner (~> 0.9.3)
19
+ tty-table (~> 0.12.0)
20
+ tty-which (~> 0.5.0)
21
+ zeitwerk (~> 2.6)
22
+
23
+ GEM
24
+ remote: https://rubygems.org/
25
+ specs:
26
+ actionview (7.0.4.3)
27
+ activesupport (= 7.0.4.3)
28
+ builder (~> 3.1)
29
+ erubi (~> 1.4)
30
+ rails-dom-testing (~> 2.0)
31
+ rails-html-sanitizer (~> 1.1, >= 1.2.0)
32
+ activesupport (7.0.4.3)
33
+ concurrent-ruby (~> 1.0, >= 1.0.2)
34
+ i18n (>= 1.6, < 2)
35
+ minitest (>= 5.1)
36
+ tzinfo (~> 2.0)
37
+ addressable (2.8.2)
38
+ public_suffix (>= 2.0.2, < 6.0)
39
+ ast (2.4.2)
40
+ builder (3.2.4)
41
+ byebug (11.1.3)
42
+ chunky_png (1.4.0)
43
+ concurrent-ruby (1.2.2)
44
+ crass (1.0.6)
45
+ diff-lcs (1.5.0)
46
+ domain_name (0.5.20190701)
47
+ unf (>= 0.0.5, < 1.0.0)
48
+ dry-cli (1.0.0)
49
+ erubi (1.12.0)
50
+ ffi (1.15.5)
51
+ ffi-compiler (1.0.1)
52
+ ffi (>= 1.0.0)
53
+ rake
54
+ http (5.1.1)
55
+ addressable (~> 2.8)
56
+ http-cookie (~> 1.0)
57
+ http-form_data (~> 2.2)
58
+ llhttp-ffi (~> 0.4.0)
59
+ http-cookie (1.0.5)
60
+ domain_name (~> 0.5)
61
+ http-form_data (2.3.0)
62
+ i18n (1.12.0)
63
+ concurrent-ruby (~> 1.0)
64
+ json (2.6.3)
65
+ llhttp-ffi (0.4.0)
66
+ ffi-compiler (~> 1.0)
67
+ rake (~> 13.0)
68
+ loofah (2.20.0)
69
+ crass (~> 1.0.2)
70
+ nokogiri (>= 1.5.9)
71
+ minitest (5.18.0)
72
+ nokogiri (1.14.2-x86_64-linux)
73
+ racc (~> 1.4)
74
+ parallel (1.22.1)
75
+ parser (3.2.2.0)
76
+ ast (~> 2.4.1)
77
+ pastel (0.8.0)
78
+ tty-color (~> 0.5)
79
+ public_suffix (5.0.1)
80
+ racc (1.6.2)
81
+ rails-dom-testing (2.0.3)
82
+ activesupport (>= 4.2.0)
83
+ nokogiri (>= 1.6)
84
+ rails-html-sanitizer (1.5.0)
85
+ loofah (~> 2.19, >= 2.19.1)
86
+ rainbow (3.1.1)
87
+ rake (13.0.6)
88
+ regexp_parser (2.7.0)
89
+ rexml (3.2.5)
90
+ rqrcode (2.1.2)
91
+ chunky_png (~> 1.0)
92
+ rqrcode_core (~> 1.0)
93
+ rqrcode_core (1.2.0)
94
+ rspec (3.12.0)
95
+ rspec-core (~> 3.12.0)
96
+ rspec-expectations (~> 3.12.0)
97
+ rspec-mocks (~> 3.12.0)
98
+ rspec-core (3.12.1)
99
+ rspec-support (~> 3.12.0)
100
+ rspec-expectations (3.12.2)
101
+ diff-lcs (>= 1.2.0, < 2.0)
102
+ rspec-support (~> 3.12.0)
103
+ rspec-mocks (3.12.5)
104
+ diff-lcs (>= 1.2.0, < 2.0)
105
+ rspec-support (~> 3.12.0)
106
+ rspec-support (3.12.0)
107
+ rubocop (1.49.0)
108
+ json (~> 2.3)
109
+ parallel (~> 1.10)
110
+ parser (>= 3.2.0.0)
111
+ rainbow (>= 2.2.2, < 4.0)
112
+ regexp_parser (>= 1.8, < 3.0)
113
+ rexml (>= 3.2.5, < 4.0)
114
+ rubocop-ast (>= 1.28.0, < 2.0)
115
+ ruby-progressbar (~> 1.7)
116
+ unicode-display_width (>= 2.4.0, < 3.0)
117
+ rubocop-ast (1.28.0)
118
+ parser (>= 3.2.1.0)
119
+ rubocop-rake (0.6.0)
120
+ rubocop (~> 1.0)
121
+ ruby-progressbar (1.13.0)
122
+ strings (0.2.1)
123
+ strings-ansi (~> 0.2)
124
+ unicode-display_width (>= 1.5, < 3.0)
125
+ unicode_utils (~> 1.4)
126
+ strings-ansi (0.2.0)
127
+ tty-color (0.6.0)
128
+ tty-command (0.10.1)
129
+ pastel (~> 0.8)
130
+ tty-cursor (0.7.1)
131
+ tty-editor (0.7.0)
132
+ tty-prompt (~> 0.22)
133
+ tty-option (0.2.0)
134
+ tty-progressbar (0.18.2)
135
+ strings-ansi (~> 0.2)
136
+ tty-cursor (~> 0.7)
137
+ tty-screen (~> 0.8)
138
+ unicode-display_width (>= 1.6, < 3.0)
139
+ tty-prompt (0.23.1)
140
+ pastel (~> 0.8)
141
+ tty-reader (~> 0.8)
142
+ tty-reader (0.9.0)
143
+ tty-cursor (~> 0.7)
144
+ tty-screen (~> 0.8)
145
+ wisper (~> 2.0)
146
+ tty-screen (0.8.1)
147
+ tty-spinner (0.9.3)
148
+ tty-cursor (~> 0.7)
149
+ tty-table (0.12.0)
150
+ pastel (~> 0.8)
151
+ strings (~> 0.2.0)
152
+ tty-screen (~> 0.8)
153
+ tty-which (0.5.0)
154
+ tzinfo (2.0.6)
155
+ concurrent-ruby (~> 1.0)
156
+ unf (0.1.4)
157
+ unf_ext
158
+ unf_ext (0.0.8.2)
159
+ unicode-display_width (2.4.2)
160
+ unicode_utils (1.4.0)
161
+ wisper (2.0.1)
162
+ zeitwerk (2.6.8)
163
+
164
+ PLATFORMS
165
+ x86_64-linux
166
+
167
+ DEPENDENCIES
168
+ byebug (~> 11.1)
169
+ pcli!
170
+ rake (~> 13.0)
171
+ rspec (~> 3.0)
172
+ rubocop (~> 1.21)
173
+ rubocop-rake (~> 0.6.0)
174
+
175
+ BUNDLED WITH
176
+ 2.3.22
data/Rakefile ADDED
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'bundler/gem_tasks'
4
+ require 'rspec/core/rake_task'
5
+
6
+ RSpec::Core::RakeTask.new(:spec)
7
+
8
+ require 'rubocop/rake_task'
9
+
10
+ RuboCop::RakeTask.new
11
+
12
+ task default: %i[spec rubocop]
data/exe/pcli ADDED
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require 'pcli'
5
+
6
+ Pcli::Main.new.run(ARGV)
@@ -0,0 +1,60 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pcli
4
+ class ApiRequest
5
+ def initialize(path)
6
+ @path = path
7
+ @method = 'get'
8
+ @params = {}
9
+ @headers = { 'Content-Type': 'application/json' }
10
+ end
11
+
12
+ def method(value = nil)
13
+ if value
14
+ @method = value
15
+ self
16
+ else
17
+ @method
18
+ end
19
+ end
20
+
21
+ def path(value = nil)
22
+ if value
23
+ @path = value
24
+ self
25
+ else
26
+ @path
27
+ end
28
+ end
29
+
30
+ def params(value = nil)
31
+ if value
32
+ @params = @params.merge(value)
33
+ self
34
+ else
35
+ @params
36
+ end
37
+ end
38
+
39
+ def param(key, value)
40
+ @params[key] = value
41
+ self
42
+ end
43
+
44
+ def headers(value = nil)
45
+ if value
46
+ @headers = @headers.merge(value)
47
+ self
48
+ else
49
+ @headers
50
+ end
51
+ end
52
+
53
+ def header(key, value)
54
+ @headers[key] = value
55
+ self
56
+ end
57
+
58
+ attr_writer :path, :method, :params, :headers
59
+ end
60
+ end
@@ -0,0 +1,82 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pcli
4
+ class ApiResponse
5
+ KnownError = Struct.new(:status, :type, :title, :message)
6
+
7
+ attr_reader :code, :status, :body
8
+
9
+ def initialize(code, success_status, status, body)
10
+ @code = code
11
+ @success_status = success_status
12
+ @status = status
13
+ @body = body
14
+ end
15
+
16
+ def json
17
+ if @json.nil?
18
+ begin
19
+ @json = JSON.parse(body)
20
+ rescue JSON::ParserError
21
+ @json = false
22
+ end
23
+ end
24
+
25
+ @json
26
+ end
27
+
28
+ def state
29
+ @state ||= calculate_state
30
+ end
31
+
32
+ def success?
33
+ state == :success
34
+ end
35
+
36
+ def known_error?
37
+ state == :error
38
+ end
39
+
40
+ def unknown_error?
41
+ state == :unknown_error
42
+ end
43
+
44
+ def failure?
45
+ !success?
46
+ end
47
+
48
+ def error
49
+ return @error unless @error.nil?
50
+
51
+ return @error = false unless state == :error
52
+
53
+ @error = KnownError.new(
54
+ json['status'],
55
+ json.dig('error', 'type'),
56
+ json.dig('error', 'title'),
57
+ json.dig('error', 'message')
58
+ )
59
+ end
60
+
61
+ private
62
+
63
+ def valid_error_schema
64
+ Util::Hash.has_keys?(json, 'error', 'status') &&
65
+ Util::Hash.has_keys?(json['error'], 'type', 'title', 'message')
66
+ end
67
+
68
+ def calculate_state
69
+ return :invalid_response unless json || body.nil? || body == ''
70
+
71
+ if success_status
72
+ :success
73
+ elsif valid_error_schema
74
+ :error
75
+ else
76
+ :unknown_error
77
+ end
78
+ end
79
+
80
+ attr_reader :success_status
81
+ end
82
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pcli
4
+ class CommandOutput
5
+ class << self
6
+ def halt
7
+ new(true)
8
+ end
9
+
10
+ def continue
11
+ new(false)
12
+ end
13
+ end
14
+
15
+ def initialize(halt)
16
+ @halt = halt
17
+ end
18
+
19
+ def halt?
20
+ @halt
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,54 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pcli
4
+ class Container
5
+ def initialize
6
+ @registrations = {}
7
+ @instances = {}
8
+ end
9
+
10
+ def register(name, type)
11
+ @registrations[name] = type
12
+ end
13
+
14
+ def register_instance(name, instance)
15
+ @instances[name] = instance
16
+ end
17
+
18
+ def register_module(m, hierarchy = [])
19
+ m.constants.each do |name|
20
+ c = m.const_get(name)
21
+ h = hierarchy.clone
22
+ h << name.to_s.underscore.downcase
23
+ next unless c.is_a?(Module)
24
+
25
+ if c.is_a?(Class)
26
+ registration_name = h.join('.')
27
+ register registration_name, c
28
+ end
29
+ register_module(c, h)
30
+ end
31
+ end
32
+
33
+ def resolve(name, originator = nil)
34
+ originator ||= name
35
+
36
+ return @instances[name] if @instances.key? name
37
+
38
+ raise "Unregistered dependency \"#{name}\"" unless @registrations.key? name
39
+
40
+ registration = @registrations[name]
41
+ dependencies = {}
42
+
43
+ if registration.respond_to?(:dependencies)
44
+ dependencies = registration.dependencies.map do |dependency|
45
+ raise "Circular dependency \"#{dependency}\"" if originator && dependency == originator
46
+
47
+ [dependency.to_sym, resolve(dependency, originator)]
48
+ end.to_h
49
+ end
50
+
51
+ @instances[name] = @registrations[name].new(**dependencies)
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pcli
4
+ module Depends
5
+ def self.on(*names, **kw_names)
6
+ Module.new do
7
+ class_methods = Module.new do
8
+ define_method :dependencies do
9
+ names + kw_names.values
10
+ end
11
+ end
12
+
13
+ define_singleton_method :included do |base|
14
+ base.extend class_methods
15
+ end
16
+
17
+ names.each do |name|
18
+ method_name = name.split('.').last
19
+
20
+ define_method(method_name) { @_dependencies[name] }
21
+ end
22
+
23
+ kw_names.each do |method_name, name|
24
+ define_method(method_name) { @_dependencies[name] }
25
+ end
26
+
27
+ define_method :initialize do |**args|
28
+ @_dependencies = self.class.dependencies.map { |n| [n, nil] }.to_h
29
+
30
+ args.each do |key, value|
31
+ key = key.to_s
32
+ raise "#{self.class.name} given invalid dependency \"#{key}\"" unless @_dependencies.key?(key)
33
+
34
+ @_dependencies[key] = value
35
+ end
36
+ @_dependencies.each_key do |n|
37
+ raise "#{self.class.name} missing dependency \"#{n}\"" unless args.key?(n.to_sym)
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
data/lib/pcli/main.rb ADDED
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pcli
4
+ class Main
5
+ def run(args)
6
+ options = Options.parse(args)
7
+
8
+ container = Container.new.tap do |c|
9
+ c.register_instance 'config.endpoint', options[:endpoint]
10
+ c.register_instance 'input', $stdin
11
+ c.register_instance 'output', $stdout
12
+ c.register_instance 'screen', TTY::Screen
13
+ c.register_instance 'which', TTY::Which
14
+ c.register_instance 'editor', TTY::Editor
15
+
16
+ c.register_module Services
17
+ end
18
+
19
+ container.resolve('app').run
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pcli
4
+ class Options
5
+ class TTYOption
6
+ include TTY::Option
7
+
8
+ usage do
9
+ program 'ponsqb'
10
+
11
+ desc 'Launch the Ponsqb admin CLI.'
12
+ end
13
+
14
+ option :endpoint do
15
+ short '-e'
16
+ long '--endpoint string'
17
+ default 'https://ponsqb.provisionsbs.com'
18
+ desc 'Ponsqb endpoint.'
19
+ end
20
+
21
+ flag :help do
22
+ short '-h'
23
+ long '--help'
24
+ desc 'Print usgae.'
25
+ end
26
+
27
+ def evaluate
28
+ if params[:help]
29
+ print help
30
+ exit
31
+ end
32
+
33
+ params.to_h
34
+ end
35
+ end
36
+
37
+ def self.parse(args)
38
+ TTYOption.new.parse(args).evaluate
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pcli
4
+ module Output
5
+ class Padded
6
+ def self.show(input, output, screen)
7
+ amount = 5
8
+ messages = input
9
+
10
+ messages = [messages] unless messages.respond_to?(:each)
11
+
12
+ messages = messages.flat_map { |m| m == '' ? '' : m.split("\n") }
13
+
14
+ length = screen.width - amount
15
+ result = ''
16
+
17
+ messages.each do |message|
18
+ message.each_char.with_index do |c, i|
19
+ if (i % length).zero?
20
+ result += "\n" if i.positive?
21
+ result += ' ' * amount
22
+ end
23
+ result += c
24
+ end
25
+ result += "\n"
26
+ end
27
+
28
+ output.print(result)
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pcli
4
+ module Output
5
+ class ServerError
6
+ def self.show(response, output, screen)
7
+ result = ''
8
+
9
+ if response.known_error?
10
+ output.puts 'Server:'
11
+ Output::Padded.show([
12
+ "#{Pl.yellow(response.error.title)} #{Pl.dim("(#{response.error.status})")}",
13
+ '',
14
+ response.error.message
15
+ ], output, screen)
16
+ else
17
+ output.puts "Server #{Pl.yellow("(#{response.code})")}:"
18
+ Output::Padded.show(response.body, output, screen)
19
+ end
20
+ result
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pcli
4
+ module Output
5
+ end
6
+ end
data/lib/pcli/pl.rb ADDED
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pcli
4
+ class Pl
5
+ @base = Pastel.new
6
+
7
+ class << self
8
+ delegate_missing_to :base
9
+
10
+ private
11
+
12
+ attr_reader :base
13
+ end
14
+ end
15
+ end