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 +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
|