conify 0.0.1

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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 1341bc6fcee246543d347268d052a9f4a54d8700
4
+ data.tar.gz: bcaab7d870a605f12ae094afad844e4f4e866873
5
+ SHA512:
6
+ metadata.gz: 51a20b09d4b11d8bfc50eef1529fedd1666b9f0920ec46b3f920e46afba1840c4e35c63fe86f0c50e1d542c4c4c32dbc121a9606d721b643f8765c7758ce166a
7
+ data.tar.gz: a0dc663dc467fced8b6484a71b7b0d7859867ab14e0ba406707667017c516f70fbd0023d73f8e892ee88d08a32e7f6a1434e45f2d5caa3f62c9cddc133f25bbf
Binary file
@@ -0,0 +1,13 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ /.idea/
11
+ /.conflux/
12
+ /configs.yml
13
+ /conflux-manifest.json
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --format documentation
2
+ --color
@@ -0,0 +1,4 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.0.0
4
+ before_install: gem install bundler -v 1.11.2
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in conify.gemspec
4
+ gemspec
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2016 Ben Whittle
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
@@ -0,0 +1,9 @@
1
+ # Conify
2
+
3
+ ## Contributing
4
+
5
+ To contribute to this repo, submit a pull request or raise an issue in the issues section with an appropriate issue tag.
6
+
7
+ ## License
8
+
9
+ [MIT License](http://opensource.org/licenses/MIT).
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
@@ -0,0 +1,30 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ lib = File.expand_path(File.dirname(__FILE__) + '/../lib')
4
+ $LOAD_PATH.unshift(lib) if File.directory?(lib) && !$LOAD_PATH.include?(lib)
5
+
6
+ # Fixes https://github.com/rubygems/rubygems/issues/1420
7
+ require 'rubygems/specification'
8
+
9
+ class Gem::Specification
10
+ def this
11
+ self
12
+ end
13
+ end
14
+
15
+ # Create way to set config vars during development --> put them in configs.yml inside root of this project
16
+ config_vars_path = File.expand_path(File.dirname(__FILE__) + '/../configs.yml')
17
+
18
+ if File.exists?(config_vars_path)
19
+ require 'yaml'
20
+
21
+ configs = YAML::load_file(config_vars_path) rescue {}
22
+
23
+ (configs || {}).each { |key, val|
24
+ ENV[key] = val if !ENV.key?(key)
25
+ }
26
+ end
27
+
28
+ require 'conify/cli'
29
+
30
+ Conify::CLI.start!(*ARGV)
@@ -0,0 +1,7 @@
1
+ require 'rubygems'
2
+ require 'bundler'
3
+
4
+ Bundler.require :default, :development
5
+
6
+ Combustion.initialize! :all
7
+ run Combustion::Application
@@ -0,0 +1,27 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'conify/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "conify"
8
+ spec.version = Conify::VERSION
9
+ spec.authors = ["Ben Whittle"]
10
+ spec.email = ["benwhittle31@gmail.com"]
11
+ spec.summary = "A gem to help developer tools integrate their services with Conflux"
12
+ spec.homepage = "https://www.github.com/GoConflux/conify"
13
+ spec.license = "MIT"
14
+
15
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
16
+ spec.bindir = "bin"
17
+ spec.executables = ["conify"]
18
+ spec.require_paths = ["lib"]
19
+
20
+ spec.add_runtime_dependency "mechanize", "~> 2.6.0"
21
+ spec.add_runtime_dependency "rest-client", "~> 2.0.0"
22
+
23
+ spec.add_development_dependency "bundler", "~> 1.11"
24
+ spec.add_development_dependency "rake", "~> 10.0"
25
+ spec.add_development_dependency "rspec", "~> 3.0"
26
+ spec.add_development_dependency "pry"
27
+ end
Binary file
@@ -0,0 +1,2 @@
1
+ module Conify
2
+ end
@@ -0,0 +1,4 @@
1
+ module Conify
2
+ module Api
3
+ end
4
+ end
@@ -0,0 +1,78 @@
1
+ require 'conify/api'
2
+ require 'conify/helpers'
3
+ require 'net/http'
4
+ require 'net/https'
5
+ require 'uri'
6
+ require 'json'
7
+
8
+ # Used to make requests to the Conflux API
9
+ class Conify::Api::AbstractApi
10
+ include Conify::Helpers
11
+
12
+ def get(route, data: {}, headers: {}, error_message: 'Error making request', show_err_response: false)
13
+ form_request(Net::HTTP::Get, route, data, headers, error_message, show_err_response)
14
+ end
15
+
16
+ def post(route, data: {}, headers: {}, error_message: 'Error making request', show_err_response: false)
17
+ json_request(Net::HTTP::Post, route, data, headers, error_message, show_err_response)
18
+ end
19
+
20
+ def put(route, data: {}, headers: {}, error_message: 'Error making request', show_err_response: false)
21
+ json_request(Net::HTTP::Put, route, data, headers, error_message, show_err_response)
22
+ end
23
+
24
+ def delete(route, data: {}, headers: {}, error_message: 'Error making request', show_err_response: false)
25
+ form_request(Net::HTTP::Delete, route, data, headers, error_message, show_err_response)
26
+ end
27
+
28
+ def ssl_check_win(net_http)
29
+ case RUBY_PLATFORM
30
+ when /win/i, /ming/i
31
+ net_http.verify_mode = OpenSSL::SSL::VERIFY_NONE if net_http.use_ssl?
32
+ end
33
+ end
34
+
35
+ def http
36
+ uri = URI.parse(host_url)
37
+ http = Net::HTTP.new(uri.host, uri.port)
38
+ http.use_ssl = true if uri.scheme == 'https'
39
+ ssl_check_win(http)
40
+ http
41
+ end
42
+
43
+ def form_request(net_obj, route, data, headers, error_message, show_err_response)
44
+ route = data.empty? ? route : "#{route}?#{URI.encode_www_form(data)}"
45
+ request = net_obj.new("/api#{route}")
46
+ request.add_field('Content-Type', 'application/x-www-form-urlencoded')
47
+ add_headers(request, headers)
48
+ response = http.request(request)
49
+ handle_json_response(response, error_message, show_err_response)
50
+ end
51
+
52
+ def json_request(net_obj, route, data, headers, error_message, show_err_response)
53
+ request = net_obj.new("/api#{route}")
54
+ request.add_field('Content-Type', 'application/json')
55
+ add_headers(request, headers)
56
+ request.body = data.to_json
57
+ response = http.request(request)
58
+ handle_json_response(response, error_message, show_err_response)
59
+ end
60
+
61
+ def add_headers(request, headers = {})
62
+ headers.each { |key, val| request.add_field(key, val) }
63
+ end
64
+
65
+ def handle_json_response(response, error_message, show_err_response)
66
+ if response.code.to_i == 200
67
+ JSON.parse(response.body) rescue {}
68
+ else
69
+ if show_err_response
70
+ json_err = JSON.parse(response.body) rescue {}
71
+ error json_err['message'] || response.body
72
+ else
73
+ error error_message
74
+ end
75
+ end
76
+ end
77
+
78
+ end
@@ -0,0 +1,19 @@
1
+ require 'conify/api/abstract_api'
2
+
3
+ class Conify::Api::Addons < Conify::Api::AbstractApi
4
+
5
+ def extension
6
+ '/addons'
7
+ end
8
+
9
+ # Push draft service to Conflux
10
+ def push(manifest, token)
11
+ post(
12
+ "#{extension}/push",
13
+ data: { manifest: manifest },
14
+ headers: { 'Conflux-User' => token },
15
+ show_err_response: true
16
+ )
17
+ end
18
+
19
+ end
@@ -0,0 +1,18 @@
1
+ require 'conify/api/abstract_api'
2
+
3
+ class Conify::Api::Users < Conify::Api::AbstractApi
4
+
5
+ def extension
6
+ '/users'
7
+ end
8
+
9
+ # Exchange email/password for Conflux user_token
10
+ def login(creds)
11
+ post(
12
+ "#{extension}/login",
13
+ data: creds,
14
+ error_message: "Invalid credentials.\nMake sure you have a valid Conflux account before proceeding."
15
+ )
16
+ end
17
+
18
+ end
@@ -0,0 +1,29 @@
1
+ require 'conify/helpers'
2
+
3
+ module Conify
4
+ module CLI
5
+ extend Conify::Helpers
6
+
7
+ def self.start!(*args)
8
+ # Setup StdIn/StdOut sync
9
+ $stdin.sync = true if $stdin.isatty
10
+ $stdout.sync = true if $stdout.isatty
11
+
12
+ # Strip out command
13
+ command = args.shift.strip rescue 'help'
14
+
15
+ require 'conify/command'
16
+
17
+ # Find and run command if it exists
18
+ Conify::Command.find_command(command, args)
19
+
20
+ rescue Errno::EPIPE => e
21
+ error(e.message)
22
+ rescue Interrupt => e
23
+ error('Command cancelled.')
24
+ rescue => e
25
+ error(e)
26
+ end
27
+
28
+ end
29
+ end
@@ -0,0 +1,286 @@
1
+ require 'conify/helpers'
2
+ require 'conify/version'
3
+ require 'optparse'
4
+ require 'pathname'
5
+
6
+ module Conify
7
+ module Command
8
+ extend Conify::Helpers
9
+ extend self
10
+
11
+ CMD_BLACKLIST = []
12
+
13
+ # Finds file/method for command
14
+ def find_command(cmd, args = [])
15
+ @current_cmd = cmd
16
+ @current_args = args
17
+
18
+ respond_with_help if seeking_help?
19
+ respond_with_version if seeking_version?
20
+
21
+ # Separate out primary/secondary commands based on if command was namespaced
22
+ # e.g. `conify services vs. conify services:add`
23
+ primary_cmd, secondary_cmd = @current_cmd.split(':')
24
+
25
+ # Get the command file path (string) for the primary command
26
+ primary_cmd_file = file_for_command(primary_cmd)
27
+
28
+ # If the primary command has it's own file, require it
29
+ primary_cmd_file_exists = File.exists?(primary_cmd_file)
30
+ require primary_cmd_file if primary_cmd_file_exists
31
+
32
+ # If a secondary command exists, the primary_cmd_file must be where our command method lies
33
+ if !secondary_cmd.nil?
34
+ error_no_command if !primary_cmd_file_exists
35
+
36
+ # Get command_klass for file path. Example response --> Conify::Command::Services
37
+ command_klass = klass_for_file(primary_cmd_file)
38
+
39
+ # Error out if the command klass doesn't have a method named <secondary_cmd>
40
+ error_no_command if !klass_has_method?(command_klass, secondary_cmd)
41
+
42
+ run(command_klass, secondary_cmd)
43
+
44
+ # If there's no secondary command, there are 2 options for where the command method could be (in order of priority):
45
+ # (1) Inside the primary command file as the 'index' method
46
+ # (2) Inside the global command file, as a method named <primary_cmd>
47
+ else
48
+ # Store lambda for later
49
+ try_global = lambda {
50
+ require 'conify/command/global'
51
+ command_klass = Conify::Command::Global
52
+ error_no_command if !klass_has_method?(command_klass, primary_cmd)
53
+ run(command_klass, primary_cmd)
54
+ }
55
+
56
+ # Number 1 above. If primary_cmd file exists, call the index method on it if it exists.
57
+ # If index method doens't exist, check to see if method is a global command.
58
+ if primary_cmd_file_exists
59
+ # Get command_klass for file path. Example response --> Conify::Command::Services
60
+ command_klass = klass_for_file(primary_cmd_file)
61
+
62
+ klass_has_method?(command_klass, 'index') ? run(command_klass, 'index') : try_global.call
63
+
64
+ # Number 2 above. Check to see if method is a global command inside command/global.rb
65
+ else
66
+ try_global.call
67
+ end
68
+ end
69
+ end
70
+
71
+ # Call a method on a klass with certain arguments.
72
+ # Will validate arguments first before calling method.
73
+ def run(klass, method)
74
+ # Get the command info for this method on this klass
75
+ command_info_module = klass::CommandInfo.const_get(camelize(method))
76
+
77
+ # If seeking help for this command with --help or -h
78
+ if seeking_command_help?(@current_args)
79
+ puts "\nPurpose: #{command_description(command_info_module)}\n"
80
+
81
+ # respond with command-specific help
82
+ respond_with_command_help(command_info_module)
83
+ return
84
+ end
85
+
86
+ # get the valid arguments defined for this comand
87
+ valid_args = command_valid_args(command_info_module)
88
+
89
+ if !valid_args?(valid_args)
90
+ handle_invalid_args(command_info_module)
91
+ return
92
+ end
93
+
94
+ klass.new(@current_args.dup).send(method)
95
+ end
96
+
97
+ # Get a command klass back from a file path:
98
+ # Example I/O: 'command/bundles' --> Conify::Command::Bundles
99
+ def klass_for_file(file)
100
+ # Get basename for the file without the extension
101
+ basename = get_basename_from_file(file)
102
+
103
+ # Camelcase the basename to be the klass name
104
+ klass_name = camelize(basename)
105
+
106
+ # return the command klass for this klass_name
107
+ Conify::Command.const_get(klass_name)
108
+ end
109
+
110
+ # Create a command file path from the name of a command
111
+ def file_for_command(command)
112
+ File.join(File.dirname(__FILE__), 'command', "#{command}.rb")
113
+ end
114
+
115
+ # Check to see if user-defined method exists on a klass
116
+ def klass_has_method?(klass, method)
117
+ manually_added_methods(klass).include?(method.to_sym)
118
+ end
119
+
120
+ def error_no_command
121
+ error([
122
+ "`#{@current_cmd}` is not a conify command.",
123
+ "Type `conify help` for a list of available commands."
124
+ ].compact.join("\n"))
125
+ end
126
+
127
+ # Check if passed-in arguments are valid for a specific format
128
+ def valid_args?(accepted_arg_formats)
129
+ valid_args = false
130
+
131
+ accepted_arg_formats.each { |format|
132
+ # if no arguments exist, and no arguments is an accepted format, args are valid.
133
+ if format.empty? && @current_args.empty?
134
+ valid_args = true
135
+ else
136
+ passed_in_args = @current_args.clone
137
+
138
+ format.each_with_index { |arg, i|
139
+ passed_in_args[i] = arg if CMD_BLACKLIST.include?(arg)
140
+ }
141
+
142
+ @invalid_args = passed_in_args - format - [nil]
143
+
144
+ valid_args = true if passed_in_args == format
145
+ end
146
+ }
147
+
148
+ valid_args
149
+ end
150
+
151
+ # Respond to the user in the instance of invalid arguments.
152
+ def handle_invalid_args(command_info_module)
153
+ if !@invalid_args.empty?
154
+ message = 'Invalid argument'
155
+ message += 's' if @invalid_args.length > 1
156
+ args = @invalid_args.map { |arg| "\"#{arg}\"" }.join(', ')
157
+
158
+ puts " ! #{message}: #{args}"
159
+ else
160
+ puts " ! Invalid command usage"
161
+ end
162
+
163
+ respond_with_command_help(command_info_module)
164
+ end
165
+
166
+ def command_valid_args(command_info_module)
167
+ command_info_module.const_defined?('VALID_ARGS') ? command_info_module::VALID_ARGS : []
168
+ end
169
+
170
+ def command_description(command_info_module)
171
+ command_info_module.const_defined?('DESCRIPTION') ? command_info_module::DESCRIPTION : ''
172
+ end
173
+
174
+ # stdin is `conify help` or `conify -h`
175
+ def seeking_help?
176
+ @current_args.length == 0 && (@current_cmd.empty? || ['help', '--help', '-h'].include?(@current_cmd))
177
+ end
178
+
179
+ def respond_with_help
180
+ create_commands_map
181
+
182
+ header = [
183
+ 'Usage: conify COMMAND [command-specific-arguments]',
184
+ 'Type "conify COMMAND --help" for more details about each command',
185
+ 'Commands:'
186
+ ].join("\n\n")
187
+
188
+ commands_info = usage_info(commands)
189
+
190
+ puts "\n#{header}"
191
+ puts "\n#{commands_info}\n\n"
192
+ exit(0)
193
+ end
194
+
195
+ # Create a commands map to respond to `conify help` with.
196
+ def create_commands_map
197
+ # Require all the ruby command files
198
+ command_file_paths.each do |file|
199
+ require file
200
+
201
+ # Get basename for the file without the extension
202
+ basename = get_basename_from_file(file)
203
+
204
+ # Camelcase the basename to be the klass name
205
+ klass_name = camelize(basename)
206
+
207
+ # return the command klass for this klass_name
208
+ command_klass = Conify::Command.const_get(klass_name)
209
+
210
+ # For each of the user-defined methods inside this class, create a command for it
211
+ manually_added_methods(command_klass).each { |method|
212
+ register_command(basename, method.to_s, command_klass, global: basename == 'global')
213
+ }
214
+ end
215
+ end
216
+
217
+ # Format a map of commands into help output format
218
+ def usage_info(map)
219
+ keys = map.keys
220
+ commands_column_width = keys.max_by(&:length).length + 1
221
+ commands_column_width += 2 if commands_column_width < 12
222
+
223
+ # iterate through each of the commands, create an array
224
+ # of strings in a `<command> # <description>` format. Sort
225
+ # them alphabetically, and then join them with new lines.
226
+ keys.map { |key|
227
+ command = " #{key}"
228
+ command += (' ' * (commands_column_width - key.length + 1))
229
+ command += "# #{map[key][:description]}"
230
+ command
231
+ }.sort_by{ |k| k.downcase }.join("\n")
232
+ end
233
+
234
+ # Seeking command-specific help. e.g. `conify bundles --help`
235
+ def seeking_command_help?(args)
236
+ args.include?('-h') || args.include?('--help')
237
+ end
238
+
239
+ # Respond to command-specific help
240
+ def respond_with_command_help(command_info_module)
241
+ help = "\nValid Command Formats:\n\n"
242
+
243
+ command_valid_args(command_info_module).each { |format|
244
+ help += "# conify #{@current_cmd} #{format.join(' ')}\n"
245
+ }
246
+
247
+ puts "#{help}\n"
248
+ end
249
+
250
+ # stdin is `conify --version` or `conify -v`
251
+ def seeking_version?
252
+ @current_args.length == 0 && (@current_cmd == '--version' || @current_cmd == '-v')
253
+ end
254
+
255
+ def respond_with_version
256
+ display "conify #{Conify::VERSION}"
257
+ exit(0)
258
+ end
259
+
260
+ # Return just the basename for a file, no extensions.
261
+ def get_basename_from_file(file)
262
+ basename = Pathname.new(file).basename.to_s
263
+ basename[0..(basename.rindex('.') - 1)]
264
+ end
265
+
266
+ # Feturn an array of all command file paths, with the exception of abstract_command.rb
267
+ def command_file_paths
268
+ abstract_file = File.join(File.dirname(__FILE__), 'command', 'abstract_command.rb')
269
+ Dir[File.join(File.dirname(__FILE__), 'command', '*.rb')] - [abstract_file]
270
+ end
271
+
272
+ def commands
273
+ @@commands ||= {}
274
+ end
275
+
276
+ # register a command's info to the @@commands map - utilized when calling `conify help`
277
+ def register_command(basename, action, command_class, global: false)
278
+ command = global ? action : (action == 'index' ? basename : "#{basename}:#{action}")
279
+
280
+ command_info_module = command_class::CommandInfo.const_get(camelize(action))
281
+
282
+ commands[command] = { description: command_description(command_info_module) }
283
+ end
284
+
285
+ end
286
+ end