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.
Files changed (37) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +196 -14
  3. data/bin/fox +28 -8
  4. data/fox.gemspec +41 -3
  5. data/lib/fox.rb +23 -10
  6. data/lib/fox/cli.rb +17 -0
  7. data/lib/fox/configuration.rb +48 -0
  8. data/lib/fox/core_ext.rb +8 -0
  9. data/lib/fox/core_ext/array.rb +51 -0
  10. data/lib/fox/core_ext/hash.rb +17 -0
  11. data/lib/fox/core_ext/io_binary_read.rb +20 -0
  12. data/lib/fox/error.rb +8 -0
  13. data/lib/fox/error/errors.rb +232 -0
  14. data/lib/fox/interface/thor/all.rb +34 -0
  15. data/lib/fox/interface/thor/configuration.rb +71 -0
  16. data/lib/fox/interface/thor/create.rb +49 -0
  17. data/lib/fox/interface/thor/default.rb +67 -0
  18. data/lib/fox/interface/thor/init.rb +57 -0
  19. data/lib/fox/interface/thor/mixin/config_choice.rb +3 -3
  20. data/lib/fox/interface/thor/mixin/configuration.rb +1 -1
  21. data/lib/fox/interface/thor/mixin/database.rb +129 -0
  22. data/lib/fox/interface/thor/mixin/default.rb +6 -0
  23. data/lib/fox/interface/thor/mixin/default_model.rb +13 -0
  24. data/lib/fox/interface/thor/mixin/generators/base_generator.rb +35 -0
  25. data/lib/fox/interface/thor/mixin/generators/structure.rb +41 -0
  26. data/lib/fox/interface/thor/mixin/generators/template_loader.rb +48 -0
  27. data/lib/fox/interface/thor/mixin/history.rb +12 -0
  28. data/lib/fox/interface/thor/mixin/logger.rb +2 -2
  29. data/lib/fox/interface/thor/mixin/model.rb +19 -0
  30. data/lib/fox/interface/thor/new.thor +74 -0
  31. data/lib/fox/interface/thor/version.rb +59 -0
  32. data/lib/fox/library/choice.rb +160 -0
  33. data/lib/fox/library/logger.rb +175 -0
  34. data/lib/fox/library/project_builder.rb +83 -0
  35. data/lib/fox/library/secure_config.rb +114 -0
  36. metadata +298 -7
  37. data/lib/fox/interface/thor/version.thor +0 -33
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env ruby
2
+
3
+
4
+ Dir[ "#{File.dirname(__FILE__)}/core_ext/*.rb" ].sort.each do |path|
5
+ require_relative "core_ext/#{File.basename( path, '.rb' )}"
6
+ end
7
+
8
+ # vim:ts=2:tw=100:wm=100:syntax=ruby
@@ -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
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env ruby
2
+
3
+
4
+ Dir[ "#{File.dirname(__FILE__)}/error/*.rb" ].sort.each do |path|
5
+ require_relative "error/#{File.basename( path, '.rb' )}"
6
+ end
7
+
8
+ # vim:ts=2:tw=100:wm=100:syntax=ruby
@@ -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