qb 0.1.77 → 0.1.78

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: 5034072491c569409a8d336f915896be6a6d0b0e
4
- data.tar.gz: 121e0e57dc4eeb6b1f35e5ce2695c7f6c1b2380b
3
+ metadata.gz: a116f7c56db4ada78655a13a0bd1082c1a0f3489
4
+ data.tar.gz: 62ef6a65bc735292b9e78232f698d34f59e3bedc
5
5
  SHA512:
6
- metadata.gz: b49a812b695412a1d0eaced107e01ea49d978fdc4266ebb87e89fb8db0738aed30db5c9d3e45db6d4fbccfa3d881e912ab4f19baf2ad717938d56fa8e009b852
7
- data.tar.gz: 392d529ac62f2fc62b76983f87819207f2a7022ce444f4de48b6e53b8ab6205ae5e4a035748d6c5bdb98187cc3afbdced6a87a3ac3f88eb5e5d1efe3095113d2
6
+ metadata.gz: 5dba83f32282f531f8e3cca01a78db53b1daac2025a9a9a8c2bb62688f7a70af894f0071cfdbbeba00b2e35372e011c63b7f44053250f5434489fc3a94db2e68
7
+ data.tar.gz: cdb4b31a280a269e6e344493f4969145f1217716be071481504b327dfaf05b2d5ec47dac93acd83e05095568441ea754dcb099790625bee5b12e0c74b26b1d31
data/lib/qb.rb CHANGED
@@ -1,10 +1,9 @@
1
1
  require 'nrser/extras'
2
2
 
3
3
  require_relative './qb/errors'
4
- require_relative "./qb/version"
5
- require_relative "./qb/util"
6
- require_relative './qb/util/stdio'
7
- require_relative "./qb/ansible_module"
4
+ require_relative './qb/version'
5
+ require_relative './qb/util'
6
+ require_relative './qb/ansible_module'
8
7
 
9
8
  module QB
10
9
  ROOT = (Pathname.new(__FILE__).dirname + '..').expand_path
@@ -38,4 +37,5 @@ end
38
37
 
39
38
  # needs QB::*_ROLES_DIR
40
39
  require 'qb/role'
41
- require 'qb/options'
40
+ require 'qb/options'
41
+ require_relative './qb/repo'
@@ -1,10 +1,10 @@
1
1
  require 'time'
2
2
 
3
- require 'nrser/types'
3
+ require 'nrser/refinements/types'
4
4
 
5
- require 'qb/util/docker_mixin'
5
+ using NRSER::Types
6
6
 
7
- T = NRSER::Types
7
+ require 'qb/util/docker_mixin'
8
8
 
9
9
  module QB
10
10
  module Package
@@ -13,9 +13,51 @@ module QB
13
13
  #
14
14
  # Intended to be immutable for practical purposes.
15
15
  #
16
- class Version
16
+ class Version < NRSER::Meta::Props::Base
17
+
18
+ # Mixins
19
+ # =====================================================================
20
+
17
21
  include QB::Util::DockerMixin
18
22
 
23
+
24
+ # Constants
25
+ # =====================================================================
26
+
27
+ NUMBER_SEGMENT = t.non_neg_int
28
+ NAME_SEGMENT = t.str
29
+ MIXED_SEGMENT = t.union NUMBER_SEGMENT, NAME_SEGMENT
30
+
31
+
32
+ # Props
33
+ # =====================================================================
34
+
35
+ prop :raw, type: t.maybe(t.str), default: nil
36
+ prop :major, type: NUMBER_SEGMENT
37
+ prop :minor, type: NUMBER_SEGMENT, default: 0
38
+ prop :patch, type: NUMBER_SEGMENT, default: 0
39
+ prop :prerelease, type: t.array(MIXED_SEGMENT), default: []
40
+ prop :build, type: t.array(MIXED_SEGMENT), default: []
41
+
42
+ prop :release, type: t.str, source: :@release
43
+ prop :level, type: t.str, source: :@level
44
+ prop :is_release, type: t.bool, source: :release?
45
+ prop :is_prerelease, type: t.bool, source: :prerelease?
46
+ prop :is_build, type: t.bool, source: :build?
47
+ prop :is_dev, type: t.bool, source: :dev?
48
+ prop :is_rc, type: t.bool, source: :rc?
49
+ prop :has_level, type: t.bool, source: :level?
50
+ prop :semver, type: t.str, source: :semver
51
+ prop :docker_tag, type: t.str, source: :docker_tag
52
+
53
+
54
+ # Attributes
55
+ # =====================================================================
56
+
57
+ attr_reader :release,
58
+ :level
59
+
60
+
19
61
  # Class Methods
20
62
  # =====================================================================
21
63
 
@@ -116,79 +158,21 @@ module QB
116
158
  end
117
159
 
118
160
 
119
- # Instantiate from a hash. Slices out
120
- #
121
- # - `raw`
122
- # - `major`
123
- # - `minor`
124
- # - `patch`
125
- # - `prerelease`
126
- # - `build`
127
- #
128
- # And passes their values to the constructor. Keys may be strings or
129
- # symbols. All other key/values are ignored, allowing you to pass in
130
- # the JSON encoding of a version instance.
131
- #
132
- # @param [Hash] hash
133
- # Values to be passed to constructor.
134
- #
135
- # @return [QB::Package::Version]
136
- #
137
- def self.from_h hash
138
- self.new(
139
- NRSER.slice_keys(
140
- NRSER.symbolize_keys(hash),
141
- :raw,
142
- :major,
143
- :minor,
144
- :patch,
145
- :prerelease,
146
- :build,
147
- )
148
- )
149
- end # #from_h
150
-
151
-
152
-
153
- # Attributes
154
- # =====================================================================
155
-
156
- attr_reader :raw,
157
- :major,
158
- :minor,
159
- :patch,
160
- :prerelease,
161
- :build,
162
- :release,
163
- :level
164
-
165
-
166
161
  # Constructor
167
162
  # =====================================================================
168
163
 
169
164
  # Construct a new Version
170
- def initialize(
171
- raw: nil,
172
- major:,
173
- minor: 0,
174
- patch: 0,
175
- prerelease: [],
176
- build: []
177
- )
178
- @raw = T.maybe(T.str).check raw
179
- @major = T.non_neg_int.check major
180
- @minor = T.non_neg_int.check minor
181
- @patch = T.non_neg_int.check patch
182
- @prerelease = T.array(T.union(T.non_neg_int, T.str)).check prerelease
183
- @build = T.array(T.union(T.non_neg_int, T.str)).check build
165
+ def initialize **values
166
+ super **values
167
+
184
168
  @release = [major, minor, patch].join '.'
185
169
 
186
- @level = T.match @prerelease[0], {
187
- T.is(nil) => ->(_) { nil },
170
+ @level = t.match prerelease[0], {
171
+ t.is(nil) => ->(_) { nil },
188
172
 
189
- T.str => ->(str) { str },
173
+ NAME_SEGMENT => ->(str) { str },
190
174
 
191
- T.non_neg_int => ->(int) { nil },
175
+ NUMBER_SEGMENT => ->(int) { nil },
192
176
  }
193
177
  end
194
178
 
@@ -203,7 +187,7 @@ module QB
203
187
  # True if this version is a release (no prerelease or build values).
204
188
  #
205
189
  def release?
206
- @prerelease.empty? && @build.empty?
190
+ prerelease.empty? && build.empty?
207
191
  end
208
192
 
209
193
 
@@ -214,7 +198,7 @@ module QB
214
198
  # empty.
215
199
  #
216
200
  def prerelease?
217
- !@prerelease.empty?
201
+ !prerelease.empty?
218
202
  end
219
203
 
220
204
 
@@ -227,7 +211,7 @@ module QB
227
211
  # Gem version.
228
212
  #
229
213
  def build?
230
- !@build.empty?
214
+ !build.empty?
231
215
  end
232
216
 
233
217
 
@@ -236,7 +220,7 @@ module QB
236
220
  # we consider the 'level'.
237
221
  #
238
222
  def level?
239
- !@level.nil?
223
+ !level.nil?
240
224
  end
241
225
 
242
226
 
@@ -245,7 +229,7 @@ module QB
245
229
  # is 'dev').
246
230
  #
247
231
  def dev?
248
- @level == 'dev'
232
+ level == 'dev'
249
233
  end
250
234
 
251
235
 
@@ -254,7 +238,7 @@ module QB
254
238
  # is 'rc').
255
239
  #
256
240
  def rc?
257
- @level == 'rc'
241
+ level == 'rc'
258
242
  end
259
243
 
260
244
 
@@ -282,6 +266,14 @@ module QB
282
266
  alias_method :normalized, :semver
283
267
 
284
268
 
269
+
270
+ # Related Versions
271
+ # ---------------------------------------------------------------------
272
+ #
273
+ # Functions that construct new version instances based on the current
274
+ # one as well as additional information provided.
275
+ #
276
+
285
277
  # @return [QB::Package::Version]
286
278
  # A new {QB::Package::Version} created from {#release}. Even if `self`
287
279
  # *is* a release version already, still returns a new instance.
@@ -291,11 +283,6 @@ module QB
291
283
  end # #release_version
292
284
 
293
285
 
294
- def merge overrides = {}
295
- self.class.from_h self.to_h.merge(overrides)
296
- end
297
-
298
-
299
286
  # Return a new {QB::Package::Version} with build information added.
300
287
  #
301
288
  # @return [QB::Package::Version]
@@ -318,6 +305,17 @@ module QB
318
305
  merge raw: nil, build: segments
319
306
  end
320
307
 
308
+
309
+ # @return [QB::Package::Version]
310
+ # A new {QB::Package::Version} created from {#release} and
311
+ # {#prerelease} data, but without any build information.
312
+ #
313
+ def prerelease_version
314
+ merge raw: nil, build: []
315
+ end # #prerelease_version
316
+
317
+
318
+
321
319
  # Docker image tag for the version.
322
320
  #
323
321
  # See {QB::Util::DockerMixin::ClassMethods#to_docker_tag}.
@@ -391,29 +389,6 @@ module QB
391
389
  end
392
390
 
393
391
 
394
- # dump all instance variables into a hash
395
- def to_h
396
- instance_variables.map {|var|
397
- [var[1..-1], instance_variable_get(var)]
398
- }.to_h
399
- end # #to_h
400
-
401
-
402
- # Dump all instance variables in JSON serialization
403
- def to_json *args
404
- to_h.merge(
405
- is_release: release?,
406
- is_prerelease: prerelease?,
407
- is_build: build?,
408
- is_dev: dev?,
409
- is_rc: rc?,
410
- has_level: level?,
411
- semver: semver,
412
- docker_tag: docker_tag,
413
- ).to_json *args
414
- end
415
-
416
-
417
392
  def to_s
418
393
  "#<QB::Package::Version #{ @raw }>"
419
394
  end
@@ -0,0 +1 @@
1
+ require_relative './repo/git'
@@ -0,0 +1,261 @@
1
+ require 'cmds'
2
+ require 'nrser/refinements/types'
3
+
4
+ using NRSER::Types
5
+
6
+ module QB
7
+ module Repo
8
+
9
+ # Encapsulate information about a Git repository and expose useful operations as
10
+ # instance methods.
11
+ #
12
+ # The main entry point is {QB::Repo::Git.from_path}, which creates a
13
+ #
14
+ class Git < NRSER::Meta::Props::Base
15
+ GITHUB_SSH_URL_RE = /^git@github\.com\:(?<owner>.*)\/(?<name>.*)\.git$/
16
+ GITHUB_HTTPS_URL_RE = /^https:\/\/github\.com\/(?<owner>.*)\/(?<name>.*)\.git$/
17
+
18
+ class User < NRSER::Meta::Props::Base
19
+ prop :name, type: t.maybe(t.str), default: nil
20
+ prop :email, type: t.maybe(t.str), default: nil
21
+ end
22
+
23
+
24
+ # class GitHubRemote < NRSER::Meta::Props::Base
25
+ # SSH_URL_RE = /^git@github\.com\:(?<owner>.*)\/(?<name>.*)\.git$/
26
+ # HTTPS_URL_RE = /^https:\/\/github\.com\/(?<owner>.*)\/(?<name>.*)\.git$/
27
+ #
28
+ # prop :owner, type: t.str
29
+ # prop :name, type: t.str
30
+ # prop :api_response, type: t.maybe(t.hash)
31
+ #
32
+ # prop :full_name, type: t.str, source: :full_name
33
+ #
34
+ #
35
+ # # Class Methods
36
+ # # =====================================================================
37
+ #
38
+ # # Test if a Git SSH or HTTPS remote url points to GitHub.
39
+ # #
40
+ # # @param [String] url
41
+ # #
42
+ # # @return [Boolean]
43
+ # #
44
+ # def self.url? url
45
+ # SSH_URL_RE.match(url) || HTTPS_URL_RE.match(url)
46
+ # end # .url?
47
+ #
48
+ #
49
+ # # Instantiate an instance from a Git SSH or HTTPS remote url that points
50
+ # # to GitHub.
51
+ # #
52
+ # # @param [type] arg_name
53
+ # # @todo Add name param description.
54
+ # #
55
+ # # @return [QB::Repo::Git::GitHubRemote]
56
+ # # @todo Document return value.
57
+ # #
58
+ # def self.from_url url, use_api: false
59
+ # match = SSH_URL_RE.match(git.origin) ||
60
+ # HTTPS_URL_RE.match(git.origin)
61
+ #
62
+ # unless match
63
+ # raise ArgumentError.new NRSER.squish <<-END
64
+ # url #{ url.inspect } does not match GitHub SSH or HTTPS patterns.
65
+ # END
66
+ # end
67
+ #
68
+ # owner = match['owner']
69
+ # name = match['name']
70
+ #
71
+ # if use_api
72
+ #
73
+ # end
74
+ # end # .from_url
75
+ #
76
+ #
77
+ #
78
+ # # @todo Document full_name method.
79
+ # #
80
+ # # @param [type] arg_name
81
+ # # @todo Add name param description.
82
+ # #
83
+ # # @return [return_type]
84
+ # # @todo Document return value.
85
+ # #
86
+ # def full_name arg_name
87
+ # "#{ owner }/#{ name }"
88
+ # end # #full_name
89
+ #
90
+ # end
91
+
92
+
93
+ # Class Methods
94
+ # =====================================================================
95
+
96
+ # @todo Document from_path method.
97
+ #
98
+ # @param [String, Pathname] input_path
99
+ # A path that is in the Git repo.
100
+ #
101
+ # @return [QB::Repo::Git]
102
+ #
103
+ # @raise [QB::FSStateError]
104
+ # - If we can't find any existing directory to look in based on
105
+ # `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
+ #
110
+ def self.from_path path, use_github_api: false
111
+ raw_input_path = path
112
+
113
+ # Create a Pathname from the input
114
+ input_path = Pathname.new raw_input_path
115
+
116
+ # input_path may point to a file, or something that doesn't even exist.
117
+ # We want to ascend until we find an existing directory that we can cd into.
118
+ closest_dir = input_path.ascend.find {|p| p.directory?}
119
+
120
+ # Make sure we found something
121
+ if closest_dir.nil?
122
+ raise QB::FSStateError,
123
+ "Unable to find any existing directory from path " +
124
+ "#{ raw_input_path.inspect }"
125
+ end
126
+
127
+ # Change into the directory to make shell life easier
128
+ Dir.chdir closest_dir do
129
+ root_result = Cmds.capture "git rev-parse --show-toplevel"
130
+
131
+ unless root_result.ok?
132
+ raise QB::FSStateError,
133
+ "Path #{ raw_input_path.inspect } does not appear to be in a " +
134
+ "Git repo (looked in #{ closest_dir.inspect })."
135
+ end
136
+
137
+ root = Pathname.new root_result.out.chomp
138
+
139
+ user = User.new **NRSER.map_values(User.props.keys) {|key, _|
140
+ begin
141
+ Cmds.chomp! "git config user.#{ key }"
142
+ rescue
143
+ end
144
+ }
145
+
146
+ is_clean = Cmds.chomp!('git status --porcelain 2>/dev/null').empty?
147
+
148
+ rev_parse = Cmds.capture 'git rev-parse HEAD'
149
+
150
+ head = if rev_parse.ok?
151
+ rev_parse.out.chomp
152
+ end
153
+
154
+ branch_result = Cmds.capture 'git branch --no-color 2> /dev/null'
155
+
156
+ branch = if branch_result.ok?
157
+ if line = branch_result.out.lines.find {|line| line.start_with? '*'}
158
+ if m = line.match(/\*\s+(\S+)/)
159
+ m[1]
160
+ end
161
+ end
162
+ end
163
+
164
+ origin = begin
165
+ Cmds.chomp! "git remote get-url origin"
166
+ rescue
167
+ end
168
+
169
+ owner = nil
170
+ name = nil
171
+ github = nil
172
+
173
+ if origin && match = (
174
+ GITHUB_SSH_URL_RE.match(origin) ||
175
+ GITHUB_HTTPS_URL_RE.match(origin)
176
+ )
177
+
178
+ owner = match['owner']
179
+ name = match['name']
180
+
181
+ if use_github_api
182
+ github = OpenStruct.new
183
+ github.api_url = "https://api.github.com/repos/#{ owner }/#{ name }"
184
+
185
+ response = Net::HTTP.get_response URI(github.api_url)
186
+
187
+ if response.is_a? Net::HTTPSuccess
188
+ # parse response body and add everything to github result
189
+ parsed = JSON.parse response.body
190
+ parsed.each {|k, v| github[k] = v}
191
+ else
192
+ # assume it's private if we failed to find it
193
+ github.private = true
194
+ end
195
+
196
+ github = github.to_h
197
+ end
198
+
199
+ end
200
+
201
+ new(
202
+ raw_input_path: raw_input_path,
203
+ input_path: input_path,
204
+ root: root,
205
+ user: user,
206
+ is_clean: is_clean,
207
+ head: head,
208
+ branch: branch,
209
+ origin: origin,
210
+ owner: owner,
211
+ name: name,
212
+ github: github,
213
+ )
214
+
215
+ end # chdir
216
+
217
+ end # .from_path
218
+
219
+
220
+ # Props
221
+ # =====================================================================
222
+
223
+ prop :raw_input_path, type: t.maybe(t.union(Pathname, t.str)), default: nil
224
+ prop :root, type: Pathname
225
+ prop :user, type: User
226
+ prop :is_clean, type: t.bool
227
+ prop :head, type: t.maybe(t.str), default: nil
228
+ prop :branch, type: t.maybe(t.str), default: nil
229
+ prop :origin, type: t.maybe(t.str), default: nil
230
+ prop :owner, type: t.maybe(t.str), default: nil
231
+ prop :name, type: t.maybe(t.str), default: nil
232
+ prop :github, type: t.maybe(t.hash_), default: nil
233
+
234
+ prop :head_short, type: t.maybe(t.str), source: :head_short
235
+ prop :full_name, type: t.maybe(t.str), source: :full_name
236
+ prop :is_github, type: t.bool, source: :github?
237
+
238
+
239
+ # Instance Methods
240
+ # =====================================================================
241
+
242
+ def full_name
243
+ "#{ owner }/#{ name }" if owner && name
244
+ end
245
+
246
+ def head_short
247
+ head[0...7] if head
248
+ end
249
+
250
+ def github?
251
+ !github.nil?
252
+ end
253
+
254
+ def clean?
255
+ is_clean
256
+ end
257
+
258
+ end # class Git
259
+
260
+ end # module Repo
261
+ end # module QB
@@ -1,3 +1,6 @@
1
+ require_relative './util/stdio'
2
+ require_relative './util/interop'
3
+
1
4
  require 'nrser'
2
5
 
3
6
  using NRSER
@@ -112,4 +115,4 @@ module QB
112
115
  return find_up filename, parent
113
116
  end # .find_up
114
117
  end # Util
115
- end # QB
118
+ end # QB
@@ -0,0 +1,51 @@
1
+ require 'nrser/refinements'
2
+
3
+ using NRSER
4
+
5
+ module QB
6
+ module Util
7
+
8
+ module Interop
9
+ class << self
10
+
11
+ # @todo Document receive method.
12
+ #
13
+ # @param [type] arg_name
14
+ # @todo Add name param description.
15
+ #
16
+ # @return [return_type]
17
+ # @todo Document return value.
18
+ #
19
+ def receive
20
+ # method body
21
+ yaml = $stdin.read
22
+
23
+ File.open('./receive.log', 'w') { |f|
24
+ f.write yaml
25
+ }
26
+
27
+ payload = YAML.load yaml
28
+
29
+ data = payload.fetch 'data'
30
+ method = payload.fetch 'method'
31
+ args = payload['args'] || []
32
+ kwds = payload['kwds'] || {}
33
+ args << kwds.symbolize_keys unless kwds.empty?
34
+
35
+ obj = if data.is_a?(Hash) && data.key?(NRSER::Meta::Props::CLASS_KEY)
36
+ NRSER::Meta::Props.from_data data
37
+ else
38
+ data
39
+ end
40
+
41
+ result = obj.send method, *args
42
+
43
+ $stdout.write result.to_yaml
44
+
45
+ end # #receive
46
+
47
+ end # class << self
48
+ end # module Interop
49
+
50
+ end # module Util
51
+ end # module QB
@@ -4,7 +4,7 @@ module QB
4
4
 
5
5
  GEM_NAME = 'qb'
6
6
 
7
- VERSION = "0.1.77"
7
+ VERSION = "0.1.78"
8
8
 
9
9
  MIN_ANSIBLE_VERSION = Gem::Version.new '2.1.2'
10
10
 
@@ -59,9 +59,15 @@ class PathFacts < QB::AnsibleModule
59
59
  end
60
60
 
61
61
 
62
+ def add_git_facts
63
+ @result.git = QB::Repo::Git.from_path @path,
64
+ use_github_api: !!@args['github_api']
65
+ end
66
+
67
+
62
68
  # If the path is part of a Git repo, as well as useful general
63
69
  # Git environment facts.
64
- def add_git_facts
70
+ def add_git_facts_old
65
71
  # see if we're in a git repo. first, we need a directory that exists
66
72
  dir = @path.expand_path.ascend.find {|p| p.directory? }
67
73
 
@@ -0,0 +1,85 @@
1
+ from __future__ import (absolute_import, division, print_function)
2
+ __metaclass__ = type
3
+
4
+ from ansible.errors import AnsibleError
5
+
6
+ import subprocess
7
+ import yaml
8
+
9
+ def qb_send(data, method, *args, **kwds):
10
+ '''
11
+ Load data as an object in ruby and send it a message (call a method).
12
+ '''
13
+
14
+ payload = {
15
+ 'data': data,
16
+ 'method': method,
17
+ 'args': args,
18
+ 'kwds': kwds,
19
+ }
20
+
21
+ input = yaml.safe_dump(payload)
22
+
23
+ ruby_code = '''
24
+ # init bundler in dev env
25
+ if ENV['QB_DEV_ENV']
26
+ ENV.each {|k, v|
27
+ if k.start_with? 'QB_DEV_ENV_'
28
+ ENV[k.sub('QB_DEV_ENV_', '')] = v
29
+ end
30
+ }
31
+ require 'bundler/setup'
32
+ end
33
+
34
+ require 'qb'
35
+
36
+ QB::Util::Interop.receive
37
+ '''
38
+
39
+ process = subprocess.Popen(
40
+ ['/usr/bin/env', 'ruby', '-e', ruby_code],
41
+ stdin=subprocess.PIPE,
42
+ stdout=subprocess.PIPE,
43
+ stderr=subprocess.PIPE,
44
+ )
45
+
46
+ out, err = process.communicate(input)
47
+
48
+ if process.returncode != 0:
49
+ raise AnsibleError('''
50
+ qb_send failed!
51
+
52
+ ERROR:
53
+ %s
54
+ ''' % (err))
55
+
56
+ try:
57
+ result = yaml.load(out)
58
+ except Exception as error:
59
+ raise AnsibleError('''
60
+ qb_send failed to parse response:
61
+
62
+ %s
63
+ ''' % out)
64
+
65
+ return result
66
+
67
+
68
+ class FilterModule(object):
69
+ '''
70
+ Ruby interop filters.
71
+ '''
72
+
73
+ def filters(self):
74
+ return {
75
+ 'qb_send': qb_send,
76
+ }
77
+ # filters()
78
+ # FilterModule
79
+
80
+
81
+ # testing - call camel_case on first cli arg and print result
82
+ if __name__ == '__main__':
83
+ import doctest
84
+ doctest.testmod()
85
+
@@ -103,6 +103,29 @@ def semver_parse(version):
103
103
  # semver_parse()
104
104
 
105
105
 
106
+ def qb_version_parse(version):
107
+ '''Parse version into QB::Package::Version
108
+ '''
109
+
110
+ ruby_code = (
111
+ '''
112
+ require 'qb'
113
+
114
+ puts JSON.parse(
115
+ QB::Package::Version.from_string %s
116
+ )
117
+ ''' % json.dumps(version)
118
+ )
119
+
120
+ cmd = ['/usr/bin/env', 'ruby', '-e', ruby_code]
121
+
122
+ out = subprocess.check_output(cmd)
123
+
124
+ qb_version = json.loads(out)
125
+
126
+ return version
127
+
128
+
106
129
  class FilterModule(object):
107
130
  ''' version manipulation filters '''
108
131
 
@@ -110,6 +133,7 @@ class FilterModule(object):
110
133
  return {
111
134
  'semver_inc': semver_inc,
112
135
  'semver_parse': semver_parse,
136
+ 'qb_version_parse': qb_version_parse,
113
137
  }
114
138
  # filters()
115
139
  # FilterModule
data/qb.gemspec CHANGED
@@ -94,7 +94,7 @@ Gem::Specification.new do |spec|
94
94
  spec.add_development_dependency "yard"
95
95
 
96
96
  spec.add_dependency "cmds",'~> 0.0', ">= 0.2.1"
97
- spec.add_dependency "nrser",'~> 0.0', ">= 0.0.18"
97
+ spec.add_dependency "nrser",'~> 0.0', ">= 0.0.20"
98
98
  spec.add_dependency "nrser-extras", '~> 0.0', ">= 0.0.3"
99
99
  spec.add_dependency "state_mate", '~> 0.0', ">= 0.0.9"
100
100
  spec.add_dependency 'parseconfig', '~> 1.0', '>= 1.0.8'
@@ -21,6 +21,11 @@ require 'json'
21
21
  require 'shellwords'
22
22
  require 'pp'
23
23
 
24
+ # We originally used the name 'vars', but switched to prefer 'bind'.
25
+ # However, we still support either, but doesn't make sense to provide
26
+ # both.
27
+ BIND_ARG_NAMES = ['bind', 'vars']
28
+
24
29
  # Global var to append warning messages to.
25
30
  $warnings = []
26
31
 
@@ -45,11 +50,14 @@ def main
45
50
 
46
51
  args = JSON.load input
47
52
 
48
- var_name = args.fetch 'var_name'
49
-
50
53
  b = binding
51
54
 
52
- ['bind', 'vars'].each do |key|
55
+ if BIND_ARG_NAMES.count {|name| args.key? name } > 1
56
+ raise ArgumentError,
57
+ "Please provide exactly one of args #{ BIND_ARG_NAMES.join ', ' }"
58
+ end
59
+
60
+ BIND_ARG_NAMES.each do |key|
53
61
  if args.key? key
54
62
  args[key].each {|k, v|
55
63
  # Ansible sends null/None values as empty strings, so convert those
@@ -62,12 +70,23 @@ def main
62
70
  end
63
71
 
64
72
  result = b.eval args.fetch('src')
73
+
74
+ ansible_facts = if args.key? 'var_name'
75
+ # We received a var_name, so we consider the result to be it's value
76
+ {args['var_name'] => result}
77
+ else
78
+ # The result should be a hash of variable names to value to set
79
+ unless result.is_a? Hash
80
+ raise "When var_name arg is not provided, result of evaluation must "
81
+ "be a Hash of variable names to value to set. " +
82
+ "Found #{ result.inspect }"
83
+ end
84
+ result
85
+ end
65
86
 
66
87
  print JSON.dump({
67
88
  'changed' => false,
68
- 'ansible_facts' => {
69
- var_name => result,
70
- },
89
+ 'ansible_facts' => ansible_facts,
71
90
  'warnings' => $warnings,
72
91
  })
73
92
 
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.1.77
4
+ version: 0.1.78
5
5
  platform: ruby
6
6
  authors:
7
7
  - nrser
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2017-08-17 00:00:00.000000000 Z
11
+ date: 2017-08-20 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -95,7 +95,7 @@ dependencies:
95
95
  version: '0.0'
96
96
  - - ">="
97
97
  - !ruby/object:Gem::Version
98
- version: 0.0.18
98
+ version: 0.0.20
99
99
  type: :runtime
100
100
  prerelease: false
101
101
  version_requirements: !ruby/object:Gem::Requirement
@@ -105,7 +105,7 @@ dependencies:
105
105
  version: '0.0'
106
106
  - - ">="
107
107
  - !ruby/object:Gem::Version
108
- version: 0.0.18
108
+ version: 0.0.20
109
109
  - !ruby/object:Gem::Dependency
110
110
  name: nrser-extras
111
111
  requirement: !ruby/object:Gem::Requirement
@@ -185,10 +185,13 @@ files:
185
185
  - lib/qb/options.rb
186
186
  - lib/qb/options/option.rb
187
187
  - lib/qb/package/version.rb
188
+ - lib/qb/repo.rb
189
+ - lib/qb/repo/git.rb
188
190
  - lib/qb/role.rb
189
191
  - lib/qb/role/errors.rb
190
192
  - lib/qb/util.rb
191
193
  - lib/qb/util/docker_mixin.rb
194
+ - lib/qb/util/interop.rb
192
195
  - lib/qb/util/stdio.rb
193
196
  - lib/qb/version.rb
194
197
  - library/git_mkdir.py
@@ -204,6 +207,7 @@ files:
204
207
  - node_modules/semver/semver.js
205
208
  - package.json
206
209
  - plugins/filter_plugins/path.py
210
+ - plugins/filter_plugins/ruby_interop.py
207
211
  - plugins/filter_plugins/string.py
208
212
  - plugins/filter_plugins/version.py
209
213
  - plugins/lookup_plugins/every.py