garcun 0.0.2

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 (139) hide show
  1. checksums.yaml +7 -0
  2. data/.gitattributes +17 -0
  3. data/.gitignore +197 -0
  4. data/.rspec +2 -0
  5. data/Gemfile +22 -0
  6. data/LICENSE +201 -0
  7. data/README.md +521 -0
  8. data/Rakefile +47 -0
  9. data/garcun.gemspec +83 -0
  10. data/lib/garcon.rb +290 -0
  11. data/lib/garcon/chef/chef_helpers.rb +343 -0
  12. data/lib/garcon/chef/coerce/coercer.rb +134 -0
  13. data/lib/garcon/chef/coerce/coercions/boolean_definitions.rb +34 -0
  14. data/lib/garcon/chef/coerce/coercions/date_definitions.rb +32 -0
  15. data/lib/garcon/chef/coerce/coercions/date_time_definitions.rb +32 -0
  16. data/lib/garcon/chef/coerce/coercions/fixnum_definitions.rb +34 -0
  17. data/lib/garcon/chef/coerce/coercions/float_definitions.rb +32 -0
  18. data/lib/garcon/chef/coerce/coercions/hash_definitions.rb +29 -0
  19. data/lib/garcon/chef/coerce/coercions/integer_definitions.rb +31 -0
  20. data/lib/garcon/chef/coerce/coercions/string_definitions.rb +45 -0
  21. data/lib/garcon/chef/coerce/coercions/time_definitions.rb +32 -0
  22. data/lib/garcon/chef/handler/devreporter.rb +127 -0
  23. data/lib/garcon/chef/log.rb +64 -0
  24. data/lib/garcon/chef/node.rb +100 -0
  25. data/lib/garcon/chef/provider/civilize.rb +209 -0
  26. data/lib/garcon/chef/provider/development.rb +159 -0
  27. data/lib/garcon/chef/provider/download.rb +420 -0
  28. data/lib/garcon/chef/provider/house_keeping.rb +265 -0
  29. data/lib/garcon/chef/provider/node_cache.rb +31 -0
  30. data/lib/garcon/chef/provider/partial.rb +183 -0
  31. data/lib/garcon/chef/provider/recovery.rb +80 -0
  32. data/lib/garcon/chef/provider/zip_file.rb +271 -0
  33. data/lib/garcon/chef/resource/attribute.rb +52 -0
  34. data/lib/garcon/chef/resource/base_dsl.rb +174 -0
  35. data/lib/garcon/chef/resource/blender.rb +140 -0
  36. data/lib/garcon/chef/resource/lazy_eval.rb +66 -0
  37. data/lib/garcon/chef/resource/resource_name.rb +109 -0
  38. data/lib/garcon/chef/secret_bag.rb +204 -0
  39. data/lib/garcon/chef/validations.rb +76 -0
  40. data/lib/garcon/chef_inclusions.rb +151 -0
  41. data/lib/garcon/configuration.rb +138 -0
  42. data/lib/garcon/core_ext.rb +39 -0
  43. data/lib/garcon/core_ext/array.rb +27 -0
  44. data/lib/garcon/core_ext/binding.rb +64 -0
  45. data/lib/garcon/core_ext/boolean.rb +66 -0
  46. data/lib/garcon/core_ext/duration.rb +271 -0
  47. data/lib/garcon/core_ext/enumerable.rb +34 -0
  48. data/lib/garcon/core_ext/file.rb +127 -0
  49. data/lib/garcon/core_ext/filetest.rb +62 -0
  50. data/lib/garcon/core_ext/hash.rb +279 -0
  51. data/lib/garcon/core_ext/kernel.rb +159 -0
  52. data/lib/garcon/core_ext/lazy.rb +222 -0
  53. data/lib/garcon/core_ext/method_access.rb +243 -0
  54. data/lib/garcon/core_ext/module.rb +92 -0
  55. data/lib/garcon/core_ext/nil.rb +53 -0
  56. data/lib/garcon/core_ext/numeric.rb +44 -0
  57. data/lib/garcon/core_ext/object.rb +342 -0
  58. data/lib/garcon/core_ext/pathname.rb +152 -0
  59. data/lib/garcon/core_ext/process.rb +41 -0
  60. data/lib/garcon/core_ext/random.rb +497 -0
  61. data/lib/garcon/core_ext/string.rb +312 -0
  62. data/lib/garcon/core_ext/struct.rb +49 -0
  63. data/lib/garcon/core_ext/symbol.rb +170 -0
  64. data/lib/garcon/core_ext/time.rb +234 -0
  65. data/lib/garcon/exceptions.rb +101 -0
  66. data/lib/garcon/inflections.rb +237 -0
  67. data/lib/garcon/inflections/defaults.rb +79 -0
  68. data/lib/garcon/inflections/inflections.rb +182 -0
  69. data/lib/garcon/inflections/rules_collection.rb +37 -0
  70. data/lib/garcon/secret.rb +271 -0
  71. data/lib/garcon/stash/format.rb +114 -0
  72. data/lib/garcon/stash/journal.rb +226 -0
  73. data/lib/garcon/stash/queue.rb +83 -0
  74. data/lib/garcon/stash/serializer.rb +86 -0
  75. data/lib/garcon/stash/store.rb +435 -0
  76. data/lib/garcon/task.rb +31 -0
  77. data/lib/garcon/task/atomic.rb +151 -0
  78. data/lib/garcon/task/atomic_boolean.rb +127 -0
  79. data/lib/garcon/task/condition.rb +99 -0
  80. data/lib/garcon/task/copy_on_notify_observer_set.rb +154 -0
  81. data/lib/garcon/task/copy_on_write_observer_set.rb +153 -0
  82. data/lib/garcon/task/count_down_latch.rb +92 -0
  83. data/lib/garcon/task/delay.rb +196 -0
  84. data/lib/garcon/task/dereferenceable.rb +144 -0
  85. data/lib/garcon/task/event.rb +119 -0
  86. data/lib/garcon/task/executor.rb +275 -0
  87. data/lib/garcon/task/executor_options.rb +59 -0
  88. data/lib/garcon/task/future.rb +107 -0
  89. data/lib/garcon/task/immediate_executor.rb +84 -0
  90. data/lib/garcon/task/ivar.rb +171 -0
  91. data/lib/garcon/task/lazy_reference.rb +74 -0
  92. data/lib/garcon/task/monotonic_time.rb +69 -0
  93. data/lib/garcon/task/obligation.rb +256 -0
  94. data/lib/garcon/task/observable.rb +101 -0
  95. data/lib/garcon/task/priority_queue.rb +234 -0
  96. data/lib/garcon/task/processor_count.rb +128 -0
  97. data/lib/garcon/task/read_write_lock.rb +304 -0
  98. data/lib/garcon/task/safe_task_executor.rb +58 -0
  99. data/lib/garcon/task/single_thread_executor.rb +97 -0
  100. data/lib/garcon/task/thread_pool/cached.rb +71 -0
  101. data/lib/garcon/task/thread_pool/executor.rb +294 -0
  102. data/lib/garcon/task/thread_pool/fixed.rb +61 -0
  103. data/lib/garcon/task/thread_pool/worker.rb +90 -0
  104. data/lib/garcon/task/timer.rb +44 -0
  105. data/lib/garcon/task/timer_set.rb +194 -0
  106. data/lib/garcon/task/timer_task.rb +377 -0
  107. data/lib/garcon/task/waitable_list.rb +58 -0
  108. data/lib/garcon/utility/ansi.rb +199 -0
  109. data/lib/garcon/utility/at_random.rb +77 -0
  110. data/lib/garcon/utility/crypto.rb +292 -0
  111. data/lib/garcon/utility/equalizer.rb +146 -0
  112. data/lib/garcon/utility/faker/extensions/array.rb +22 -0
  113. data/lib/garcon/utility/faker/extensions/symbol.rb +9 -0
  114. data/lib/garcon/utility/faker/faker.rb +164 -0
  115. data/lib/garcon/utility/faker/faker/company.rb +17 -0
  116. data/lib/garcon/utility/faker/faker/hacker.rb +30 -0
  117. data/lib/garcon/utility/faker/faker/version.rb +3 -0
  118. data/lib/garcon/utility/faker/locales/en-US.yml +83 -0
  119. data/lib/garcon/utility/faker/locales/en.yml +21 -0
  120. data/lib/garcon/utility/file_helper.rb +170 -0
  121. data/lib/garcon/utility/hookers.rb +178 -0
  122. data/lib/garcon/utility/interpolation.rb +90 -0
  123. data/lib/garcon/utility/memstash.rb +364 -0
  124. data/lib/garcon/utility/misc.rb +54 -0
  125. data/lib/garcon/utility/msg_from_god.rb +62 -0
  126. data/lib/garcon/utility/retry.rb +238 -0
  127. data/lib/garcon/utility/timeout.rb +58 -0
  128. data/lib/garcon/utility/uber/builder.rb +91 -0
  129. data/lib/garcon/utility/uber/callable.rb +7 -0
  130. data/lib/garcon/utility/uber/delegates.rb +13 -0
  131. data/lib/garcon/utility/uber/inheritable_attr.rb +37 -0
  132. data/lib/garcon/utility/uber/options.rb +101 -0
  133. data/lib/garcon/utility/uber/uber_version.rb +3 -0
  134. data/lib/garcon/utility/uber/version.rb +33 -0
  135. data/lib/garcon/utility/url_helper.rb +100 -0
  136. data/lib/garcon/utils.rb +29 -0
  137. data/lib/garcon/version.rb +62 -0
  138. data/lib/garcun.rb +24 -0
  139. metadata +680 -0
@@ -0,0 +1,79 @@
1
+ # encoding: UTF-8
2
+ #
3
+ # Author: Stefano Harding <riddopic@gmail.com>
4
+ # License: Apache License, Version 2.0
5
+ # Copyright: (C) 2014-2015 Stefano Harding
6
+ #
7
+ # Licensed under the Apache License, Version 2.0 (the "License");
8
+ # you may not use this file except in compliance with the License.
9
+ # You may obtain a copy of the License at
10
+ #
11
+ # http://www.apache.org/licenses/LICENSE-2.0
12
+ #
13
+ # Unless required by applicable law or agreed to in writing, software
14
+ # distributed under the License is distributed on an "AS IS" BASIS,
15
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
+ # See the License for the specific language governing permissions and
17
+ # limitations under the License.
18
+ #
19
+
20
+ Garcon::Inflections.inflections do |inflect|
21
+ inflect.plural(/$/, 's')
22
+ inflect.plural(/s$/i, 's')
23
+ inflect.plural(/^(ax|test)is$/i, '\1es')
24
+ inflect.plural(/(octop|vir)us$/i, '\1i')
25
+ inflect.plural(/(octop|vir)i$/i, '\1i')
26
+ inflect.plural(/(alias|status)$/i, '\1es')
27
+ inflect.plural(/(bu)s$/i, '\1ses')
28
+ inflect.plural(/(buffal|tomat)o$/i, '\1oes')
29
+ inflect.plural(/([ti])um$/i, '\1a')
30
+ inflect.plural(/([ti])a$/i, '\1a')
31
+ inflect.plural(/sis$/i, 'ses')
32
+ inflect.plural(/(?:([^f])fe|([lr])f)$/i, '\1\2ves')
33
+ inflect.plural(/(hive)$/i, '\1s')
34
+ inflect.plural(/([^aeiouy]|qu)y$/i, '\1ies')
35
+ inflect.plural(/(x|ch|ss|sh)$/i, '\1es')
36
+ inflect.plural(/(matr|vert|ind)(?:ix|ex)$/i, '\1ices')
37
+ inflect.plural(/^(m|l)ouse$/i, '\1ice')
38
+ inflect.plural(/^(m|l)ice$/i, '\1ice')
39
+ inflect.plural(/^(ox)$/i, '\1en')
40
+ inflect.plural(/^(oxen)$/i, '\1')
41
+ inflect.plural(/(quiz)$/i, '\1zes')
42
+
43
+ inflect.singular(/s$/i, '')
44
+ inflect.singular(/(ss)$/i, '\1')
45
+ inflect.singular(/(n)ews$/i, '\1ews')
46
+ inflect.singular(/([ti])a$/i, '\1um')
47
+ inflect.singular(/((a)naly|(b)a|(d)iagno|(p)arenthe|(p)rogno|(s)ynop|(t)he)(sis|ses)$/i, '\1sis')
48
+ inflect.singular(/(^analy)(sis|ses)$/i, '\1sis')
49
+ inflect.singular(/([^f])ves$/i, '\1fe')
50
+ inflect.singular(/(hive)s$/i, '\1')
51
+ inflect.singular(/(tive)s$/i, '\1')
52
+ inflect.singular(/([lr])ves$/i, '\1f')
53
+ inflect.singular(/([^aeiouy]|qu)ies$/i, '\1y')
54
+ inflect.singular(/(s)eries$/i, '\1eries')
55
+ inflect.singular(/(m)ovies$/i, '\1ovie')
56
+ inflect.singular(/(x|ch|ss|sh)es$/i, '\1')
57
+ inflect.singular(/^(m|l)ice$/i, '\1ouse')
58
+ inflect.singular(/(bus)(es)?$/i, '\1')
59
+ inflect.singular(/(o)es$/i, '\1')
60
+ inflect.singular(/(shoe)s$/i, '\1')
61
+ inflect.singular(/(cris|test)(is|es)$/i, '\1is')
62
+ inflect.singular(/^(a)x[ie]s$/i, '\1xis')
63
+ inflect.singular(/(octop|vir)(us|i)$/i, '\1us')
64
+ inflect.singular(/(alias|status)(es)?$/i, '\1')
65
+ inflect.singular(/^(ox)en/i, '\1')
66
+ inflect.singular(/(vert|ind)ices$/i, '\1ex')
67
+ inflect.singular(/(matr)ices$/i, '\1ix')
68
+ inflect.singular(/(quiz)zes$/i, '\1')
69
+ inflect.singular(/(database)s$/i, '\1')
70
+
71
+ inflect.irregular('person', 'people')
72
+ inflect.irregular('man', 'men')
73
+ inflect.irregular('child', 'children')
74
+ inflect.irregular('sex', 'sexes')
75
+ inflect.irregular('move', 'moves')
76
+ inflect.irregular('zombie', 'zombies')
77
+
78
+ inflect.uncountable(%w(hovercraft moose milk rain Swiss grass equipment information rice money species series fish sheep jeans))
79
+ end
@@ -0,0 +1,182 @@
1
+ # encoding: UTF-8
2
+ #
3
+ # Author: Stefano Harding <riddopic@gmail.com>
4
+ # License: Apache License, Version 2.0
5
+ # Copyright: (C) 2014-2015 Stefano Harding
6
+ #
7
+ # Licensed under the Apache License, Version 2.0 (the "License");
8
+ # you may not use this file except in compliance with the License.
9
+ # You may obtain a copy of the License at
10
+ #
11
+ # http://www.apache.org/licenses/LICENSE-2.0
12
+ #
13
+ # Unless required by applicable law or agreed to in writing, software
14
+ # distributed under the License is distributed on an "AS IS" BASIS,
15
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
+ # See the License for the specific language governing permissions and
17
+ # limitations under the License.
18
+ #
19
+
20
+ module Garcon
21
+ module Inflections
22
+ # A singleton instance of this class is yielded by Garcon.inflections,
23
+ # which can then be used to specify additional inflection rules. Examples:
24
+ #
25
+ # Inflections.inflections do |inflect|
26
+ # inflect.plural /^(ox)$/i, '\1\2en'
27
+ # inflect.singular /^(ox)en/i, '\1'
28
+ #
29
+ # inflect.irregular 'octopus', 'octopi'
30
+ #
31
+ # inflect.uncountable "equipment"
32
+ # end
33
+ #
34
+ # New rules are added at the top. So in the example above, the irregular
35
+ # rule for octopus will now be the first of the pluralization and
36
+ # singularization rules that is runs. This guarantees that your rules run
37
+ # before any of the rules that may already have been loaded.
38
+ #
39
+ class Inflections
40
+
41
+ # Return instance
42
+ #
43
+ # @return [Inflections]
44
+ # @api private
45
+ def self.instance
46
+ @__instance__ ||= new
47
+ end
48
+
49
+ # @return [Array] plurals
50
+ # @api private
51
+ attr_reader :plurals
52
+
53
+ # @return [Array] singulars
54
+ # @api private
55
+ attr_reader :singulars
56
+
57
+ # @return [Array] uncountables
58
+ # @api private
59
+ attr_reader :uncountables
60
+
61
+ # @return [Array] humans
62
+ # @api private
63
+ attr_reader :humans
64
+
65
+ # Initialize object
66
+ #
67
+ # @return [undefined]
68
+ # @api private
69
+ def initialize
70
+ @plurals = RulesCollection.new
71
+ @singulars = RulesCollection.new
72
+ @humans = RulesCollection.new
73
+ @uncountables = Set[]
74
+ end
75
+
76
+ # Specifies a new pluralization rule and its replacement. The rule can
77
+ # either be a string or a regular expression. The replacement should
78
+ # always be a string that may include references to the matched data from
79
+ # the rule.
80
+ #
81
+ # @param [String, Regexp] rule
82
+ # @param [String, Regexp] replacement
83
+ # @return [self]
84
+ # @api private
85
+ def plural(rule, replacement)
86
+ rule(rule, replacement, @plurals)
87
+ self
88
+ end
89
+
90
+ # Specifies a new singularization rule and its replacement. The rule can
91
+ # either be a string or a regular expression. The replacement should
92
+ # always be a string that may include references to the matched data from
93
+ # the rule.
94
+ #
95
+ # @param [String, Regexp] rule
96
+ # @param [String, Regexp] replacement
97
+ # @return [self]
98
+ # @api private
99
+ def singular(rule, replacement)
100
+ rule(rule, replacement, @singulars)
101
+ self
102
+ end
103
+
104
+ # Specifies a new irregular that applies to both pluralization and
105
+ # singularization at the same time. This can only be used for strings, not
106
+ # regular expressions. You simply pass the irregular in singular and
107
+ # plural form.
108
+ #
109
+ # @param [String] singular
110
+ # @param [String] plural
111
+ # @return [self]
112
+ # @api private
113
+ def irregular(singular, plural)
114
+ @uncountables.delete(singular)
115
+ @uncountables.delete(plural)
116
+ add_irregular(singular, plural, @plurals)
117
+ add_irregular(plural, singular, @singulars)
118
+ self
119
+ end
120
+
121
+ # Uncountable will not be inflected
122
+ #
123
+ # @param [Enumerable<String>] words
124
+ # @return [self]
125
+ # @api private
126
+ def uncountable(*words)
127
+ @uncountables.merge(words.flatten)
128
+ self
129
+ end
130
+
131
+ # Specifies a humanized form of a string by a regular expression rule or
132
+ # by a string mapping. When using a regular expression based replacement,
133
+ # the normal humanize formatting is called after the replacement. When a
134
+ # string is used, the human form should be specified as desired (example:
135
+ # 'The name', not 'the_name')
136
+ #
137
+ # @param [String, Regexp] rule
138
+ # @param [String, Regexp] replacement
139
+ # @return [self]
140
+ # @api private
141
+ def human(rule, replacement)
142
+ @humans.insert(0, [rule, replacement])
143
+ self
144
+ end
145
+
146
+ # Clear all inflection rules
147
+ #
148
+ # @return [self]
149
+ # @api private
150
+ def clear
151
+ initialize
152
+ self
153
+ end
154
+
155
+ private # P R O P R I E T À P R I V A T A Vietato L'accesso
156
+
157
+ # Add irregular inflection
158
+ #
159
+ # @param [String] rule
160
+ # @param [String] replacement
161
+ # @return [undefined]
162
+ # @api private
163
+ def add_irregular(rule, replacement, target)
164
+ head, *tail = rule.chars.to_a
165
+ rule(/(#{head})#{tail.join}\z/i, '\1' + replacement[1..-1], target)
166
+ end
167
+
168
+ # Add a new rule
169
+ #
170
+ # @param [String, Regexp] rule
171
+ # @param [String, Regexp] replacement
172
+ # @param [Array] target
173
+ # @return [undefined]
174
+ # @api private
175
+ def rule(rule, replacement, target)
176
+ @uncountables.delete(rule)
177
+ @uncountables.delete(replacement)
178
+ target.insert(0, [rule, replacement])
179
+ end
180
+ end
181
+ end
182
+ end
@@ -0,0 +1,37 @@
1
+ # encoding: UTF-8
2
+ #
3
+ # Author: Stefano Harding <riddopic@gmail.com>
4
+ # License: Apache License, Version 2.0
5
+ # Copyright: (C) 2014-2015 Stefano Harding
6
+ #
7
+ # Licensed under the Apache License, Version 2.0 (the "License");
8
+ # you may not use this file except in compliance with the License.
9
+ # You may obtain a copy of the License at
10
+ #
11
+ # http://www.apache.org/licenses/LICENSE-2.0
12
+ #
13
+ # Unless required by applicable law or agreed to in writing, software
14
+ # distributed under the License is distributed on an "AS IS" BASIS,
15
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
+ # See the License for the specific language governing permissions and
17
+ # limitations under the License.
18
+ #
19
+
20
+ module Garcon
21
+ module Inflections
22
+ # Wraps inflections array
23
+ #
24
+ class RulesCollection < Array
25
+ # Applies first found rule to given word
26
+ #
27
+ # @param [String] word
28
+ # @return [String] modified word
29
+ # @api private
30
+ def apply_to(word)
31
+ result = word.dup
32
+ each { |rule, replacement| break if result.gsub!(rule, replacement) }
33
+ result
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,271 @@
1
+ # encoding: UTF-8
2
+ #
3
+ # Author: Stefano Harding <riddopic@gmail.com>
4
+ # License: Apache License, Version 2.0
5
+ # Copyright: (C) 2014-2015 Stefano Harding
6
+ #
7
+ # Licensed under the Apache License, Version 2.0 (the "License");
8
+ # you may not use this file except in compliance with the License.
9
+ # You may obtain a copy of the License at
10
+ #
11
+ # http://www.apache.org/licenses/LICENSE-2.0
12
+ #
13
+ # Unless required by applicable law or agreed to in writing, software
14
+ # distributed under the License is distributed on an "AS IS" BASIS,
15
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
+ # See the License for the specific language governing permissions and
17
+ # limitations under the License.
18
+ #
19
+
20
+ # ______ __ __ ___ _____ ___ __ ____ ___ ______
21
+ # | T| T T / _] / ___/ / _] / ]| \ / _]| T
22
+ # | || l | / [_ ( \_ / [_ / / | D ) / [_ | |
23
+ # l_j l_j| _ |Y _] \__ TY _] / / | / Y _]l_j l_j
24
+ # | | | | || [_ / \ || [_ / \_ | \ | [_ | |
25
+ # | | | | || T \ || T\ || . Y| T | |
26
+ # l__j l__j__jl_____j \___jl_____j \____jl__j\_jl_____j l__j
27
+ #
28
+ # __ _ ___ ___ ____ ___ ____ __
29
+ # | l/ ] / _] / _]| \ / _]| \ | T
30
+ # | ' / / [_ / [_ | o )/ [_ | D )| |
31
+ # | \ Y _]Y _]| _/Y _]| / |__j
32
+ # | Y| [_ | [_ | | | [_ | \ __
33
+ # | . || T| T| | | T| . Y| T
34
+ # l__j\_jl_____jl_____jl__j l_____jl__j\_jl__j
35
+
36
+ require 'tempfile'
37
+ require 'fileutils'
38
+ require_relative 'utility/crypto'
39
+ require_relative 'utility/memstash'
40
+
41
+ module Garcon
42
+ # Creates a transient file with sensitive content, usefule when you have an
43
+ # excecutable that reads a password from a file but you do not wish to leave
44
+ # the password on the filesystem. When used in a block parameter the file is
45
+ # written and deleted when the block returns, optionally you can encrypt and
46
+ # decrypt your secret strings with salt, cipher and a splash of obfuscation.
47
+ #
48
+ module Secret
49
+ # A Configuration instance
50
+ class Configuration
51
+
52
+ # @!attribute [r] :lock
53
+ # @return [String] Access the shared Monitor for this instance.
54
+ attr_reader :lock
55
+
56
+ # @!attribute [rw] :stash
57
+ # @return [String] The shared Stash (in-memory cache) for this instance.
58
+ attr_accessor :stash
59
+
60
+ # @!attribute [rw] :queue
61
+ # @return [String] The shared queue object for this instance.
62
+ attr_accessor :queue
63
+
64
+ # Initialized a configuration instance
65
+ #
66
+ # @return [undefined]
67
+ #
68
+ # @api private
69
+ def initialize(options = {})
70
+ @lock = Monitor.new
71
+ @stash = MemStash.new
72
+ @queue = MutexPriorityQueue.new
73
+ @queue << Secret.tmpfile until @queue.length >= 4
74
+
75
+ yield self if block_given?
76
+ end
77
+
78
+ # @api private
79
+ def to_h
80
+ { lock: lock,
81
+ stash: stash,
82
+ queue: queue
83
+ }.freeze
84
+ end
85
+ end
86
+
87
+ # Encrypt and store the given value with the given key, either with an an
88
+ # argument or block. If a previous value was set it will be overwritten
89
+ # with the new value.
90
+ #
91
+ # @param key [Symbol, String]
92
+ # String or symbol representing the key.
93
+ #
94
+ # @param value [Object]
95
+ # Any object that represents the value.
96
+ #
97
+ # @yield [Block]
98
+ # Optionally specify a block that returns the value to set.
99
+ #
100
+ # @return [String]
101
+ # The encrypted value.
102
+ #
103
+ def self.set(key, value)
104
+ Garcon.secret.stash[key] = value.encrypt
105
+ end
106
+
107
+ # Retrieve and decrypt a value at key from the stash.
108
+ #
109
+ # @param key [Symbol, String]
110
+ # String or symbol representing the key.
111
+ #
112
+ # @raise [KeyError]
113
+ # If no such key found.
114
+ #
115
+ # @return [String]
116
+ # Unencrypted value.
117
+ #
118
+ def self.get(key)
119
+ (Garcon.secret.stash[key]).decrypt
120
+ end
121
+
122
+ # Creates the secrets file yields to the block, removes the secrets file
123
+ # when the block returns
124
+ #
125
+ # @example
126
+ # secret.tmp { |file| shell_out!("open_sesame --passwd-file #{file}") }
127
+ #
128
+ # @yield [Block]
129
+ # invokes the block
130
+ #
131
+ # @yieldreturn [Object]
132
+ # the result of evaluating the optional block
133
+ #
134
+ # @api public
135
+ def self.tmp(key, *args, &block)
136
+ Garcon.secret.lock.synchronize do
137
+ begin
138
+ file = queue.pop
139
+ atomic_write(file, get(key)) unless valid?(key, file)
140
+ yield file if block_given?
141
+ ensure
142
+ File.unlink(file) if File.exist?(file)
143
+ end
144
+ end
145
+ end
146
+
147
+ # Search a text file for a matching string
148
+ #
149
+ # @return [Boolean]
150
+ # True if the file is present and a match was found, otherwise returns
151
+ # false if file does not exist and/or does not contain a match
152
+ #
153
+ # @api public
154
+ def self.valid?(key, file)
155
+ Garcon.secret.lock.synchronize do
156
+ return false unless File.exist?(file)
157
+ File.open(file, &:readlines).map! do |line|
158
+ return true if line.match(get(key))
159
+ end
160
+ false
161
+ end
162
+ end
163
+
164
+ private # P R O P R I E T À P R I V A T A Vietato L'accesso
165
+
166
+ def self.queue
167
+ until Garcon.secret.queue.length >= 2
168
+ Garcon.secret.queue << Secret.tmpfile
169
+ end
170
+ Garcon.secret.queue
171
+ end
172
+
173
+ # Write the secrets file
174
+ #
175
+ # @return [String]
176
+ # the path to the file
177
+ #
178
+ # @api private
179
+ def self.write(key, file)
180
+ Garcon.secret.lock.synchronize do
181
+ begin
182
+ atomic_write(file, get(key)) unless valid?(key, file)
183
+ ensure
184
+ File.chmod(00400, file)
185
+ end
186
+ end
187
+ end
188
+
189
+ # Delete the secrets file
190
+ #
191
+ # @return [undefined]
192
+ #
193
+ # @api private
194
+ def self.delete(file = nil)
195
+ Garcon.secret.lock.synchronize do
196
+ if file.nil?
197
+ until Garcon.secret.queue.length == 0
198
+ tmpfile = Garcon.secret.queue.pop
199
+ File.unlink(tmpfile) if File.exist?(tmpfile)
200
+ end
201
+ else
202
+ File.unlink(file) if File.exist?(file)
203
+ end
204
+ end
205
+ end
206
+
207
+ # Write to a file atomically. Useful for situations where you don't
208
+ # want other processes or threads to see half-written files.
209
+ #
210
+ # @param [String] file
211
+ # fill path of the file to write to
212
+ # @param [String] secret
213
+ # content to write to file
214
+ #
215
+ # @api private
216
+ def self.atomic_write(file, secret, tmp_dir = Dir.tmpdir)
217
+ tmp_file = Tempfile.new(File.basename(file), tmp_dir)
218
+ tmp_file.write(secret)
219
+ tmp_file.close
220
+
221
+ FileUtils.mv(tmp_file.path, file)
222
+ begin
223
+ File.chmod(00400, file)
224
+ rescue Errno::EPERM, Errno::EACCES
225
+ # Changing file ownership/permissions failed
226
+ end
227
+ ensure
228
+ tmp_file.close
229
+ tmp_file.unlink
230
+ end
231
+
232
+ # Lock a file for a block so only one process can modify it at a time
233
+ #
234
+ # @param [String] file
235
+ # fill path of the file to lock
236
+ #
237
+ # @yield [Block]
238
+ # invokes the block
239
+ #
240
+ # @yieldreturn [Object]
241
+ # the result of evaluating the optional block
242
+ #
243
+ # @api private
244
+ def self.lock_file(file, &block)
245
+ if File.exist?(file)
246
+ File.open(file, 'r+') do |f|
247
+ begin
248
+ f.flock File::LOCK_EX
249
+ yield
250
+ ensure
251
+ f.flock File::LOCK_UN
252
+ end
253
+ end
254
+ else
255
+ yield
256
+ end
257
+ end
258
+
259
+ # @return [String] tmp_file
260
+ # @api private
261
+ def self.tmpfile(tmp_dir = Dir.tmpdir)
262
+ Tempfile.new(random_seed, tmp_dir).path.freeze
263
+ end
264
+
265
+ # @return [String] random_seed
266
+ # @api private
267
+ def self.random_seed
268
+ SecureRandom.random_number(0x100000000).to_s(36)
269
+ end
270
+ end
271
+ end