qb 0.3.17 → 0.3.18
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/exe/qb +2 -0
- data/lib/qb/cli.rb +1 -0
- data/lib/qb/cli/list.rb +9 -15
- data/lib/qb/package/version.rb +2 -2
- data/lib/qb/role.rb +21 -266
- data/lib/qb/role/matches.rb +165 -0
- data/lib/qb/role/name.rb +6 -8
- data/lib/qb/role/search_path.rb +176 -0
- data/lib/qb/util.rb +18 -36
- data/lib/qb/version.rb +1 -1
- data/qb.gemspec +1 -1
- data/roles/{qb.vars → qb/dump/vars}/.qb-options.yml +1 -1
- data/roles/{qb.vars → qb/dump/vars}/README.md +0 -0
- data/roles/{qb.vars → qb/dump/vars}/meta/main.yml +1 -2
- data/roles/{qb.vars → qb/dump/vars}/meta/qb.yml +2 -2
- data/roles/{qb.vars → qb/dump/vars}/tasks/main.yml +1 -1
- data/roles/qb/git/check/clean/meta/qb.yml +1 -1
- data/roles/{qb.git_repo → qb/git/repo}/defaults/main.yml +1 -1
- data/roles/qb/git/repo/meta/main.yml +4 -0
- data/roles/qb/git/repo/meta/qb.yml +6 -0
- data/roles/{qb.git_repo → qb/git/repo}/tasks/main.yml +1 -1
- data/roles/qb/project/meta/main.yml +3 -2
- metadata +15 -13
- data/roles/qb.git_repo/meta/main.yml +0 -4
- data/roles/qb.git_repo/meta/qb.yml +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 36d941451916fb21a0e92a4c73520240b12a7b4a
|
4
|
+
data.tar.gz: 6e11fb934d559165fe98096924e3afe27c80b684
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b43a422d14c11a56580fa543f3fa6679ee0c3187d7379b6bfe942fc6c3d194baa74a8da76dd8f6a4fe74acbbe8633f4129c2173e23ed59c7c383566e1ef59bec
|
7
|
+
data.tar.gz: 657b3bd019e0cc539a21dc072d5a6d498a68a1e4b73af6e70ce517299d5445512d78de6316942f31ed46c0905c08af51d9658aa1400a7c1f1d68d37244f5cb7f
|
data/exe/qb
CHANGED
data/lib/qb/cli.rb
CHANGED
data/lib/qb/cli/list.rb
CHANGED
@@ -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
|
41
|
-
|
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
|
38
|
+
return 0
|
45
39
|
end # .help
|
46
40
|
|
47
41
|
end # module QB::CLI
|
data/lib/qb/package/version.rb
CHANGED
@@ -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?
|
data/lib/qb/role.rb
CHANGED
@@ -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
|
-
#
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
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
|
-
|
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
|
data/lib/qb/role/name.rb
CHANGED
@@ -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
|
data/lib/qb/util.rb
CHANGED
@@ -8,47 +8,29 @@ using NRSER
|
|
8
8
|
|
9
9
|
module QB
|
10
10
|
module Util
|
11
|
-
|
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.
|
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
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
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
|
data/lib/qb/version.rb
CHANGED
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.
|
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
|
File without changes
|
@@ -1,5 +1,5 @@
|
|
1
1
|
---
|
2
|
-
# meta/qb.yml file for qb
|
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
|
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.
|
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-
|
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.
|
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.
|
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
|
File without changes
|