conify 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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