qb 0.3.7 → 0.3.8
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/lib/qb.rb +10 -4
- data/lib/qb/package.rb +102 -0
- data/lib/qb/package/gem.rb +153 -0
- data/lib/qb/package/version.rb +445 -422
- data/lib/qb/path.rb +219 -19
- data/lib/qb/repo/git.rb +90 -19
- data/lib/qb/role.rb +22 -4
- data/lib/qb/util/resource.rb +36 -0
- data/lib/qb/version.rb +1 -1
- data/qb.gemspec +1 -1
- data/roles/qb.qb_role/templates/qb.yml.j2 +3 -3
- data/roles/qb/gem/bin_stubs/defaults/main.yml +7 -0
- data/roles/qb/gem/bin_stubs/meta/main.yml +8 -0
- data/roles/qb/gem/bin_stubs/meta/qb.yml +76 -0
- data/roles/qb/gem/bin_stubs/tasks/main.yml +28 -0
- data/roles/qb/gem/bin_stubs/templates/console +25 -0
- data/roles/qb/gem/bin_stubs/templates/rake +3 -0
- data/roles/qb/gem/bin_stubs/templates/rspec +3 -0
- metadata +14 -4
data/lib/qb/path.rb
CHANGED
@@ -16,6 +16,8 @@ require 'nrser'
|
|
16
16
|
# Package
|
17
17
|
# -----------------------------------------------------------------------
|
18
18
|
|
19
|
+
require_relative './repo/git'
|
20
|
+
|
19
21
|
|
20
22
|
# Refinements
|
21
23
|
# =======================================================================
|
@@ -36,8 +38,9 @@ module QB; end
|
|
36
38
|
# Definitions
|
37
39
|
# =======================================================================
|
38
40
|
|
39
|
-
|
40
|
-
#
|
41
|
+
# An extension of {Pathname} that implements the facts we want about paths
|
42
|
+
# as {NRSER::Meta::Props}.
|
43
|
+
#
|
41
44
|
class QB::Path < Pathname
|
42
45
|
|
43
46
|
# Mixins
|
@@ -46,29 +49,137 @@ class QB::Path < Pathname
|
|
46
49
|
include NRSER::Meta::Props
|
47
50
|
|
48
51
|
|
49
|
-
#
|
52
|
+
# Props
|
50
53
|
# ======================================================================
|
51
54
|
|
55
|
+
# Principle path properties
|
56
|
+
# ---------------------------------------------------------------------
|
57
|
+
#
|
58
|
+
# Values stored as variables on the instance.
|
59
|
+
#
|
52
60
|
|
53
|
-
#
|
54
|
-
#
|
61
|
+
# The current working directory *relevant* to the path - basically, when
|
62
|
+
# and where the instance was created, which may be on a totally different
|
63
|
+
# system if the instance was loaded from data.
|
64
|
+
#
|
65
|
+
# TODO Not totally flushed out yet, could imagine a lot of problems and
|
66
|
+
# weirdness, but it seems like we need something like this to make
|
67
|
+
# instances transportable. Issues with relative paths come to mind...
|
68
|
+
#
|
69
|
+
prop :cwd,
|
70
|
+
type: t.pathname,
|
71
|
+
to_data: :to_s
|
55
72
|
|
73
|
+
# The raw path argument used to instantiate the path object.
|
74
|
+
#
|
75
|
+
# NOTE Because we reduce {Pathname} instances to {String} when converting
|
76
|
+
# to data, there is some lossy-ness. I guess it's similar to how
|
77
|
+
# symbols and strings all become strings when run through {JSON}
|
78
|
+
# dump and load.
|
79
|
+
#
|
80
|
+
prop :raw,
|
81
|
+
type: t.path,
|
82
|
+
to_data: :to_s
|
56
83
|
|
57
|
-
# Props
|
58
|
-
# ======================================================================
|
59
84
|
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
85
|
+
# Derived path properties
|
86
|
+
# ---------------------------------------------------------------------
|
87
|
+
#
|
88
|
+
# On-demand values computed via method calls.
|
89
|
+
#
|
90
|
+
|
91
|
+
prop :expanded,
|
92
|
+
type: t.path,
|
93
|
+
source: ->() { expand_path.to_s }
|
94
|
+
|
95
|
+
prop :exists,
|
96
|
+
type: t.bool,
|
97
|
+
source: :exist?
|
98
|
+
|
99
|
+
prop :is_expanded,
|
100
|
+
type: t.bool,
|
101
|
+
source: :expanded?
|
102
|
+
|
103
|
+
prop :is_absolute,
|
104
|
+
type: t.bool,
|
105
|
+
source: :absolute?
|
106
|
+
|
107
|
+
prop :is_relative,
|
108
|
+
type: t.bool,
|
109
|
+
source: :relative?
|
110
|
+
|
111
|
+
prop :is_dir,
|
112
|
+
type: t.bool,
|
113
|
+
source: :directory?
|
114
|
+
|
115
|
+
prop :is_file,
|
116
|
+
type: t.bool,
|
117
|
+
source: :file?
|
118
|
+
|
119
|
+
prop :is_cwd,
|
120
|
+
type: t.bool,
|
121
|
+
source: :cwd?
|
122
|
+
|
123
|
+
prop :relative,
|
124
|
+
type: t.maybe( t.path ),
|
125
|
+
source: :relative,
|
126
|
+
to_data: :to_s
|
127
|
+
|
128
|
+
prop :realpath,
|
129
|
+
type: t.maybe( t.path ),
|
130
|
+
source: :try_realpath,
|
131
|
+
to_data: :to_s
|
132
|
+
|
133
|
+
prop :is_realpath,
|
134
|
+
type: t.bool,
|
135
|
+
source: :realpath?
|
136
|
+
|
137
|
+
|
138
|
+
# Composed properties
|
139
|
+
# ---------------------------------------------------------------------
|
140
|
+
#
|
141
|
+
# On-demand values that point to other {NRSER::Meta::Props} instances.
|
142
|
+
#
|
143
|
+
|
144
|
+
prop :git,
|
145
|
+
type: QB::Repo::Git,
|
146
|
+
source: :git
|
147
|
+
|
64
148
|
|
65
149
|
# Constructor
|
66
150
|
# ======================================================================
|
67
151
|
|
68
|
-
#
|
69
|
-
|
70
|
-
|
71
|
-
|
152
|
+
# @overload initialize path
|
153
|
+
# Initialize in the same way as you would a {Pathname}. {#cwd} is set to
|
154
|
+
# the current directory (via {Pathname#getwd}) and the `path` argument is
|
155
|
+
# assigned to {#raw}.
|
156
|
+
#
|
157
|
+
# @param [String | Pathname] path
|
158
|
+
# Target path.
|
159
|
+
#
|
160
|
+
# @overload initialize **values
|
161
|
+
# Initialize by invoking {NRSER::Meta::Props#initialize_props}.
|
162
|
+
#
|
163
|
+
# The {#raw} value is passed up to {Pathname#initialize}.
|
164
|
+
#
|
165
|
+
# {#cwd} is accepted in `values`, allowing a re-instantiated object to
|
166
|
+
# "make sense" when the process' current directory may no longer be the
|
167
|
+
# one that data was constructed against.
|
168
|
+
#
|
169
|
+
# {#cwd} defaults to the current directory (via {Pathname.getwd}) if not
|
170
|
+
# provided.
|
171
|
+
#
|
172
|
+
# @param **values see {NRSER::Meta::Props#initialize_props}
|
173
|
+
#
|
174
|
+
def initialize arg
|
175
|
+
case arg
|
176
|
+
when Hash
|
177
|
+
super arg[:raw]
|
178
|
+
initialize_props cwd: Pathname.getwd, **arg
|
179
|
+
else
|
180
|
+
super arg
|
181
|
+
initialize_props raw: arg, cwd: Pathname.getwd
|
182
|
+
end
|
72
183
|
end # #initialize
|
73
184
|
|
74
185
|
|
@@ -76,13 +187,102 @@ class QB::Path < Pathname
|
|
76
187
|
# ======================================================================
|
77
188
|
|
78
189
|
# @return [Boolean]
|
79
|
-
# `true` if
|
190
|
+
# `true` if `self` is equal to {#expand_path}.
|
191
|
+
#
|
80
192
|
def expanded?
|
193
|
+
self == expand_path
|
194
|
+
end
|
195
|
+
|
196
|
+
|
197
|
+
# @return [Boolean]
|
198
|
+
# `true` if `self` is equal to {#cwd}.
|
199
|
+
#
|
200
|
+
def cwd?
|
201
|
+
self == cwd
|
202
|
+
end
|
203
|
+
|
204
|
+
|
205
|
+
# Relative path from {#cwd} to `self`, if one exists.
|
206
|
+
#
|
207
|
+
# @return [QB::Path]
|
208
|
+
# If a relative path from {#cwd} to `self` exists.
|
209
|
+
#
|
210
|
+
# @return [nil]
|
211
|
+
# If no relative path from {#cwd} to `self` exists. Can't recall exactly
|
212
|
+
# how this happens, but I guess it can...
|
213
|
+
#
|
214
|
+
def relative
|
215
|
+
begin
|
216
|
+
relative_path_from cwd
|
217
|
+
rescue ArgumentError => error
|
218
|
+
nil
|
219
|
+
end
|
220
|
+
end
|
221
|
+
|
222
|
+
|
223
|
+
# Like {Pathname#realpath} but returns {nil} instead of raising if there
|
224
|
+
# isn't one.
|
225
|
+
#
|
226
|
+
# @return [nil]
|
227
|
+
# If there is no real path.
|
228
|
+
#
|
229
|
+
# @return [Pathname]
|
230
|
+
# If there is a real path.
|
231
|
+
#
|
232
|
+
def try_realpath
|
233
|
+
begin
|
234
|
+
realpath
|
235
|
+
rescue SystemCallError => error
|
236
|
+
nil
|
237
|
+
end
|
238
|
+
end
|
239
|
+
|
240
|
+
|
241
|
+
# Is `self` already it's real path?
|
242
|
+
#
|
243
|
+
# @return [Boolean]
|
244
|
+
# `true` if `self` and {#try_realpath} are equal.
|
245
|
+
#
|
246
|
+
def realpath?
|
247
|
+
self == try_realpath
|
248
|
+
end # #realpath?
|
249
|
+
|
250
|
+
|
251
|
+
# @return [Pathname]
|
252
|
+
# A regular (non-{QB::Path}) {Pathname} version of `self`.
|
253
|
+
def path
|
254
|
+
Pathname.new self
|
255
|
+
end
|
256
|
+
|
257
|
+
|
258
|
+
# Composed Sub-Instances
|
259
|
+
# ---------------------------------------------------------------------
|
260
|
+
|
261
|
+
# {QB::Repo::Git} resource for the Git repo {#path} is in one, or {nil} if
|
262
|
+
# it isn't.
|
263
|
+
#
|
264
|
+
# @return [QB::Repo::Git]
|
265
|
+
# If {#path} is in a Git repo.
|
266
|
+
#
|
267
|
+
# @return [nil]
|
268
|
+
# If {#path} is not in a Git repo.
|
269
|
+
#
|
270
|
+
def git
|
271
|
+
unless instance_variable_defined? :@git
|
272
|
+
@git = QB::Repo::Git.from_path path
|
273
|
+
end
|
81
274
|
|
275
|
+
@git
|
276
|
+
end
|
277
|
+
|
278
|
+
|
279
|
+
def gem
|
280
|
+
unless instance_variable_defined? :@gem
|
281
|
+
@gem = QB::Package::Gem.from_root_path path
|
282
|
+
end
|
283
|
+
|
284
|
+
@gem
|
82
285
|
end
|
83
286
|
|
84
287
|
end # class QB::Path
|
85
288
|
|
86
|
-
|
87
|
-
# Post-Processing
|
88
|
-
# =======================================================================
|
data/lib/qb/repo/git.rb
CHANGED
@@ -1,17 +1,43 @@
|
|
1
|
+
# Requirements
|
2
|
+
# =======================================================================
|
3
|
+
|
4
|
+
# Stdlib
|
5
|
+
# -----------------------------------------------------------------------
|
6
|
+
|
7
|
+
# Deps
|
8
|
+
# -----------------------------------------------------------------------
|
1
9
|
require 'cmds'
|
2
|
-
require 'nrser/refinements/types'
|
3
10
|
|
11
|
+
# Project / Package
|
12
|
+
# -----------------------------------------------------------------------
|
13
|
+
|
14
|
+
|
15
|
+
# Refinements
|
16
|
+
# =======================================================================
|
17
|
+
|
18
|
+
require 'nrser/refinements'
|
19
|
+
using NRSER
|
20
|
+
|
21
|
+
require 'nrser/refinements/types'
|
4
22
|
using NRSER::Types
|
5
23
|
|
6
|
-
|
7
|
-
|
24
|
+
|
25
|
+
# Declarations
|
26
|
+
# =======================================================================
|
27
|
+
|
28
|
+
module QB; end
|
29
|
+
module QB::Repo; end
|
30
|
+
|
31
|
+
|
32
|
+
# Definitions
|
33
|
+
# =======================================================================
|
8
34
|
|
9
35
|
# Encapsulate information about a Git repository and expose useful operations as
|
10
36
|
# instance methods.
|
11
37
|
#
|
12
38
|
# The main entry point is {QB::Repo::Git.from_path}, which creates a
|
13
39
|
#
|
14
|
-
class Git < NRSER::Meta::Props::Base
|
40
|
+
class QB::Repo::Git < NRSER::Meta::Props::Base
|
15
41
|
GITHUB_SSH_URL_RE = /^git@github\.com\:(?<owner>.*)\/(?<name>.*)\.git$/
|
16
42
|
GITHUB_HTTPS_URL_RE = /^https:\/\/github\.com\/(?<owner>.*)\/(?<name>.*)\.git$/
|
17
43
|
|
@@ -93,19 +119,30 @@ class Git < NRSER::Meta::Props::Base
|
|
93
119
|
# Class Methods
|
94
120
|
# =====================================================================
|
95
121
|
|
96
|
-
#
|
122
|
+
# Instantiate a {QB::Package::Git} resource for whatever Git repo `path`
|
123
|
+
# is in, or return `nil` if `path` is not in a Git repo.
|
97
124
|
#
|
98
|
-
# @param [String, Pathname]
|
99
|
-
# A path that
|
125
|
+
# @param [String, Pathname] path
|
126
|
+
# A path that may be in the Git repo.
|
127
|
+
#
|
128
|
+
# @param [Boolean] use_github_api:
|
129
|
+
# When `true` will will contact the GitHub API for information to populate
|
130
|
+
# the {QB::Repo::Git#github} property for repos that have a GitHub origin
|
131
|
+
# URL.
|
132
|
+
#
|
133
|
+
# Otherwise we will just assume GitHub repos are private since it's the
|
134
|
+
# safe guess, resulting in a {QB::Repo::Git#github} value of
|
135
|
+
# `{private: true}`.
|
100
136
|
#
|
101
137
|
# @return [QB::Repo::Git]
|
138
|
+
# If `path` is in a Git repo.
|
139
|
+
#
|
140
|
+
# @return [nil]
|
141
|
+
# If `path` is not in a Git repo.
|
102
142
|
#
|
103
143
|
# @raise [QB::FSStateError]
|
104
144
|
# - If we can't find any existing directory to look in based on
|
105
145
|
# `input_path`.
|
106
|
-
#
|
107
|
-
# - If the directory we do find to look in does not seems to be part of
|
108
|
-
# a Git repo.
|
109
146
|
#
|
110
147
|
def self.from_path path, use_github_api: false
|
111
148
|
raw_input_path = path
|
@@ -129,9 +166,7 @@ class Git < NRSER::Meta::Props::Base
|
|
129
166
|
root_result = Cmds.capture "git rev-parse --show-toplevel"
|
130
167
|
|
131
168
|
unless root_result.ok?
|
132
|
-
|
133
|
-
"Path #{ raw_input_path.inspect } does not appear to be in a " +
|
134
|
-
"Git repo (looked in #{ closest_dir.inspect })."
|
169
|
+
return nil
|
135
170
|
end
|
136
171
|
|
137
172
|
root = Pathname.new root_result.out.chomp
|
@@ -217,11 +252,39 @@ class Git < NRSER::Meta::Props::Base
|
|
217
252
|
end # .from_path
|
218
253
|
|
219
254
|
|
255
|
+
# Instantiate a {QB::Package::Git} resource for whatever Git repo `path`
|
256
|
+
# is in, raising an error if it's not in one.
|
257
|
+
#
|
258
|
+
# @param [String, Pathname] path
|
259
|
+
# A path that is in the Git repo.
|
260
|
+
#
|
261
|
+
# @param use_github_api: see #from_path
|
262
|
+
#
|
263
|
+
# @return [QB::Repo::Git]
|
264
|
+
#
|
265
|
+
# @raise [QB::FSStateError]
|
266
|
+
# - If we can't find any existing directory to look in based on
|
267
|
+
# `input_path`.
|
268
|
+
#
|
269
|
+
# - If the directory we do find to look in does not seems to be part of
|
270
|
+
# a Git repo.
|
271
|
+
#
|
272
|
+
def from_path! path, use_github_api: false
|
273
|
+
from_path( path, use_github_api: use_github_api ).tap { |git|
|
274
|
+
if git.nil?
|
275
|
+
raise QB::FSStateError,
|
276
|
+
"Path #{ path.inspect } does not appear to be in a " +
|
277
|
+
"Git repo."
|
278
|
+
end
|
279
|
+
}
|
280
|
+
end # #from_path!
|
281
|
+
|
282
|
+
|
220
283
|
# Props
|
221
284
|
# =====================================================================
|
222
285
|
|
223
|
-
prop :raw_input_path, type: t.
|
224
|
-
prop :root, type:
|
286
|
+
prop :raw_input_path, type: t.path, default: nil, to_data: :to_s
|
287
|
+
prop :root, type: t.pathname, to_data: :to_s
|
225
288
|
prop :user, type: User
|
226
289
|
prop :is_clean, type: t.bool
|
227
290
|
prop :head, type: t.maybe(t.str), default: nil
|
@@ -231,6 +294,10 @@ class Git < NRSER::Meta::Props::Base
|
|
231
294
|
prop :name, type: t.maybe(t.str), default: nil
|
232
295
|
prop :github, type: t.maybe(t.hash_), default: nil
|
233
296
|
|
297
|
+
|
298
|
+
# Derived Properties
|
299
|
+
# ---------------------------------------------------------------------
|
300
|
+
|
234
301
|
prop :head_short, type: t.maybe(t.str), source: :head_short
|
235
302
|
prop :full_name, type: t.maybe(t.str), source: :full_name
|
236
303
|
prop :is_github, type: t.bool, source: :github?
|
@@ -251,11 +318,15 @@ class Git < NRSER::Meta::Props::Base
|
|
251
318
|
!github.nil?
|
252
319
|
end
|
253
320
|
|
321
|
+
|
322
|
+
# Reading Repo State
|
323
|
+
# ---------------------------------------------------------------------
|
324
|
+
|
325
|
+
# @return [Boolean]
|
326
|
+
# `false` if the repo has any uncommitted changes or untracked files.
|
327
|
+
#
|
254
328
|
def clean?
|
255
329
|
is_clean
|
256
330
|
end
|
257
331
|
|
258
|
-
end # class Git
|
259
|
-
|
260
|
-
end # module Repo
|
261
|
-
end # module QB
|
332
|
+
end # class QB::Repo::Git
|
data/lib/qb/role.rb
CHANGED
@@ -411,19 +411,37 @@ class QB::Role
|
|
411
411
|
path = QB::Util.resolve dest
|
412
412
|
|
413
413
|
search_dirs = search_path.find_all { |pathname|
|
414
|
-
path.fnmatch? pathname
|
414
|
+
path.fnmatch?( pathname / '**' )
|
415
415
|
}
|
416
416
|
|
417
417
|
case search_dirs.length
|
418
418
|
when 0
|
419
419
|
# It's not in any of the search directories
|
420
420
|
#
|
421
|
-
# If it has 'roles' as a segment than use what's after
|
421
|
+
# If it has 'roles' as a segment than use what's after the last occurrence
|
422
|
+
# of that (unless there isn't anything).
|
422
423
|
#
|
423
|
-
|
424
|
+
segments = path.to_s.split File::SEPARATOR
|
425
|
+
|
426
|
+
if index = segments.rindex( 'roles' )
|
427
|
+
name_segs = segments[index..-1]
|
428
|
+
|
429
|
+
unless name_segs.empty?
|
430
|
+
return File.join name_segs
|
431
|
+
end
|
432
|
+
end
|
433
|
+
|
434
|
+
# Ok, that didn't work... just return the basename I guess...
|
435
|
+
File.basename path
|
436
|
+
|
437
|
+
when 1
|
438
|
+
|
439
|
+
else
|
440
|
+
# Multiple matches?!?!?
|
441
|
+
|
424
442
|
|
425
443
|
end
|
426
|
-
end
|
444
|
+
end # #guess_role_name
|
427
445
|
|
428
446
|
|
429
447
|
# Instance Attributes
|