(continued) diff --git a/lib/puppet/type/file/checksum.rb > b/lib/puppet/type/file/checksum.rb > index 5af943e..5b99bef 100755 > --- a/lib/puppet/type/file/checksum.rb > +++ b/lib/puppet/type/file/checksum.rb > @@ -23,4 +23,11 @@ Puppet::Type.type(:file).newparam(:checksum) do > method = type.to_s + "_file" > "{#{type}}" + send(method, path).to_s > end > + > + def sum_stream(&block) > + type = value || :md5 # same comment as above > + method = type.to_s + "_stream" > + checksum = send(method, &block) > + "{#{type}}#{checksum}" > + end > end > diff --git a/lib/puppet/type/file/content.rb > b/lib/puppet/type/file/content.rb > index b6c671b..3789900 100755 > --- a/lib/puppet/type/file/content.rb > +++ b/lib/puppet/type/file/content.rb > @@ -1,9 +1,14 @@ > +require 'net/http' > +require 'uri' > + > require 'puppet/util/checksums' > +require 'puppet/network/http/api/v1' > > module Puppet > Puppet::Type.type(:file).newproperty(:content) do > include Puppet::Util::Diff > include Puppet::Util::Checksums > + include Puppet::Network::HTTP::API::V1 > > desc "Specify the contents of a file as a string. Newlines, tabs, > and > spaces can be specified using the escaped syntax (e.g., \\n for > a > @@ -68,21 +73,22 @@ module Puppet > end > end > > - # If content was specified, return that; else try to return the > source content; > + # If content was specified, return that; > # else, return nil. > def actual_content > if defined?(@actual_content) and @actual_content > return @actual_content > end > > - if s = resource.parameter(:source) > - return s.content > - end > - fail "Could not find actual content from checksum" > + return nil > + end > + >
:-) So that would be: def actual_content @actual_content end or even attr_reader :actual_content > + def length > + (actual_content and actual_content.length) || 0 > end > > def content > - self.should || (s = resource.parameter(:source) and s.content) > + self.should > end > > # Override this method to provide diffs if asked for. > @@ -140,9 +146,62 @@ module Puppet > # We're safe not testing for the 'source' if there's no > 'should' > # because we wouldn't have gotten this far if there weren't at > least > # one valid value somewhere. > - @resource.write(actual_content, :content) > + @resource.write(:content) > > return return_event > end > + > + def write(file) > + return write_content(file) if actual_content > + return write_source(file) if resource.parameter(:source) > + self.fail "Writing content that wasn't provided" > + end > + > + def write_content(file) > + file.print actual_content > + return resource.parameter(:checksum).sum(actual_content) > + end > + > + def write_source(file) > + if source = resource.parameter(:source) > + return write_local_source(file, source) if source.local? > + return write_remote_source(file, source) > + end > + end > + > + def write_local_source(file, source) > + resource.parameter(:checksum).sum_stream do |sum| > + File.open(source.full_path, "r") do |src| > + puts "local open" > I assume the puts should be removed? > + while chunk = src.read(8192) > + sum << chunk > + file.print chunk > + end > + end > + end > + end > + > + def write_remote_source(file, source) > + request = Puppet::Indirector::Request.new(:file_content, > :find, source.full_path) > + checksum = nil > + Puppet::Network::HttpPool.http_instance(source.server, > source.port).request_get(indirection2uri(request), {"Accept" => "raw"}) do > |response| > + case response.code > + when "404" > + return nil > + when /^2/ > + checksum = resource.parameter(:checksum).sum_stream do > |sum| > + response.read_body do |chunk| > + sum << chunk > + file.print chunk > + end > + end > + else > + # Raise the http error if we didn't get a 'success' of > some kind. > + message = "Error %s on SERVER: %s" % [response.code, > (response.body||'').empty? ? response.message : response.body] > + raise Net::HTTPError.new(message, response) > + end > + end > + return checksum > + end > end > end > Hmmm. More thinking than recommending, but what about something like: def write_source(file) resource.parameter(:checksum).sum_stream { |sum| each_chunk_from(file,resource.parameter(:source) { |chunk| sum << chunk file.print chunk } } end def each_chunk_from(file,source) if source.nil? nil elsif source.local? File.open(source.full_path, "r") do |src| while chunk = src.read(8192) yield chunk end end else request = Puppet::Indirector::Request.new(:file_content, :find, source.full_path) connection = Puppet::Network::HttpPool.http_instance(source.server, source.port). connection.request_get(indirection2uri(request), {"Accept" => "raw"}) do |response| case response.code when "404"; nil when /^2/; response.read_body { |chunk| yield chunk } else # Raise the http error if we didn't get a 'success' of some kind. message = "Error %s on SERVER: %s" % [response.code, (response.body||'').empty? ? response.message : response.body] raise Net::HTTPError.new(message, response) end } end end In other words, rather than pushing the checksuming and writing into the walk the stream code, keep it at the write_source level and push the local/remote choice down instead? If this direction is good, it looks like we could go even further and unify write_source and write_content, by adding the content logic at the head of each_chunk_from. > diff --git a/lib/puppet/type/file/ensure.rb > b/lib/puppet/type/file/ensure.rb > index 5f0beee..b8a85f6 100755 > --- a/lib/puppet/type/file/ensure.rb > +++ b/lib/puppet/type/file/ensure.rb > @@ -45,7 +45,7 @@ module Puppet > if property = @resource.property(:content) > property.sync > else > - @resource.write("", :ensure) > + @resource.write(:ensure) > mode = @resource.should(:mode) > end > return :file_created > diff --git a/lib/puppet/type/file/source.rb > b/lib/puppet/type/file/source.rb > index 838dabb..5b86e82 100755 > --- a/lib/puppet/type/file/source.rb > +++ b/lib/puppet/type/file/source.rb > @@ -96,16 +96,6 @@ module Puppet > metadata && metadata.checksum > end > > - # Look up (if necessary) and return remote content. > - cached_attr(:content) do > - raise Puppet::DevError, "No source for content was stored with > the metadata" unless metadata.source > - > - unless tmp = > Puppet::FileServing::Content.find(metadata.source) > - fail "Could not find any content at %s" % metadata.source > - end > - tmp.content > - end > - > # Copy the values from the source to the resource. Yay. > def copy_source_values > devfail "Somehow got asked to copy source values without any > metadata" unless metadata > @@ -171,5 +161,32 @@ module Puppet > resource[:check] = checks > resource[:checksum] = :md5 unless resource.property(:checksum) > end > + > + def local? > + if found? and uri > + return uri.scheme == "file" || uri.scheme == nil > + end > + false > + end > How about this (reading "||" as "defaults to"): def local? found? and uri and (uri.scheme || "file") == "file" end > + def full_path > + if found? and uri > + return URI.unescape(uri.path) > + end > + end > + > + def server > + (uri and uri.host) or Puppet.settings[:server] > + end > + > + def port > + (uri and uri.port) or Puppet.settings[:masterport] > + end > + > + private > + > + def uri > + @uri ||= URI.parse(URI.escape(metadata.source)) > + end > end > end > diff --git a/lib/puppet/util/checksums.rb b/lib/puppet/util/checksums.rb > index b0dcf80..a7aeaea 100644 > --- a/lib/puppet/util/checksums.rb > +++ b/lib/puppet/util/checksums.rb > @@ -39,11 +39,27 @@ module Puppet::Util::Checksums > md5_file(filename, true) > end > > + def md5_stream(&block) > + require 'digest/md5' > + digest = Digest::MD5.new() > + yield digest > + return digest.hexdigest > + end > + > + alias :md5lite_stream :md5_stream > + > # Return the :mtime timestamp of a file. > def mtime_file(filename) > File.stat(filename).send(:mtime) > end > > + # by definition this doesn't exist > + def mtime_stream > + nil > + end > + > + alias :ctime_stream :mtime_stream > + > # Calculate a checksum using Digest::SHA1. > def sha1(content) > require 'digest/sha1' > @@ -68,6 +84,15 @@ module Puppet::Util::Checksums > sha1_file(filename, true) > end > > + def sha1_stream > + require 'digest/sha1' > + digest = Digest::SHA1.new() > + yield digest > + return digest.hexdigest > + end > + > + alias :sha1lite_stream :sha1_stream > + > # Return the :ctime of a file. > def ctime_file(filename) > File.stat(filename).send(:ctime) > Final thought: I think this has the most thorough test set of any commit I've seen this year. -- Makus -- You received this message because you are subscribed to the Google Groups "Puppet Developers" group. To post to this group, send email to puppet-...@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.