fox 0.0.2 → 0.4.0

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