fox 0.0.2 → 0.4.0
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.
- checksums.yaml +4 -4
- data/README.md +196 -14
- data/bin/fox +28 -8
- data/fox.gemspec +41 -3
- data/lib/fox.rb +23 -10
- data/lib/fox/cli.rb +17 -0
- data/lib/fox/configuration.rb +48 -0
- data/lib/fox/core_ext.rb +8 -0
- data/lib/fox/core_ext/array.rb +51 -0
- data/lib/fox/core_ext/hash.rb +17 -0
- data/lib/fox/core_ext/io_binary_read.rb +20 -0
- data/lib/fox/error.rb +8 -0
- data/lib/fox/error/errors.rb +232 -0
- data/lib/fox/interface/thor/all.rb +34 -0
- data/lib/fox/interface/thor/configuration.rb +71 -0
- data/lib/fox/interface/thor/create.rb +49 -0
- data/lib/fox/interface/thor/default.rb +67 -0
- data/lib/fox/interface/thor/init.rb +57 -0
- data/lib/fox/interface/thor/mixin/config_choice.rb +3 -3
- data/lib/fox/interface/thor/mixin/configuration.rb +1 -1
- data/lib/fox/interface/thor/mixin/database.rb +129 -0
- data/lib/fox/interface/thor/mixin/default.rb +6 -0
- data/lib/fox/interface/thor/mixin/default_model.rb +13 -0
- data/lib/fox/interface/thor/mixin/generators/base_generator.rb +35 -0
- data/lib/fox/interface/thor/mixin/generators/structure.rb +41 -0
- data/lib/fox/interface/thor/mixin/generators/template_loader.rb +48 -0
- data/lib/fox/interface/thor/mixin/history.rb +12 -0
- data/lib/fox/interface/thor/mixin/logger.rb +2 -2
- data/lib/fox/interface/thor/mixin/model.rb +19 -0
- data/lib/fox/interface/thor/new.thor +74 -0
- data/lib/fox/interface/thor/version.rb +59 -0
- data/lib/fox/library/choice.rb +160 -0
- data/lib/fox/library/logger.rb +175 -0
- data/lib/fox/library/project_builder.rb +83 -0
- data/lib/fox/library/secure_config.rb +114 -0
- metadata +298 -7
- data/lib/fox/interface/thor/version.thor +0 -33
data/lib/fox/core_ext.rb
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
|
4
|
+
# @class class Array
|
5
|
+
# @brief
|
6
|
+
class Array
|
7
|
+
|
8
|
+
class << self
|
9
|
+
|
10
|
+
# @fn def delete_unless &block {{{
|
11
|
+
# @brief Inverted #delete_if function for convenience
|
12
|
+
#
|
13
|
+
def delete_unless &block
|
14
|
+
delete_if{ |element| not block.call( element ) }
|
15
|
+
end # }}}
|
16
|
+
|
17
|
+
# @fn def %(len) {{{
|
18
|
+
# @brief Chunk array into convienent sub-chunks
|
19
|
+
#
|
20
|
+
# @credit http://drnicwilliams.com/2007/03/22/meta-magic-in-ruby-presentation/
|
21
|
+
# direct original source at http://redhanded.hobix.com/bits/matchingIntoMultipleAssignment.html
|
22
|
+
#
|
23
|
+
# now e.g. this is possible
|
24
|
+
#
|
25
|
+
# ["foo0", "foo1", "foo2", "foo3", "foo4", "foo5", "foo6", "foo7", "foo8", "foo9", "foo10"]
|
26
|
+
# [ ["foo0", "foo1", "foo2"], ["foo3", "foo4", "foo5"], ["foo6", "foo7", "foo8"], ["foo9", "foo10"]]
|
27
|
+
#
|
28
|
+
def %(len)
|
29
|
+
inject([]) do |array, x|
|
30
|
+
array << [] if [*array.last].nitems % len == 0
|
31
|
+
array.last << x
|
32
|
+
array
|
33
|
+
end
|
34
|
+
end # }}}
|
35
|
+
|
36
|
+
# @fn def sum {{{
|
37
|
+
def sum
|
38
|
+
inject( nil ) { |sum,x| sum ? sum+x : x }
|
39
|
+
end # }}}
|
40
|
+
|
41
|
+
# @fn def mean {{{
|
42
|
+
# @brief
|
43
|
+
def mean
|
44
|
+
sum / size
|
45
|
+
end # }}}
|
46
|
+
|
47
|
+
end # of class << self
|
48
|
+
end # of class Array
|
49
|
+
|
50
|
+
|
51
|
+
# vim:ts=2:tw=100:wm=100
|
@@ -0,0 +1,17 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
|
4
|
+
# @class class Hash
|
5
|
+
# @brief
|
6
|
+
class Hash
|
7
|
+
|
8
|
+
# @fn def except *keys {{{
|
9
|
+
# @brief Deletes specified keys from hash copy and returns it
|
10
|
+
# @credit https://github.com/rails/rails/blob/master/activesupport/lib/active_support/core_ext/hash/except.rb
|
11
|
+
def except(*keys)
|
12
|
+
copy = self.dup
|
13
|
+
keys.each { |key| copy.delete(key) }
|
14
|
+
copy
|
15
|
+
end #}}}
|
16
|
+
|
17
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
|
4
|
+
# @class class IO #:nodoc:
|
5
|
+
#
|
6
|
+
# @credit https://github.com/erikhuda/thor/blob/master/lib/thor/core_ext/io_binary_read.rb
|
7
|
+
class IO
|
8
|
+
|
9
|
+
class << self
|
10
|
+
def binread(file, *args)
|
11
|
+
fail ArgumentError, "wrong number of arguments (#{1 + args.size} for 1..3)" unless args.size < 3
|
12
|
+
File.open(file, "rb") do |f|
|
13
|
+
f.read(*args)
|
14
|
+
end
|
15
|
+
end unless method_defined? :binread
|
16
|
+
end
|
17
|
+
|
18
|
+
end # of class IO
|
19
|
+
|
20
|
+
# vim:ts=2:tw=100:wm=100
|
data/lib/fox/error.rb
ADDED
@@ -0,0 +1,232 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
|
4
|
+
# @module module Fox
|
5
|
+
# @brief Fox module namespace
|
6
|
+
module Fox
|
7
|
+
|
8
|
+
|
9
|
+
class FoxError < StandardError
|
10
|
+
|
11
|
+
class << self
|
12
|
+
# @param [Integer] code
|
13
|
+
def status_code(code)
|
14
|
+
define_method(:status_code) { code }
|
15
|
+
define_singleton_method(:status_code) { code }
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
alias_method :message, :to_s
|
20
|
+
end # of class FoxError
|
21
|
+
|
22
|
+
class DeprecatedError < FoxError; status_code(10); end
|
23
|
+
class InternalError < FoxError; status_code(99); end
|
24
|
+
class ArgumentError < InternalError; end
|
25
|
+
class AbstractFunction < InternalError; end
|
26
|
+
|
27
|
+
class FoxfileNotFound < FoxError
|
28
|
+
status_code(100)
|
29
|
+
|
30
|
+
# @param [#to_s] filepath
|
31
|
+
# the path where a Foxfile was not found
|
32
|
+
def initialize(filepath)
|
33
|
+
@filepath = File.dirname(File.expand_path(filepath)) rescue filepath
|
34
|
+
end
|
35
|
+
|
36
|
+
def to_s
|
37
|
+
"No Foxfile or Foxfile.lock found at '#{@filepath}'!"
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
class CookbookNotFound < FoxError
|
42
|
+
status_code(103)
|
43
|
+
|
44
|
+
def initialize(name, version, location)
|
45
|
+
@name = name
|
46
|
+
@version = version
|
47
|
+
@location = location
|
48
|
+
end
|
49
|
+
|
50
|
+
def to_s
|
51
|
+
if @version
|
52
|
+
"Cookbook '#{@name}' (#{@version}) not found #{@location}!"
|
53
|
+
else
|
54
|
+
"Cookbook '#{@name}' not found #{@location}!"
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
class DuplicateDependencyDefined < FoxError
|
60
|
+
status_code(105)
|
61
|
+
|
62
|
+
def initialize(name)
|
63
|
+
@name = name
|
64
|
+
end
|
65
|
+
|
66
|
+
def to_s
|
67
|
+
out = "Your Foxfile contains multiple entries named "
|
68
|
+
out << "'#{@name}'. Please remove duplicate dependencies, or put them in "
|
69
|
+
out << "different groups."
|
70
|
+
out
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
class NoSolutionError < FoxError
|
75
|
+
status_code(106)
|
76
|
+
|
77
|
+
attr_reader :demands
|
78
|
+
|
79
|
+
# @param [Array<Dependency>] demands
|
80
|
+
def initialize(demands)
|
81
|
+
@demands = demands
|
82
|
+
end
|
83
|
+
|
84
|
+
def to_s
|
85
|
+
"Unable to find a solution for demands: #{demands.join(', ')}"
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
class FoxfileReadError < FoxError
|
90
|
+
status_code(113)
|
91
|
+
|
92
|
+
# @param [#status_code] original_error
|
93
|
+
def initialize(original_error)
|
94
|
+
@original_error = original_error
|
95
|
+
@error_message = original_error.to_s
|
96
|
+
@error_backtrace = original_error.backtrace
|
97
|
+
end
|
98
|
+
|
99
|
+
def status_code
|
100
|
+
@original_error.respond_to?(:status_code) ? @original_error.status_code : 113
|
101
|
+
end
|
102
|
+
|
103
|
+
alias_method :original_backtrace, :backtrace
|
104
|
+
def backtrace
|
105
|
+
Array(@error_backtrace) + Array(original_backtrace)
|
106
|
+
end
|
107
|
+
|
108
|
+
def to_s
|
109
|
+
[
|
110
|
+
"An error occurred while reading the Foxfile:",
|
111
|
+
"",
|
112
|
+
" #{@error_message}",
|
113
|
+
].join("\n")
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
|
118
|
+
class InvalidConfiguration < FoxError
|
119
|
+
status_code(115)
|
120
|
+
|
121
|
+
def initialize(errors)
|
122
|
+
@errors = errors
|
123
|
+
end
|
124
|
+
|
125
|
+
def to_s
|
126
|
+
out = "Invalid configuration:\n"
|
127
|
+
@errors.each do |key, errors|
|
128
|
+
errors.each do |error|
|
129
|
+
out << " #{key} #{error}\n"
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
out.strip
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
class InsufficientPrivledges < FoxError
|
138
|
+
status_code(119)
|
139
|
+
|
140
|
+
def initialize(path)
|
141
|
+
@path = path
|
142
|
+
end
|
143
|
+
|
144
|
+
def to_s
|
145
|
+
"You do not have permission to write to '#{@path}'! Please chown the " \
|
146
|
+
"path to the current user, chmod the permissions to include the " \
|
147
|
+
"user, or choose a different path."
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
class DependencyNotFound < FoxError
|
152
|
+
status_code(120)
|
153
|
+
|
154
|
+
# @param [String, Array<String>] names
|
155
|
+
# the list of cookbook names that were not defined
|
156
|
+
def initialize(names)
|
157
|
+
@names = Array(names)
|
158
|
+
end
|
159
|
+
|
160
|
+
def to_s
|
161
|
+
if @names.size == 1
|
162
|
+
"Dependency '#{@names.first}' was not found. Please make sure it is " \
|
163
|
+
"in your Foxfile, and then run `fox install` to download and " \
|
164
|
+
"install the missing dependencies."
|
165
|
+
else
|
166
|
+
out = "The following dependencies were not found:\n"
|
167
|
+
@names.each do |name|
|
168
|
+
out << " * #{name}\n"
|
169
|
+
end
|
170
|
+
out << "\n"
|
171
|
+
out << "Please make sure they are in your Foxfile, and then run "
|
172
|
+
out << "`fox install` to download and install the missing "
|
173
|
+
out << "dependencies."
|
174
|
+
out
|
175
|
+
end
|
176
|
+
end
|
177
|
+
end
|
178
|
+
|
179
|
+
|
180
|
+
class LockfileParserError < FoxError
|
181
|
+
status_code(136)
|
182
|
+
|
183
|
+
# @param [String] lockfile
|
184
|
+
# the path to the Lockfile
|
185
|
+
# @param [~Exception] original
|
186
|
+
# the original exception class
|
187
|
+
def initialize(original)
|
188
|
+
@original = original
|
189
|
+
end
|
190
|
+
|
191
|
+
def to_s
|
192
|
+
"Error reading the Fox lockfile:\n\n" \
|
193
|
+
" #{@original.class}: #{@original.message}"
|
194
|
+
end
|
195
|
+
end
|
196
|
+
|
197
|
+
class LockfileNotFound < FoxError
|
198
|
+
status_code(140)
|
199
|
+
|
200
|
+
def to_s
|
201
|
+
'Lockfile not found! Run `fox install` to create the lockfile.'
|
202
|
+
end
|
203
|
+
end
|
204
|
+
|
205
|
+
|
206
|
+
class LockfileOutOfSync < FoxError
|
207
|
+
status_code(144)
|
208
|
+
|
209
|
+
def to_s
|
210
|
+
'The lockfile is out of sync! Run `fox install` to sync the lockfile.'
|
211
|
+
end
|
212
|
+
end
|
213
|
+
|
214
|
+
|
215
|
+
class NoAPISourcesDefined < FoxError
|
216
|
+
status_code(146)
|
217
|
+
|
218
|
+
def to_s
|
219
|
+
"Your Foxfile does not define any API sources! You must define " \
|
220
|
+
"at least one source in order to download cookbooks. To add the " \
|
221
|
+
"default Fox API server, add the following code to the top of " \
|
222
|
+
"your Foxfile:"
|
223
|
+
end
|
224
|
+
end
|
225
|
+
|
226
|
+
class LoadTemplateError < FoxError
|
227
|
+
status_code(141)
|
228
|
+
end
|
229
|
+
|
230
|
+
end
|
231
|
+
|
232
|
+
# vim:ts=2:tw=100:wm=100:syntax=ruby
|
@@ -0,0 +1,34 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
|
4
|
+
# System include
|
5
|
+
require "thor"
|
6
|
+
|
7
|
+
# Custom include
|
8
|
+
require File.expand_path( File.dirname( __FILE__ ) + '/mixin/logger' )
|
9
|
+
require File.expand_path( File.dirname( __FILE__ ) + '/mixin/database' )
|
10
|
+
|
11
|
+
# @class class All
|
12
|
+
# @brief drop structure from Fox Service
|
13
|
+
class All < Thor
|
14
|
+
|
15
|
+
# Include various partials
|
16
|
+
include ::Mixin::Logger
|
17
|
+
include ::Mixin::Database
|
18
|
+
|
19
|
+
default_task :all
|
20
|
+
|
21
|
+
# @fn def all {{{
|
22
|
+
desc "all", "Get all Models"
|
23
|
+
option :force, :aliases => :f
|
24
|
+
def all
|
25
|
+
@logger.message :info, "Running Fox All command"
|
26
|
+
all_models.sort_by(&:name).each do |model|
|
27
|
+
puts "#{model.name} #{model.version} #{model.uuid}"
|
28
|
+
end
|
29
|
+
|
30
|
+
end # def all }}}
|
31
|
+
|
32
|
+
end # of class All
|
33
|
+
|
34
|
+
# vim:ts=2:tw=100:wm=100:syntax=ruby
|
@@ -0,0 +1,71 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
|
4
|
+
# System includes
|
5
|
+
require "thor"
|
6
|
+
require 'fileutils'
|
7
|
+
|
8
|
+
#Custom includes
|
9
|
+
require File.expand_path(File.dirname(__FILE__) + '/mixin/default_config')
|
10
|
+
require File.expand_path(File.dirname(__FILE__) + '/mixin/configuration')
|
11
|
+
|
12
|
+
# @fn class Generate < Thor
|
13
|
+
# @brief Generate config files
|
14
|
+
class Configuration < Thor
|
15
|
+
|
16
|
+
namespace :config
|
17
|
+
|
18
|
+
# Include various partials
|
19
|
+
include Thor::Actions
|
20
|
+
include ::Mixin::DefaultConfig
|
21
|
+
|
22
|
+
|
23
|
+
desc "generate", "Generate fox config file" # {{{
|
24
|
+
option :pretend, desc: "Pretend switch for Fox operations"
|
25
|
+
|
26
|
+
def generate
|
27
|
+
template_path = File.expand_path(File.dirname(__FILE__) + '/../../template/config/config.tt')
|
28
|
+
source_paths << template_path
|
29
|
+
config = defaults['fox'].merge(options)
|
30
|
+
template(template_path, config_path, config)
|
31
|
+
end # }}}
|
32
|
+
|
33
|
+
# @fn def config key, value {{{
|
34
|
+
# @brief set new `value` for `key`
|
35
|
+
desc "config KEY VALUE", "Set `VALUE` for `KEY`"
|
36
|
+
def config key, value
|
37
|
+
|
38
|
+
Kernel.include Mixin::Configuration
|
39
|
+
|
40
|
+
# othewise load config file if it contain current key change to new value
|
41
|
+
current_configuration = YAML.load_file(config_path)
|
42
|
+
|
43
|
+
namaspace = key.split(".")
|
44
|
+
|
45
|
+
abort("Key '#{key}' not found in config") if namaspace.size == 1 || namaspace.size > 2
|
46
|
+
abort("Key '#{key}' not found in config") if current_configuration[namaspace.first][namaspace.last].nil?
|
47
|
+
|
48
|
+
current_configuration[namaspace.first][namaspace.last] = value
|
49
|
+
|
50
|
+
File.open(config_path, "w") do |config|
|
51
|
+
config.write(current_configuration.to_yaml)
|
52
|
+
end
|
53
|
+
|
54
|
+
end # of def config # }}}
|
55
|
+
|
56
|
+
desc "clean", "Removes fox config file" # {{{
|
57
|
+
def clean
|
58
|
+
File.delete(config_path) if File.exist?(config_path)
|
59
|
+
end # }}}
|
60
|
+
|
61
|
+
private
|
62
|
+
|
63
|
+
# @fn def config_path {{{
|
64
|
+
# @brief Return path to configuration file
|
65
|
+
def config_path
|
66
|
+
File.expand_path('~/.fox/config.yml')
|
67
|
+
end # def config_path # }}}
|
68
|
+
|
69
|
+
end # of class Generate < Thor
|
70
|
+
|
71
|
+
# vim:ts=2:tw=100:syntax=ruby
|