Please review pull request #592: Bug/2.7.x/incorrect dynamic scope warnings opened by (hunner)

Description:

Until the scope inheritance is completely fixed for the new non-dynamic scoping model, we should give appropriate dynamic scoping deprecation warnings.

This branch will perform two queries; one with the dynamic scoping and a second one that directly references the local scope or top/node scope. If the answers differ then removing dynamic scoping would affect the puppet run and a warning should be given.

  • Opened: Fri Mar 23 22:07:58 UTC 2012
  • Based on: puppetlabs:master (0b900c9548f6c652f0d7271156b69c35aa232ead)
  • Requested merge: hunner:bug/2.7.x/incorrect_dynamic_scope-warnings (fa2be2691dd1ba65eb871690d16b540c32ec1453)

Diff follows:

diff --git a/lib/puppet/parser/scope.rb b/lib/puppet/parser/scope.rb
index 746cfbd..24b725e 100644
--- a/lib/puppet/parser/scope.rb
+++ b/lib/puppet/parser/scope.rb
@@ -21,7 +21,7 @@ class Puppet::Parser::Scope
   attr_accessor :source, :resource
   attr_accessor :base, :keyword
   attr_accessor :top, :translated, :compiler
-  attr_accessor :parent, :dynamic
+  attr_accessor :parent
   attr_reader :namespaces
 
   # thin wrapper around an ephemeral
@@ -222,13 +222,48 @@ def qualified_scope(classname)
 
   private :qualified_scope
 
-  # Look up a variable.  The simplest value search we do.
+  # Look up a variable with traditional scoping and then with new scoping. If
+  # the answers differ then print a deprecation warning.
   def lookupvar(name, options = {})
+    oldval = oldlookupvar(name,options)
+    newval = newlookupvar(name,options)
+    if oldval and newval and newval != oldval
+      location = (options[:file] && options[:line]) ? " at #{options[:file]}:#{options[:line]}" : ''
+      Puppet.deprecation_warning "Dynamic lookup of $#{name}#{location} is deprecated.  Support will be removed in a later version of Puppet.  Use a fully-qualified variable name (e.g., $classname::variable) or parameterized classes."
+    end
+    oldval
+  end
+
+  # Look up a variable.  The simplest value search we do.
+  def newlookupvar(name, options = {})
+    # Save the originating scope for the request
+    options[:origin] = self unless options[:origin]
+    table = ephemeral?(name) ? @ephemeral.last : @symtable
+    if name =~ /^(.*)::(.+)$/
+      begin
+        qualified_scope($1).newlookupvar($2,options.merge({:origin => nil}))
+      rescue RuntimeError => e
+        location = (options[:file] && options[:line]) ? " at #{options[:file]}:#{options[:line]}" : ''
+        warning "Could not look up qualified variable '#{name}'; #{e.message}#{location}"
+        :undefined
+      end
+    # If the value is present and either we are top/node scope or originating scope...
+    elsif (ephemeral_include?(name) or table.include?(name)) and (compiler and self == compiler.topscope or (self.resource and self.resource.type == "Node") or self == options[:origin])
+      table[name]
+    elsif parent
+      parent.newlookupvar(name,options)
+    else
+      :undefined
+    end
+  end
+
+  # Look up a variable.  The simplest value search we do.
+  def oldlookupvar(name, options = {})
     table = ephemeral?(name) ? @ephemeral.last : @symtable
     # If the variable is qualified, then find the specified scope and look the variable up there instead.
     if name =~ /^(.*)::(.+)$/
       begin
-        qualified_scope($1).lookupvar($2,options)
+        qualified_scope($1).oldlookupvar($2,options)
       rescue RuntimeError => e
         location = (options[:file] && options[:line]) ? " at #{options[:file]}:#{options[:line]}" : ''
         warning "Could not look up qualified variable '#{name}'; #{e.message}#{location}"
@@ -236,13 +271,9 @@ def lookupvar(name, options = {})
       end
     elsif ephemeral_include?(name) or table.include?(name)
       # We can't use "if table[name]" here because the value might be false
-      if options[:dynamic] and self != compiler.topscope
-        location = (options[:file] && options[:line]) ? " at #{options[:file]}:#{options[:line]}" : ''
-        Puppet.deprecation_warning "Dynamic lookup of $#{name}#{location} is deprecated.  Support will be removed in Puppet 2.8.  Use a fully-qualified variable name (e.g., $classname::variable) or parameterized classes."
-      end
       table[name]
     elsif parent
-      parent.lookupvar(name,options.merge(:dynamic => (dynamic || options[:dynamic])))
+      parent.oldlookupvar(name,options)
     else
       :undefined
     end
@@ -374,7 +405,7 @@ def unset_ephemeral_var(level=:all)
 
   # check if name exists in one of the ephemeral scope.
   def ephemeral_include?(name)
-    @ephemeral.reverse.each do |eph|
+    @ephemeral.reverse_each do |eph|
       return true if eph.include?(name)
     end
     false
diff --git a/lib/puppet/resource/type.rb b/lib/puppet/resource/type.rb
index 600f449..16ed977 100644
--- a/lib/puppet/resource/type.rb
+++ b/lib/puppet/resource/type.rb
@@ -66,7 +66,7 @@ def evaluate_code(resource)
     static_parent = evaluate_parent_type(resource)
     scope = static_parent || resource.scope
 
-    scope = scope.newscope(:namespace => namespace, :source => self, :resource => resource, :dynamic => !static_parent) unless resource.title == :main
+    scope = scope.newscope(:namespace => namespace, :source => self, :resource => resource) unless resource.title == :main
     scope.compiler.add_class(name) unless definition?
 
     set_resource_parameters(resource, scope)
diff --git a/spec/unit/parser/scope_spec.rb b/spec/unit/parser/scope_spec.rb
index 67f0db0..b36ca6d 100755
--- a/spec/unit/parser/scope_spec.rb
+++ b/spec/unit/parser/scope_spec.rb
@@ -3,11 +3,11 @@
 
 describe Puppet::Parser::Scope do
   before :each do
-    @topscope = Puppet::Parser::Scope.new
     # This is necessary so we don't try to use the compiler to discover our parent.
-    @topscope.parent = nil
     @scope = Puppet::Parser::Scope.new
     @scope.compiler = Puppet::Parser::Compiler.new(Puppet::Node.new("foo"))
+    @scope.source = Puppet::Resource::Type.new(:node, :foo)
+    @topscope = @scope.compiler.topscope
     @scope.parent = @topscope
   end
 
@@ -92,14 +92,6 @@
 
       Puppet::Parser::Scope.new.singleton_class.ancestors.should be_include(mod)
     end
-
-    it "should remember if it is dynamic" do
-      (!!Puppet::Parser::Scope.new(:dynamic => true).dynamic).should == true
-    end
-
-    it "should assume it is not dynamic" do
-      (!Puppet::Parser::Scope.new.dynamic).should == true
-    end
   end
 
   describe "when looking up a variable" do
@@ -128,10 +120,20 @@
       @scope.lookupvar("var").should == "childval"
     end
 
+    it "should be able to look up intermediary variables in parent scopes (DEPRECATED)" do
+      Puppet.expects(:deprecation_warning)
+      thirdscope = Puppet::Parser::Scope.new
+      thirdscope.parent = @scope
+      thirdscope.source = Puppet::Resource::Type.new(:hostclass, :foo, :module_name => "foo")
+      @scope.source = Puppet::Resource::Type.new(:hostclass, :bar, :module_name => "bar")
+
+      @topscope.setvar("var2","parentval")
+      @scope.setvar("var2","childval")
+      thirdscope.lookupvar("var2").should == "childval"
+    end
+
     describe "and the variable is qualified" do
-      before do
-        @compiler = Puppet::Parser::Compiler.new(Puppet::Node.new("foonode"))
-        @scope.compiler = @compiler
+      before :each do
         @known_resource_types = @scope.known_resource_types
       end
 
@@ -151,6 +153,7 @@ def create_class_scope(name)
       end
 
       it "should be able to look up explicitly fully qualified variables from main" do
+        Puppet.expects(:deprecation_warning).never
         other_scope = create_class_scope("")
 
         other_scope.setvar("othervar", "otherval")
@@ -159,6 +162,7 @@ def create_class_scope(name)
       end
 
       it "should be able to look up explicitly fully qualified variables from other scopes" do
+        Puppet.expects(:deprecation_warning).never
         other_scope = create_class_scope("other")
 
         other_scope.setvar("var", "otherval")
@@ -167,6 +171,7 @@ def create_class_scope(name)
       end
 
       it "should be able to look up deeply qualified variables" do
+        Puppet.expects(:deprecation_warning).never
         other_scope = create_class_scope("other::deep::klass")
 
         other_scope.setvar("var", "otherval")
@@ -175,28 +180,33 @@ def create_class_scope(name)
       end
 
       it "should return ':undefined' for qualified variables that cannot be found in other classes" do
+        Puppet.expects(:deprecation_warning).never
         other_scope = create_class_scope("other::deep::klass")
 
         @scope.lookupvar("other::deep::klass::var").should == :undefined
       end
 
       it "should warn and return ':undefined' for qualified variables whose classes have not been evaluated" do
+        Puppet.expects(:deprecation_warning).never
         klass = newclass("other::deep::klass")
-        @scope.expects(:warning)
+        @scope.expects(:warning).at_least_once
         @scope.lookupvar("other::deep::klass::var").should == :undefined
       end
 
       it "should warn and return ':undefined' for qualified variables whose classes do not exist" do
-        @scope.expects(:warning)
+        Puppet.expects(:deprecation_warning).never
+        @scope.expects(:warning).at_least_once
         @scope.lookupvar("other::deep::klass::var").should == :undefined
       end
 
       it "should return ':undefined' when asked for a non-string qualified variable from a class that does not exist" do
+        Puppet.expects(:deprecation_warning).never
         @scope.stubs(:warning)
         @scope.lookupvar("other::deep::klass::var").should == :undefined
       end
 
       it "should return ':undefined' when asked for a non-string qualified variable from a class that has not been evaluated" do
+        Puppet.expects(:deprecation_warning).never
         @scope.stubs(:warning)
         klass = newclass("other::deep::klass")
         @scope.lookupvar("other::deep::klass::var").should == :undefined
diff --git a/spec/unit/resource/type_spec.rb b/spec/unit/resource/type_spec.rb
index 352f767..19f86e7 100755
--- a/spec/unit/resource/type_spec.rb
+++ b/spec/unit/resource/type_spec.rb
@@ -238,7 +238,7 @@ def double_convert
 
   describe "when setting its parameters in the scope" do
     before do
-      @scope = Puppet::Parser::Scope.new(:compiler => stub("compiler", :environment => Puppet::Node::Environment.new), :source => stub("source"))
+      @scope = Puppet::Parser::Scope.new(:compiler => Puppet::Parser::Compiler.new(Puppet::Node.new("foo")), :source => stub("source"))
       @resource = Puppet::Parser::Resource.new(:foo, "bar", :scope => @scope)
       @type = Puppet::Resource::Type.new(:hostclass, "foo")
     end
@@ -435,7 +435,7 @@ def double_convert
 
     it "should set all of its parameters in a subscope" do
       subscope = stub 'subscope', :compiler => @compiler
-      @scope.expects(:newscope).with(:source => @type, :dynamic => true, :namespace => 'foo', :resource => @resource).returns subscope
+      @scope.expects(:newscope).with(:source => @type, :namespace => 'foo', :resource => @resource).returns subscope
       @type.expects(:set_resource_parameters).with(@resource, subscope)
 
       @type.evaluate_code(@resource)

    

--
You received this message because you are subscribed to the Google Groups "Puppet Developers" group.
To post to this group, send email to puppet-dev@googlegroups.com.
To unsubscribe from this group, send email to puppet-dev+unsubscr...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/puppet-dev?hl=en.

Reply via email to