summaryrefslogtreecommitdiffstats
path: root/lib/puppet/interface
diff options
context:
space:
mode:
authorDaniel Pittman <daniel@puppetlabs.com>2011-04-20 15:51:39 -0700
committerDaniel Pittman <daniel@puppetlabs.com>2011-04-21 12:37:26 -0700
commitf17f6bba87519db888854acf7017ddff61f635be (patch)
treedc092056e59e018bb6e56f1c4918685220d21ad9 /lib/puppet/interface
parent7414ee7ebda1052f4c52f3e5565726f20de5a20b (diff)
downloadpuppet-f17f6bba87519db888854acf7017ddff61f635be.tar.gz
puppet-f17f6bba87519db888854acf7017ddff61f635be.tar.xz
puppet-f17f6bba87519db888854acf7017ddff61f635be.zip
(#7183) Implement "invisible glob" version matching for faces
"Invisible glob", or "prefix", version matching means that when you specify a version string to use you can specify as little as one version number out of the semantic versioning spec. Matching is done on the prefix; an omitted number is treated as "anything" in that slot, and we return the highest matching versioned face by that spec. For example, given the set of versions: 1.0.0, 1.0.1, 1.1.0, 1.1.1, 2.0.0 The following would be matched: input matched 1 1.1.1 1.0 1.0.1 1.0.1 1.0.1 1.0.2 fail - no match 1.1 1.1.1 1.1.1 1.1.1 1.2 fail - no match
Diffstat (limited to 'lib/puppet/interface')
-rw-r--r--lib/puppet/interface/face_collection.rb58
1 files changed, 35 insertions, 23 deletions
diff --git a/lib/puppet/interface/face_collection.rb b/lib/puppet/interface/face_collection.rb
index 49e007ec0..6e6afc545 100644
--- a/lib/puppet/interface/face_collection.rb
+++ b/lib/puppet/interface/face_collection.rb
@@ -31,12 +31,14 @@ module Puppet::Interface::FaceCollection
!!(SEMVER_VERSION =~ version.to_s)
end
+ def self.semver_to_array(v)
+ parts = SEMVER_VERSION.match(v).to_a[1..4]
+ parts[0..2] = parts[0..2].map { |e| e.to_i }
+ parts
+ end
+
def self.cmp_semver(a, b)
- a, b = [a, b].map do |x|
- parts = SEMVER_VERSION.match(x).to_a[1..4]
- parts[0..2] = parts[0..2].map { |e| e.to_i }
- parts
- end
+ a, b = [a, b].map do |x| semver_to_array(x) end
cmp = a[0..2] <=> b[0..2]
if cmp == 0
@@ -47,18 +49,38 @@ module Puppet::Interface::FaceCollection
cmp
end
- def self.[](name, version)
- @faces[underscorize(name)][version] if face?(name, version)
+ def self.prefix_match?(desired, target)
+ # Can't meaningfully do a prefix match with current on either side.
+ return false if desired == :current
+ return false if target == :current
+
+ # REVISIT: Should probably fail if the matcher is not valid.
+ prefix = desired.split('.').map {|x| x =~ /^\d+$/ and x.to_i }
+ have = semver_to_array(target)
+
+ while want = prefix.shift do
+ return false unless want == have.shift
+ end
+ return true
end
- def self.face?(name, version)
+ def self.[](name, version)
name = underscorize(name)
+ get_face(name, version) or load_face(name, version)
+ end
- # Note: be careful not to accidentally create the top level key, either,
- # because it will result in confusion when people try to enumerate the
- # list of valid faces later. --daniel 2011-04-11
- return true if @faces.has_key?(name) and @faces[name].has_key?(version)
+ # get face from memory, without loading.
+ def self.get_face(name, desired_version)
+ return nil unless @faces.has_key? name
+ return @faces[name][:current] if desired_version == :current
+
+ found = @faces[name].keys.select {|v| prefix_match?(desired_version, v) }.sort.last
+ return @faces[name][found]
+ end
+
+ # try to load the face, and return it.
+ def self.load_face(name, version)
# We always load the current version file; the common case is that we have
# the expected version and any compatibility versions in the same file,
# the default. Which means that this is almost always the case.
@@ -104,17 +126,7 @@ module Puppet::Interface::FaceCollection
# ...guess we didn't find the file; return a much better problem.
end
- # Now, either we have the version in our set of faces, or we didn't find
- # the version they were looking for. In the future we will support
- # loading versioned stuff from some look-aside part of the Ruby load path,
- # but we don't need that right now.
- #
- # So, this comment is a place-holder for that. --daniel 2011-04-06
- #
- # Note: be careful not to accidentally create the top level key, either,
- # because it will result in confusion when people try to enumerate the
- # list of valid faces later. --daniel 2011-04-11
- return !! (@faces.has_key?(name) and @faces[name].has_key?(version))
+ return get_face(name, version)
end
def self.register(face)