qb 0.3.17 → 0.3.18

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 9234ff3dddbac0d5c2b4c640f63873e53a18d9b2
4
- data.tar.gz: a9a33b610f3691b8873efef6fa9b7cce0f6a113c
3
+ metadata.gz: 36d941451916fb21a0e92a4c73520240b12a7b4a
4
+ data.tar.gz: 6e11fb934d559165fe98096924e3afe27c80b684
5
5
  SHA512:
6
- metadata.gz: cdee8091f290db8ccd416b1463d95cb1e7ce949c284a63b6941d5aac6d5ac7c603b78317968749026e77af09dc3573009f4cb20992e83d11f6d4929685041c01
7
- data.tar.gz: 40dfc00d62b08512ae3a02ddf863f4618bb7623440fb9a99600ccd1b12cd2534da30d76a5890f2ebb00640cef1e1722dc3357f1de0b891945cdc3380241b245b
6
+ metadata.gz: b43a422d14c11a56580fa543f3fa6679ee0c3187d7379b6bfe942fc6c3d194baa74a8da76dd8f6a4fe74acbbe8633f4129c2173e23ed59c7c383566e1ef59bec
7
+ data.tar.gz: 657b3bd019e0cc539a21dc072d5a6d498a68a1e4b73af6e70ce517299d5445512d78de6316942f31ed46c0905c08af51d9658aa1400a7c1f1d68d37244f5cb7f
data/exe/qb CHANGED
@@ -55,6 +55,8 @@ def main args
55
55
  [:run, args.rest]
56
56
  when 'setup'
57
57
  [:setup, args.rest]
58
+ when 'list', 'ls'
59
+ [:list, *args.rest]
58
60
  else
59
61
  # default to `run` on the full args
60
62
  [:run, args]
@@ -12,6 +12,7 @@ require_relative './cli/help'
12
12
  require_relative './cli/play'
13
13
  require_relative './cli/run'
14
14
  require_relative './cli/setup'
15
+ require_relative './cli/list'
15
16
 
16
17
 
17
18
  # Requirements
@@ -1,15 +1,3 @@
1
- # Requirements
2
- # =====================================================================
3
-
4
- # package
5
-
6
-
7
- # Declarations
8
- # =======================================================================
9
-
10
- module QB; end
11
-
12
-
13
1
  # Definitions
14
2
  # =======================================================================
15
3
 
@@ -37,11 +25,17 @@ module QB::CLI
37
25
  # Error exit status - we don't want `qb ... && ...` to move on to the
38
26
  # second command when we end up falling back to `help`.
39
27
  #
40
- def self.list args = []
41
- puts QB::Role.available
28
+ def self.list pattern = nil
29
+ roles = if pattern
30
+ QB::Role.matches pattern
31
+ else
32
+ QB::Role.available
33
+ end
34
+
35
+ puts roles
42
36
  puts
43
37
 
44
- return 1
38
+ return 0
45
39
  end # .help
46
40
 
47
41
  end # module QB::CLI
@@ -93,8 +93,8 @@ class QB::Package::Version < QB::Util::Resource
93
93
  prop :major, type: NUMBER_SEGMENT
94
94
  prop :minor, type: NUMBER_SEGMENT, default: 0
95
95
  prop :patch, type: NUMBER_SEGMENT, default: 0
96
- prop :prerelease, type: t.array(MIXED_SEGMENT), default: []
97
- prop :build, type: t.array(MIXED_SEGMENT), default: []
96
+ prop :prerelease, type: t.array(MIXED_SEGMENT), default: ->{ [] }
97
+ prop :build, type: t.array(MIXED_SEGMENT), default: ->{ [] }
98
98
 
99
99
  prop :release, type: t.str, source: :@release
100
100
  prop :is_release, type: t.bool, source: :release?
@@ -7,16 +7,16 @@
7
7
  require 'yaml'
8
8
  require 'cmds'
9
9
 
10
-
11
10
  # deps
12
11
  # ----------------------------------------------------------------------------
13
12
 
14
-
15
13
  # package
16
14
  # ----------------------------------------------------------------------------
17
15
 
18
16
  # Breakouts
19
17
  require 'qb/role/errors'
18
+ require 'qb/role/search_path'
19
+ require 'qb/role/matches'
20
20
  require 'qb/role/name'
21
21
  require 'qb/role/default_dir'
22
22
 
@@ -24,14 +24,8 @@ require 'qb/role/default_dir'
24
24
  # Refinements
25
25
  # =======================================================================
26
26
 
27
- require 'nrser/refinements'
28
27
  using NRSER
29
-
30
-
31
- # Declarations
32
- # =======================================================================
33
-
34
- module QB; end
28
+ using NRSER::Types
35
29
 
36
30
 
37
31
  # Contains info on a QB role.
@@ -44,134 +38,9 @@ class QB::Role
44
38
  include SemanticLogger::Loggable
45
39
 
46
40
 
47
- # Constants
48
- # =====================================================================
49
-
50
- # Array of string paths to directories to search for roles or paths to
51
- # `ansible.cfg` files to look for an extract role paths from.
52
- #
53
- # For the moment at least you can just mutate this value like you would
54
- # `$LOAD_PATH`:
55
- #
56
- # QB::Role::PATH.unshift '~/where/some/roles/be'
57
- # QB::Role::PATH.unshift '~/my/ansible.cfg'
58
- #
59
- # The paths are searched from first to last.
60
- #
61
- # **WARNING**
62
- #
63
- # Search is **deep** - don't point this at large directory trees and
64
- # expect any sort of reasonable performance (any directory that
65
- # contains `node_modules` is usually a terrible idea for instance).
66
- #
67
- BUILTIN_PATH = [
68
-
69
- # Development Paths
70
- # =================
71
- #
72
- # These come first because:
73
- #
74
- # 1. They are working dir-local.
75
- #
76
- # 2. They should only be present in local development, and should be
77
- # capable of overriding roles in other local directories to allow
78
- # custom development behavior (the same way `./dev/bin` is put in
79
- # front or `./bin`).
80
- #
81
-
82
- # Role paths declared in ./dev/ansible.cfg, if it exists.
83
- File.join('.', 'dev', 'ansible.cfg'),
84
-
85
- # Roles in ./dev/roles
86
- File.join('.', 'dev', 'roles'),
87
-
88
-
89
- # Working Directory Paths
90
- # =======================
91
- #
92
- # Next up, `ansible.cfg` and `roles` directory in the working dir.
93
- # Makes sense, right?
94
- #
95
-
96
- # ./ansible.cfg
97
- File.join('.', 'ansible.cfg'),
98
-
99
- # ./roles
100
- File.join('.', 'roles'),
101
-
102
-
103
- # Working Directory-Local Ansible Directory
104
- # =========================================
105
- #
106
- # `ansible.cfg` and `roles` in a `./ansible` directory, making a common
107
- # place to put Ansible stuff in an project accessible when running from
108
- # the project root.
109
- #
110
-
111
- # ./ansible/ansible.cfg
112
- File.join('.', 'ansible', 'ansible.cfg'),
113
-
114
- # ./ansible/roles
115
- File.join('.', 'ansible', 'roles'),
116
-
117
- # TODO Git repo root relative?
118
- # Some sort of flag file for a find-up?
119
- # System Ansible locations?
120
-
121
-
122
- # QB Gem Role Directories
123
- # =======================
124
- #
125
- # Last, but far from least, paths provided by the QB Gem to the user's
126
- # QB role install location and the roles that come built-in to the gem.
127
-
128
- QB::USER_ROLES_DIR,
129
-
130
- QB::GEM_ROLES_DIR,
131
- ].freeze
132
-
133
-
134
- # Array of string paths to directories to search for roles or paths to
135
- # `ansible.cfg` files to look for an extract role paths from.
136
- #
137
- # Value is a duplicate of the frozen {QB::Role::BUILTIN_PATH}. You can
138
- # reset to those values at any time via {QB::Role.reset_path!}.
139
- #
140
- # For the moment at least you can just mutate this value like you would
141
- # `$LOAD_PATH`:
142
- #
143
- # QB::Role::PATH.unshift '~/where/some/roles/be'
144
- # QB::Role::PATH.unshift '~/my/ansible.cfg'
145
- #
146
- # The paths are searched from first to last.
147
- #
148
- # **WARNING**
149
- #
150
- # Search is **deep** - don't point this at large directory trees and
151
- # expect any sort of reasonable performance (any directory that
152
- # contains `node_modules` is usually a terrible idea for instance).
153
- #
154
- PATH = BUILTIN_PATH.dup
155
-
156
-
157
41
  # Class Methods
158
42
  # =======================================================================
159
43
 
160
- # Reset {QB::Role::PATH} to the original built-in values in
161
- # {QB::Role::BUILTIN_PATH}.
162
- #
163
- # Created for testing but might be useful elsewhere as well.
164
- #
165
- # @return [Array<String>]
166
- # The reset {QB::Role::PATH}.
167
- #
168
- def self.reset_path!
169
- PATH.clear
170
- BUILTIN_PATH.each { |path| PATH << path }
171
- PATH
172
- end # .reset_path!
173
-
174
-
175
44
  # true if pathname is a QB role directory.
176
45
  def self.role_dir? pathname
177
46
  # must be a directory
@@ -181,54 +50,15 @@ class QB::Role
181
50
  end
182
51
 
183
52
 
184
- # @param dir [Pathname] dir to include.
185
- def self.roles_paths dir
186
- cfg_roles_path(dir) + [
187
- dir.join('roles'),
188
- dir.join('roles', 'tmp'),
189
- ]
190
- end
191
-
192
- # places to look for qb role directories. these paths are also included
193
- # when qb runs a playbook.
194
- #
195
- # TODO resolution order:
196
- #
197
- # 1. paths specific to this run:
198
- # a. TODO paths provided on the cli.
199
- # 2. paths specific to the current directory:
200
- # a. paths specified in ./ansible.cfg (if it exists)
201
- # b. ./roles
202
- # d. paths specified in ./ansible/ansible.cfg (if it exists)
203
- # e. ./ansible/roles
204
- # g. paths specified in ./dev/ansible.cfg (if it exists)
205
- # h. ./dev/roles
206
- # i. ./dev/roles/tmp
207
- # - used for roles that are downloaded but shouldn't be included
208
- # in source control.
209
- # 3.
210
- #
211
- # @return [Array<Pathname>]
212
- # places to look for role dirs.
213
- #
214
- def self.search_path
215
- QB::Role::PATH.
216
- map { |path|
217
- if QB::Ansible::ConfigFile.end_with_config_file?(path)
218
- if File.file?(path)
219
- QB::Ansible::ConfigFile.new(path).defaults.roles_path
220
- end
221
- else
222
- QB::Util.resolve path
223
- end
224
- }.
225
- flatten.
226
- reject(&:nil?)
227
- end
228
-
229
- # array of QB::Role found in search path.
53
+ # All {QB::Role} found in search path.
54
+ #
55
+ # Does it's best to remove duplicates that end up being reached though
56
+ # multiple search paths (happens most in development).
57
+ #
58
+ # @return [Array<QB::Role>]
59
+ #
230
60
  def self.available
231
- search_path.
61
+ self.search_path.
232
62
  select {|search_dir|
233
63
  # make sure it's there (and a directory)
234
64
  search_dir.directory?
@@ -241,93 +71,11 @@ class QB::Role
241
71
  }
242
72
  }
243
73
  }.
244
- flatten(1).
245
- map {|args|
246
- QB::Role.new *args
247
- }.
74
+ flatten( 1 ).
75
+ map { |args| QB::Role.new *args }.
248
76
  uniq
249
77
  end
250
78
 
251
- # Get an array of QB::Role that match an input string.
252
- #
253
- # @return [Array<QB::Role>]
254
- #
255
- def self.matches input
256
- # keep this here to we don't re-gen every loop
257
- available = self.available
258
-
259
- # first off, see if input matches any relative paths exactly
260
- available.each {|role|
261
- return [role] if role.display_path.to_s == input
262
- }
263
-
264
- # create an array of "separator" variations to try *exact* matching
265
- # against. in order of preference:
266
- #
267
- # 1. exact input
268
- # - this means if you ended up with roles that actually *are*
269
- # differnetiated by '_/-' differences (which, IMHO, is a
270
- # horrible fucking idea), you can get exactly what you ask for
271
- # as a first priority
272
- # 2. input with '-' changed to '_'
273
- # - prioritized because convetion is to underscore-separate
274
- # role names.
275
- # 3. input with '_' changed to '-'
276
- # - really just for convience's sake so you don't really have to
277
- # remember what separator is used.
278
- #
279
- separator_variations = [
280
- input,
281
- input.gsub('-', '_'),
282
- input.gsub('_', '-'),
283
- ]
284
-
285
- separator_variations.each { |variation|
286
- available.each { |role|
287
- # exact match to full name
288
- return [role] if role.name == variation
289
- }.each { |role|
290
- # exact match without the namespace prefix ('qb.' or similar)
291
- return [role] if role.namespaceless == variation
292
- }
293
- }
294
-
295
- # see if we prefix match any full names
296
- separator_variations.each { |variation|
297
- name_prefix_matches = available.select { |role|
298
- role.name.start_with? variation
299
- }
300
- return name_prefix_matches unless name_prefix_matches.empty?
301
- }
302
-
303
- # see if we prefix match any name
304
- separator_variations.each { |variation|
305
- namespaceless_prefix_matches = available.select { |role|
306
- role.namespaceless.start_with? variation
307
- }
308
- unless namespaceless_prefix_matches.empty?
309
- return namespaceless_prefix_matches
310
- end
311
- }
312
-
313
- # see if we prefix match any display paths
314
- separator_variations.each { |variation|
315
- path_prefix_matches = available.select { |role|
316
- role.display_path.start_with? variation
317
- }
318
- return path_prefix_matches unless path_prefix_matches.empty?
319
- }
320
-
321
- # see if we word match any display paths
322
- name_word_matches = available.select { |role|
323
- QB::Util.words_start_with? role.display_path.to_s, input
324
- }
325
- return name_word_matches unless name_word_matches.empty?
326
-
327
- # nada
328
- []
329
- end # .matches
330
-
331
79
 
332
80
  # Find exactly one matching role for the input string or raise.
333
81
  #
@@ -499,8 +247,15 @@ class QB::Role
499
247
  # Instance Methods
500
248
  # =====================================================================
501
249
 
250
+ # Just a string version of {#display_path}
251
+ #
252
+ def display_name
253
+ display_path.to_s
254
+ end
255
+
256
+
502
257
  def options_key
503
- @display_path.to_s
258
+ display_name
504
259
  end
505
260
 
506
261
  # load qb metadata from meta/qb.yml or from executing meta/qb and parsing
@@ -0,0 +1,165 @@
1
+ # frozen_string_literal: true
2
+
3
+ ##
4
+ # {QB::Role.matches} method, which is the (messy) bulk of figuring out what
5
+ # role to run based on user input.
6
+ #
7
+ # Broken out from the main `//lib/qb/role.rb` file because it was starting to
8
+ # get long and unwieldy.
9
+ #
10
+ ##
11
+
12
+ # Refinements
13
+ # =======================================================================
14
+
15
+ using NRSER
16
+ using NRSER::Types
17
+
18
+
19
+ # Definitions
20
+ # =======================================================================
21
+
22
+ class QB::Role
23
+
24
+ # Get an array of {QB::Role} that match an input string.
25
+ #
26
+ # This is the meat of whats needed to support {QB::Role.require}.
27
+ #
28
+ # How it works is... tricky. Read the comments and play around with it is
29
+ # the bast I can offer right now.
30
+ #
31
+ # @param [String] input
32
+ # The input string to match against role paths and names. Primarily what
33
+ # the user typed after `qb run` on the CLI.
34
+ #
35
+ # @return [Array<QB::Role>]
36
+ #
37
+ def self.matches input
38
+ # keep this here to we don't re-gen every loop
39
+ available = self.available
40
+
41
+ # first off, see if input matches any relative paths exactly
42
+ available.each {|role|
43
+ return [role] if role.display_path.to_s == input
44
+ }
45
+
46
+ # create an array of "separator" variations to try *exact* matching
47
+ # against. in order of preference:
48
+ #
49
+ # 1. exact input
50
+ # - this means if you ended up with roles that actually *are*
51
+ # differentiated by '_/-' differences (which, IMHO, is a
52
+ # horrible fucking idea), you can get exactly what you ask for
53
+ # as a first priority
54
+ # 2. input with '-' changed to '_'
55
+ # - prioritized because convention is to underscore-separate
56
+ # role names.
57
+ # 3. input with '_' changed to '-'
58
+ # - really just for convenience's sake so you don't really have to
59
+ # remember what separator is used.
60
+ #
61
+ separator_variations = [
62
+ input,
63
+ input.gsub('-', '_'),
64
+ input.gsub('_', '-'),
65
+ ]
66
+
67
+ # {QB::Role} method names to check against, from highest to lowest
68
+ # precedence
69
+ method_names = [
70
+ # 1. The path we display to the user. This comes first because typing
71
+ # in exactly what they see should always work.
72
+ :display_name,
73
+
74
+ # 2. The role's full name (with namespace) as it is likely to be used
75
+ # in Ansible
76
+ :name,
77
+
78
+ # 3. The part of the role after the namespace, which is far less
79
+ # specific, but nice short-hand if it's unique
80
+ :namespaceless
81
+ ]
82
+
83
+ # 1. Exact matches (allowing `-`/`_` substitution)
84
+ #
85
+ # Highest precedence, guaranteeing that exact verbatim matches will
86
+ # always work (or that's the intent).
87
+ #
88
+ method_names.each { |method_name|
89
+ separator_variations.each { |variation|
90
+ matches = available.select { |role|
91
+ role.public_send( method_name ) == variation
92
+ }
93
+ return matches unless matches.empty?
94
+ }
95
+ }
96
+
97
+ # 2. Prefix matches
98
+ #
99
+ # Do any of {#display_path}, {#name} or {#namespaceless} or start with
100
+ # the input pattern?
101
+ #
102
+ method_names.each { |method_name|
103
+ separator_variations.each { |variation|
104
+ matches = available.select { |role|
105
+ role.public_send( method_name ).start_with? variation
106
+ }
107
+ return matches unless matches.empty?
108
+ }
109
+ }
110
+
111
+ # 3. Word slice full matches
112
+ #
113
+ # Split the {#display_name} and input first by `/` and `.` segments,
114
+ # then {String#downcase} each segments and split it into words (using
115
+ # {NRSER.words}).
116
+ #
117
+ # Then see if the input appears in the role name.
118
+ #
119
+ # We test only {#display_name} because it should always contain
120
+ # {#name} and {#namesaceless}, so it's pointless to test the other
121
+ # two after it).
122
+ #
123
+
124
+ word_parse = ->( string ) {
125
+ string.split( /[\/\.]/ ).map { |seg| seg.downcase.words }
126
+ }
127
+
128
+ input_parse = word_parse.call input
129
+
130
+ exact_word_slice_matches = available.select { |role|
131
+ word_parse.call( role.display_name ).slice? input_parse
132
+ }
133
+
134
+ return exact_word_slice_matches unless exact_word_slice_matches.empty?
135
+
136
+ # 4. Word slice prefix matches
137
+ #
138
+ # Same thing as (3), but do a prefix match instead of the entire
139
+ # words.
140
+ #
141
+ name_word_matches = available.select { |role|
142
+ word_parse.call( role.display_name ).
143
+ slice?( input_parse ) { |role_words, input_words|
144
+ # Use a custom match block to implement prefix matching
145
+ #
146
+ # We want to match if each input word is the start of the
147
+ # corresponding role name word
148
+ #
149
+ if role_words.length >= input_words.length
150
+ input_words.each_with_index.all? { |input_word, index|
151
+ role_words[index].start_with? input_word
152
+ }
153
+ else
154
+ false
155
+ end
156
+ }
157
+ QB::Util.words_start_with? role.display_path.to_s, input
158
+ }
159
+ return name_word_matches unless name_word_matches.empty?
160
+
161
+ # nada
162
+ []
163
+ end # .matches
164
+
165
+ end # class QB::Role
@@ -1,7 +1,9 @@
1
+ # frozen_string_literal: true
2
+
1
3
  ##
2
4
  # {QB::Role} methods for dealing with role names.
3
5
  #
4
- # Broken out from the main `//lib/qb/role.rb` file because it was starting to
6
+ # Broken out from the main `//lib/qb/role.rb` file because it was starting to
5
7
  # get long and unwieldy.
6
8
  #
7
9
  ##
@@ -23,12 +25,8 @@ require 'qb/util'
23
25
  # Refinements
24
26
  # =======================================================================
25
27
 
26
- require 'nrser/refinements'
27
28
  using NRSER
28
-
29
-
30
- # Declarations
31
- # =======================================================================
29
+ using NRSER::Types
32
30
 
33
31
 
34
32
  # Definitions
@@ -66,8 +64,8 @@ class QB::Role
66
64
  # Find the first directory in the search path that contains the path,
67
65
  # if any do.
68
66
  #
69
- # It *could* be in more than one in funky situations like overlapping
70
- # search paths or link silliness, but that doesn't matter - we consider
67
+ # It *could* be in more than one in funky situations like overlapping
68
+ # search paths or link silliness, but that doesn't matter - we consider
71
69
  # the first place we find it to be the relevant once, since the search
72
70
  # path is most-important-first.
73
71
  #
@@ -0,0 +1,176 @@
1
+ # frozen_string_literal: true
2
+
3
+ ##
4
+ # {QB::Role} methods for dealing with role search path.
5
+ #
6
+ # Broken out from the main `//lib/qb/role.rb` file because it was starting to
7
+ # get long and unwieldy.
8
+ #
9
+ ##
10
+
11
+ # Refinements
12
+ # =======================================================================
13
+
14
+ using NRSER
15
+ using NRSER::Types
16
+
17
+
18
+ # Definitions
19
+ # =======================================================================
20
+
21
+ class QB::Role
22
+
23
+ # Constants
24
+ # =====================================================================
25
+
26
+ # "Factory defaults" that {QB::Role::PATH} is initialized to, and what it
27
+ # gets reset to when {QB::Role.reset_path!} is called.
28
+ #
29
+ # Read the {QB::Role::PATH} docs for details on how QB role paths work.
30
+ #
31
+ # This value is deeply frozen, and you should not attempt to change it -
32
+ # mess with {QB::Role::PATH} instead.
33
+ #
34
+ # @return [Array<String>]
35
+ #
36
+ BUILTIN_PATH = [
37
+
38
+ # Development Paths
39
+ # =================
40
+ #
41
+ # These come first because:
42
+ #
43
+ # 1. They are working dir-local.
44
+ #
45
+ # 2. They should only be present in local development, and should be
46
+ # capable of overriding roles in other local directories to allow
47
+ # custom development behavior (the same way `./dev/bin` is put in
48
+ # front or `./bin`).
49
+ #
50
+
51
+ # Role paths declared in ./dev/ansible.cfg, if it exists.
52
+ File.join('.', 'dev', 'ansible.cfg'),
53
+
54
+ # Roles in ./dev/roles
55
+ File.join('.', 'dev', 'roles'),
56
+
57
+
58
+ # Working Directory Paths
59
+ # =======================
60
+ #
61
+ # Next up, `ansible.cfg` and `roles` directory in the working dir.
62
+ # Makes sense, right?
63
+ #
64
+
65
+ # ./ansible.cfg
66
+ File.join('.', 'ansible.cfg'),
67
+
68
+ # ./roles
69
+ File.join('.', 'roles'),
70
+
71
+
72
+ # Working Directory-Local Ansible Directory
73
+ # =========================================
74
+ #
75
+ # `ansible.cfg` and `roles` in a `./ansible` directory, making a common
76
+ # place to put Ansible stuff in an project accessible when running from
77
+ # the project root.
78
+ #
79
+
80
+ # ./ansible/ansible.cfg
81
+ File.join('.', 'ansible', 'ansible.cfg'),
82
+
83
+ # ./ansible/roles
84
+ File.join('.', 'ansible', 'roles'),
85
+
86
+ # TODO Git repo root relative?
87
+ # Some sort of flag file for a find-up?
88
+ # System Ansible locations?
89
+
90
+
91
+ # QB Gem Role Directories
92
+ # =======================
93
+ #
94
+ # Last, but far from least, paths provided by the QB Gem to the user's
95
+ # QB role install location and the roles that come built-in to the gem.
96
+
97
+ QB::USER_ROLES_DIR,
98
+
99
+ QB::GEM_ROLES_DIR,
100
+ ].freeze
101
+
102
+
103
+ # Array of string paths to directories to search for roles or paths to
104
+ # `ansible.cfg` files to look for an extract role paths from.
105
+ #
106
+ # Value is a duplicate of the frozen {QB::Role::BUILTIN_PATH}. You can
107
+ # reset to those values at any time via {QB::Role.reset_path!}.
108
+ #
109
+ # For the moment at least you can just mutate this value like you would
110
+ # `$LOAD_PATH`:
111
+ #
112
+ # QB::Role::PATH.unshift '~/where/some/roles/be'
113
+ # QB::Role::PATH.unshift '~/my/ansible.cfg'
114
+ #
115
+ # The paths are searched from first to last.
116
+ #
117
+ # **WARNING**
118
+ #
119
+ # Search is **deep** - don't point this at large directory trees and
120
+ # expect any sort of reasonable performance (any directory that
121
+ # contains `node_modules` is usually a terrible idea for instance).
122
+ #
123
+ # @return [Array<String>]
124
+ #
125
+ PATH = BUILTIN_PATH.dup
126
+
127
+
128
+ # Class Methods
129
+ # ======================================================================
130
+
131
+ # Reset {QB::Role::PATH} to the original built-in values in
132
+ # {QB::Role::BUILTIN_PATH}.
133
+ #
134
+ # Created for testing but might be useful elsewhere as well.
135
+ #
136
+ # @return [Array<String>]
137
+ # The reset {QB::Role::PATH}.
138
+ #
139
+ def self.reset_path!
140
+ PATH.clear
141
+ BUILTIN_PATH.each { |path| PATH << path }
142
+ PATH
143
+ end # .reset_path!
144
+
145
+
146
+ # Gets the array of paths to search for QB roles based on {QB::Role::PATH}
147
+ # and the working directory at the time it's called.
148
+ #
149
+ # QB then uses the returned value to figure out what roles are available.
150
+ #
151
+ # The process:
152
+ #
153
+ # 1. Resolve relative paths against the working directory.
154
+ #
155
+ # 2. Load up any `ansible.cfg` files on the path and add any `roles_path`
156
+ # they define where the `ansible.cfg` entry was in {QB::Role::PATH}.
157
+ #
158
+ # @return [Array<Pathname>]
159
+ # Directories to search for QB roles.
160
+ #
161
+ def self.search_path
162
+ QB::Role::PATH.
163
+ map { |path|
164
+ if QB::Ansible::ConfigFile.end_with_config_file?(path)
165
+ if File.file?(path)
166
+ QB::Ansible::ConfigFile.new(path).defaults.roles_path
167
+ end
168
+ else
169
+ QB::Util.resolve path
170
+ end
171
+ }.
172
+ flatten.
173
+ reject(&:nil?)
174
+ end
175
+
176
+ end # class QB::Role
@@ -8,47 +8,29 @@ using NRSER
8
8
 
9
9
  module QB
10
10
  module Util
11
- # split a string into 'words' for word-based matching
11
+
12
+ # Split a string into 'words' for word-based matching
13
+ #
14
+ # @return [Array<String>]
15
+ # Array of non-empty words in `string`.
16
+ #
12
17
  def self.words string
13
- string.split(/[\W_\-\/]+/).reject {|w| w.empty?}
18
+ string.words
14
19
  end # .words
15
20
 
21
+
22
+ def self.words_slice? full_string, input, &is_match
23
+ full_string.words.slice? input.words, &is_match
24
+ end # .words_include?
25
+
26
+
16
27
  # see if words from an input match words
17
28
  def self.words_start_with? full_string, input
18
- # QB.debug "does #{ input } match #{ full_string }?"
19
-
20
- input_words = words input
21
-
22
- # short-circuit if there are no input words ('./' for example)
23
- return false if input_words.empty?
24
-
25
- full_string_words = words full_string
26
-
27
- full_string_words.each_with_index {|word, start_index|
28
- # compute the end index in full_string_words
29
- end_index = start_index + input_words.length - 1
30
-
31
- # short-circuit if can't match (more input words than full words left)
32
- if end_index >= full_string_words.length
33
- return false
34
- end
35
-
36
- # create the slice to test against
37
- slice = full_string_words[start_index..end_index]
38
-
39
- # see if every word in the slice starts with the corresponding word
40
- # in the input
41
- if slice.zip(input_words).all? {|full_word, input_word|
42
- full_word.start_with? input_word
43
- }
44
- # got a match!
45
- return true
46
- end
47
- }
48
-
49
- # no match
50
- false
51
- end # .match_words?
29
+ words_slice? full_string, input do |full_string_word, input_word|
30
+ full_string_word.start_with? input_word
31
+ end
32
+ end # .words_start_with?
33
+
52
34
 
53
35
  # @return [Pathname] absolute resolved path.
54
36
  def self.resolve *segments
@@ -4,7 +4,7 @@ module QB
4
4
 
5
5
  GEM_NAME = 'qb'
6
6
 
7
- VERSION = "0.3.17"
7
+ VERSION = "0.3.18"
8
8
 
9
9
  MIN_ANSIBLE_VERSION = Gem::Version.new '2.1.2'
10
10
 
data/qb.gemspec CHANGED
@@ -195,7 +195,7 @@ Gem::Specification.new do |spec|
195
195
  # ----------------------------------------------------------------------------
196
196
 
197
197
  spec.add_dependency "cmds", '~> 0.0', ">= 0.2.7"
198
- spec.add_dependency "nrser", '~> 0.1', ">= 0.1.3"
198
+ spec.add_dependency "nrser", '~> 0.1', ">= 0.1.4"
199
199
  spec.add_dependency "state_mate", '~> 0.0', ">= 0.1.0"
200
200
 
201
201
  # Used to parse `ansible.cfg` files
@@ -1,3 +1,3 @@
1
1
  ---
2
- qb.qb_role:
2
+ qb/role/qb:
3
3
  defaults: false
@@ -1,8 +1,7 @@
1
1
  ---
2
- # meta file for qb.vars
2
+ # meta file for qb/dump/vars
3
3
 
4
4
  allow_duplicates: yes
5
5
 
6
6
  dependencies: []
7
7
  # - role: role-name
8
-
@@ -1,5 +1,5 @@
1
1
  ---
2
- # meta/qb.yml file for qb.vars
2
+ # meta/qb.yml file for qb/dump/vars
3
3
  #
4
4
  # qb settings for this role. see README.md for more info.
5
5
  #
@@ -7,7 +7,7 @@
7
7
  # prefix for role variables
8
8
  var_prefix: null
9
9
 
10
- # how to get a default for `dir` if it's not provided as the
10
+ # how to get a default for `dir` if it's not provided as the
11
11
  default_dir: null
12
12
 
13
13
  # set to false to not save options in .qb-options.yml files
@@ -1,5 +1,5 @@
1
1
  ---
2
- # tasks file for qb.vars
2
+ # tasks file for qb/dump/vars
3
3
 
4
4
  - when: vars_output is defined
5
5
  local_action:
@@ -10,7 +10,7 @@
10
10
 
11
11
  # Shown in help output, etc.
12
12
  description: >-
13
- TODO describe qb/git/check/clean role
13
+ Fail if Git repo working directory isn't clean
14
14
 
15
15
  # Gemspec-style requirements. Right now only `.gems.qb` is used.
16
16
  requirements:
@@ -1,4 +1,4 @@
1
1
  ---
2
- # defaults file for qb.git_repo
2
+ # defaults file for qb/git/repo
3
3
  git_repo_dest: "{{ qb_dir }}"
4
4
  git_repo_gitignores: []
@@ -0,0 +1,4 @@
1
+ ---
2
+ # meta file for qb/git/repo
3
+
4
+ dependencies: []
@@ -0,0 +1,6 @@
1
+ # Shown in help output, etc.
2
+ description: >-
3
+ Ensure directory is a Git repo - init and add basic ignore sections
4
+
5
+ # Prefix for role variables
6
+ var_prefix: git_repo
@@ -1,5 +1,5 @@
1
1
  ---
2
- # tasks file for qb.git_repo
2
+ # tasks file for qb/git/repo
3
3
 
4
4
  - name: >-
5
5
  Create {{ git_repo_dest }} directory
@@ -2,5 +2,6 @@
2
2
  # meta file for qb/project
3
3
 
4
4
  dependencies:
5
- - role: qb.git_repo
6
- git_repo_dest: "{{ project_dest }}"
5
+ - role: qb/git/repo
6
+ git_repo_dest: >-
7
+ {{ project_dest }}
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: qb
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.17
4
+ version: 0.3.18
5
5
  platform: ruby
6
6
  authors:
7
7
  - nrser
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2018-01-31 00:00:00.000000000 Z
11
+ date: 2018-02-03 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -143,7 +143,7 @@ dependencies:
143
143
  version: '0.1'
144
144
  - - ">="
145
145
  - !ruby/object:Gem::Version
146
- version: 0.1.3
146
+ version: 0.1.4
147
147
  type: :runtime
148
148
  prerelease: false
149
149
  version_requirements: !ruby/object:Gem::Requirement
@@ -153,7 +153,7 @@ dependencies:
153
153
  version: '0.1'
154
154
  - - ">="
155
155
  - !ruby/object:Gem::Version
156
- version: 0.1.3
156
+ version: 0.1.4
157
157
  - !ruby/object:Gem::Dependency
158
158
  name: state_mate
159
159
  requirement: !ruby/object:Gem::Requirement
@@ -310,7 +310,9 @@ files:
310
310
  - lib/qb/role.rb
311
311
  - lib/qb/role/default_dir.rb
312
312
  - lib/qb/role/errors.rb
313
+ - lib/qb/role/matches.rb
313
314
  - lib/qb/role/name.rb
315
+ - lib/qb/role/search_path.rb
314
316
  - lib/qb/util.rb
315
317
  - lib/qb/util/bundler.rb
316
318
  - lib/qb/util/docker_mixin.rb
@@ -370,10 +372,6 @@ files:
370
372
  - roles/nrser.state_mate/test/ansible/ansible.cfg
371
373
  - roles/nrser.state_mate/test/ansible/hosts
372
374
  - roles/nrser.state_mate/test/ansible/template.yml
373
- - roles/qb.git_repo/defaults/main.yml
374
- - roles/qb.git_repo/meta/main.yml
375
- - roles/qb.git_repo/meta/qb.yml
376
- - roles/qb.git_repo/tasks/main.yml
377
375
  - roles/qb.git_submodule_update/.qb-options.yml
378
376
  - roles/qb.git_submodule_update/README.md
379
377
  - roles/qb.git_submodule_update/defaults/main.yml
@@ -416,11 +414,6 @@ files:
416
414
  - roles/qb.unhack_gem/meta/main.yml
417
415
  - roles/qb.unhack_gem/meta/qb.yml
418
416
  - roles/qb.unhack_gem/tasks/main.yml
419
- - roles/qb.vars/.qb-options.yml
420
- - roles/qb.vars/README.md
421
- - roles/qb.vars/meta/main.yml
422
- - roles/qb.vars/meta/qb.yml
423
- - roles/qb.vars/tasks/main.yml
424
417
  - roles/qb.yarn_release/defaults/main.yml
425
418
  - roles/qb.yarn_release/meta/main.yml
426
419
  - roles/qb.yarn_release/meta/qb.yml
@@ -433,6 +426,11 @@ files:
433
426
  - roles/qb/dev/ref/repo/git/meta/main.yml
434
427
  - roles/qb/dev/ref/repo/git/meta/qb.yml
435
428
  - roles/qb/dev/ref/repo/git/tasks/main.yml
429
+ - roles/qb/dump/vars/.qb-options.yml
430
+ - roles/qb/dump/vars/README.md
431
+ - roles/qb/dump/vars/meta/main.yml
432
+ - roles/qb/dump/vars/meta/qb.yml
433
+ - roles/qb/dump/vars/tasks/main.yml
436
434
  - roles/qb/facts/defaults/main.yml
437
435
  - roles/qb/facts/meta/main.yml
438
436
  - roles/qb/facts/meta/qb.yml
@@ -637,6 +635,10 @@ files:
637
635
  - roles/qb/git/ignore/meta/main.yml
638
636
  - roles/qb/git/ignore/meta/qb
639
637
  - roles/qb/git/ignore/tasks/main.yml
638
+ - roles/qb/git/repo/defaults/main.yml
639
+ - roles/qb/git/repo/meta/main.yml
640
+ - roles/qb/git/repo/meta/qb.yml
641
+ - roles/qb/git/repo/tasks/main.yml
640
642
  - roles/qb/github/pages/setup/defaults/main.yml
641
643
  - roles/qb/github/pages/setup/meta/main.yml
642
644
  - roles/qb/github/pages/setup/meta/qb.yml
@@ -1,4 +0,0 @@
1
- ---
2
- # meta file for qb.git_repo
3
-
4
- dependencies: []
File without changes