diff --git a/ext/build_defaults.yaml b/ext/build_defaults.yaml index 4c46aa9fa..d842b8a8a 100644 --- a/ext/build_defaults.yaml +++ b/ext/build_defaults.yaml @@ -1,23 +1,23 @@ --- packaging_url: 'git://github.com/puppetlabs/packaging.git --branch=master' packaging_repo: 'packaging' default_cow: 'base-squeeze-i386.cow' -cows: 'base-lucid-i386.cow base-natty-i386.cow base-oneiric-i386.cow base-precise-i386.cow base-sid-i386.cow base-squeeze-i386.cow base-stable-i386.cow base-testing-i386.cow base-unstable-i386.cow base-wheezy-i386.cow' +cows: 'base-lucid-i386.cow base-natty-i386.cow base-oneiric-i386.cow base-precise-i386.cow base-quantal-i386.cow base-sid-i386.cow base-squeeze-i386.cow base-stable-i386.cow base-testing-i386.cow base-unstable-i386.cow base-wheezy-i386.cow' pbuild_conf: '/etc/pbuilderrc' packager: 'puppetlabs' gpg_name: 'info@puppetlabs.com' gpg_key: '4BD6EC30' sign_tar: FALSE # a space separated list of mock configs final_mocks: 'pl-5-i386 pl-6-i386 fedora-15-i386 fedora-16-i386 fedora-17-i386' rc_mocks: 'pl-5-i386-dev pl-6-i386-dev fedora-15-i386-dev fedora-16-i386-dev fedora-17-i386-dev' yum_host: 'burji.puppetlabs.com' yum_repo_path: '/opt/repository/yum/' build_gem: TRUE build_dmg: TRUE apt_host: 'burji.puppetlabs.com' apt_repo_url: 'http://apt.puppetlabs.com' apt_repo_path: '/opt/repository/incoming' ips_repo: '/var/pkgrepo' ips_store: '/opt/repository' ips_host: 'solaris-11-ips-repo.acctest.dc1.puppetlabs.net' diff --git a/install.rb b/install.rb index 5753ff9db..7d8858fff 100755 --- a/install.rb +++ b/install.rb @@ -1,452 +1,452 @@ #! /usr/bin/env ruby #-- # Copyright 2004 Austin Ziegler # Install utility. Based on the original installation script for rdoc by the # Pragmatic Programmers. # # This program is free software. It may be redistributed and/or modified under # the terms of the GPL version 2 (or later) or the Ruby licence. # # Usage # ----- # In most cases, if you have a typical project layout, you will need to do # absolutely nothing to make this work for you. This layout is: # # bin/ # executable files -- "commands" # lib/ # the source of the library # tests/ # unit tests # # The default behaviour: # 1) Run all unit test files (ending in .rb) found in all directories under # tests/. # 2) Build Rdoc documentation from all files in bin/ (excluding .bat and .cmd), # all .rb files in lib/, ./README, ./ChangeLog, and ./Install. # 3) Build ri documentation from all files in bin/ (excluding .bat and .cmd), # and all .rb files in lib/. This is disabled by default on Microsoft Windows. # 4) Install commands from bin/ into the Ruby bin directory. On Windows, if a # if a corresponding batch file (.bat or .cmd) exists in the bin directory, # it will be copied over as well. Otherwise, a batch file (always .bat) will # be created to run the specified command. # 5) Install all library files ending in .rb from lib/ into Ruby's # site_lib/version directory. # #++ require 'rbconfig' require 'find' require 'fileutils' require 'tempfile' begin require 'ftools' # apparently on some system ftools doesn't get loaded $haveftools = true rescue LoadError puts "ftools not found. Using FileUtils instead.." $haveftools = false end require 'optparse' require 'ostruct' begin require 'rdoc/rdoc' $haverdoc = true rescue LoadError puts "Missing rdoc; skipping documentation" $haverdoc = false end PREREQS = %w{openssl facter cgi} MIN_FACTER_VERSION = 1.5 InstallOptions = OpenStruct.new def glob(list) g = list.map { |i| Dir.glob(i) } g.flatten! g.compact! g end # Set these values to what you want installed. configs = glob(%w{conf/auth.conf}) bins = glob(%w{bin/*}) rdoc = glob(%w{bin/* lib/**/*.rb README README-library CHANGELOG TODO Install}).reject { |e| e=~ /\.(bat|cmd)$/ } ri = glob(%w{bin/*.rb lib/**/*.rb}).reject { |e| e=~ /\.(bat|cmd)$/ } man = glob(%w{man/man[0-9]/*}) libs = glob(%w{lib/**/*.rb lib/**/*.erb lib/**/*.py lib/puppet/util/command_line/*}) tests = glob(%w{test/**/*.rb}) def do_configs(configs, target, strip = 'conf/') Dir.mkdir(target) unless File.directory? target configs.each do |cf| ocf = File.join(InstallOptions.config_dir, cf.gsub(/#{strip}/, '')) if $haveftools File.install(cf, ocf, 0644, true) else - FileUtils.install(cf, ocf, {:mode => 0644, :verbose => true}) + FileUtils.install(cf, ocf, {:mode => 0644, :preserve => true, :verbose => true}) end end if $operatingsystem == 'windows' src_dll = 'ext/windows/eventlog/puppetres.dll' dst_dll = File.join(InstallOptions.bin_dir, 'puppetres.dll') if $haveftools File.install(src_dll, dst_dll, 0644, true) else - FileUtils.install(src_dll, dst_dll, {:mode => 0644, :verbose => true}) + FileUtils.install(src_dll, dst_dll, {:mode => 0644, :preserve => true, :verbose => true}) end require 'win32/registry' include Win32::Registry::Constants begin Win32::Registry::HKEY_LOCAL_MACHINE.create('SYSTEM\CurrentControlSet\services\eventlog\Application\Puppet', KEY_ALL_ACCESS | 0x0100) do |reg| reg.write_s('EventMessageFile', dst_dll.tr('/', '\\')) reg.write_i('TypesSupported', 0x7) end rescue Win32::Registry::Error => e warn "Failed to create puppet eventlog registry key: #{e}" end end end def do_bins(bins, target, strip = 's?bin/') Dir.mkdir(target) unless File.directory? target bins.each do |bf| obf = bf.gsub(/#{strip}/, '') install_binfile(bf, obf, target) end end def do_libs(libs, strip = 'lib/') libs.each do |lf| olf = File.join(InstallOptions.site_dir, lf.gsub(/#{strip}/, '')) op = File.dirname(olf) if $haveftools File.makedirs(op, true) File.chmod(0755, op) File.install(lf, olf, 0644, true) else FileUtils.makedirs(op, {:mode => 0755, :verbose => true}) FileUtils.chmod(0755, op) - FileUtils.install(lf, olf, {:mode => 0644, :verbose => true}) + FileUtils.install(lf, olf, {:mode => 0644, :preserve => true, :verbose => true}) end end end def do_man(man, strip = 'man/') man.each do |mf| omf = File.join(InstallOptions.man_dir, mf.gsub(/#{strip}/, '')) om = File.dirname(omf) if $haveftools File.makedirs(om, true) File.chmod(0755, om) File.install(mf, omf, 0644, true) else FileUtils.makedirs(om, {:mode => 0755, :verbose => true}) FileUtils.chmod(0755, om) - FileUtils.install(mf, omf, {:mode => 0644, :verbose => true}) + FileUtils.install(mf, omf, {:mode => 0644, :preserve => true, :verbose => true}) end gzip = %x{which gzip} gzip.chomp! %x{#{gzip} -f #{omf}} end end # Verify that all of the prereqs are installed def check_prereqs PREREQS.each { |pre| begin require pre if pre == "facter" # to_f isn't quite exact for strings like "1.5.1" but is good # enough for this purpose. facter_version = Facter.version.to_f if facter_version < MIN_FACTER_VERSION puts "Facter version: #{facter_version}; minimum required: #{MIN_FACTER_VERSION}; cannot install" exit -1 end end rescue LoadError puts "Could not load #{pre}; cannot install" exit -1 end } end ## # Prepare the file installation. # def prepare_installation $operatingsystem = Facter["operatingsystem"].value InstallOptions.configs = true # Only try to do docs if we're sure they have rdoc if $haverdoc InstallOptions.rdoc = true InstallOptions.ri = $operatingsystem != "windows" else InstallOptions.rdoc = false InstallOptions.ri = false end InstallOptions.tests = true ARGV.options do |opts| opts.banner = "Usage: #{File.basename($0)} [options]" opts.separator "" opts.on('--[no-]rdoc', 'Prevents the creation of RDoc output.', 'Default on.') do |onrdoc| InstallOptions.rdoc = onrdoc end opts.on('--[no-]ri', 'Prevents the creation of RI output.', 'Default off on mswin32.') do |onri| InstallOptions.ri = onri end opts.on('--[no-]tests', 'Prevents the execution of unit tests.', 'Default on.') do |ontest| InstallOptions.tests = ontest end opts.on('--[no-]configs', 'Prevents the installation of config files', 'Default off.') do |ontest| InstallOptions.configs = ontest end opts.on('--destdir[=OPTIONAL]', 'Installation prefix for all targets', 'Default essentially /') do |destdir| InstallOptions.destdir = destdir end opts.on('--configdir[=OPTIONAL]', 'Installation directory for config files', 'Default /etc/puppet') do |configdir| InstallOptions.configdir = configdir end opts.on('--bindir[=OPTIONAL]', 'Installation directory for binaries', 'overrides RbConfig::CONFIG["bindir"]') do |bindir| InstallOptions.bindir = bindir end opts.on('--ruby[=OPTIONAL]', 'Ruby interpreter to use with installation', 'overrides ruby used to call install.rb') do |ruby| InstallOptions.ruby = ruby end opts.on('--sitelibdir[=OPTIONAL]', 'Installation directory for libraries', 'overrides RbConfig::CONFIG["sitelibdir"]') do |sitelibdir| InstallOptions.sitelibdir = sitelibdir end opts.on('--mandir[=OPTIONAL]', 'Installation directory for man pages', 'overrides RbConfig::CONFIG["mandir"]') do |mandir| InstallOptions.mandir = mandir end opts.on('--quick', 'Performs a quick installation. Only the', 'installation is done.') do |quick| InstallOptions.rdoc = false InstallOptions.ri = false InstallOptions.tests = false InstallOptions.configs = true end opts.on('--full', 'Performs a full installation. All', 'optional installation steps are run.') do |full| InstallOptions.rdoc = true InstallOptions.ri = true InstallOptions.tests = true InstallOptions.configs = true end opts.separator("") opts.on_tail('--help', "Shows this help text.") do $stderr.puts opts exit end opts.parse! end version = [RbConfig::CONFIG["MAJOR"], RbConfig::CONFIG["MINOR"]].join(".") libdir = File.join(RbConfig::CONFIG["libdir"], "ruby", version) # Mac OS X 10.5 and higher declare bindir # /System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/bin # which is not generally where people expect executables to be installed # These settings are appropriate defaults for all OS X versions. if RUBY_PLATFORM =~ /^universal-darwin[\d\.]+$/ RbConfig::CONFIG['bindir'] = "/usr/bin" end if not InstallOptions.configdir.nil? configdir = InstallOptions.configdir elsif $operatingsystem == "windows" begin require 'win32/dir' rescue LoadError => e puts "Cannot run on Microsoft Windows without the sys-admin, win32-process, win32-dir & win32-service gems: #{e}" exit -1 end configdir = File.join(Dir::COMMON_APPDATA, "PuppetLabs", "puppet", "etc") else configdir = "/etc/puppet" end if not InstallOptions.bindir.nil? bindir = InstallOptions.bindir else bindir = RbConfig::CONFIG['bindir'] end if not InstallOptions.sitelibdir.nil? sitelibdir = InstallOptions.sitelibdir else sitelibdir = RbConfig::CONFIG["sitelibdir"] if sitelibdir.nil? sitelibdir = $LOAD_PATH.find { |x| x =~ /site_ruby/ } if sitelibdir.nil? sitelibdir = File.join(libdir, "site_ruby") elsif sitelibdir !~ Regexp.quote(version) sitelibdir = File.join(sitelibdir, version) end end end if not InstallOptions.mandir.nil? mandir = InstallOptions.mandir else mandir = RbConfig::CONFIG['mandir'] end # This is the new way forward if not InstallOptions.destdir.nil? destdir = InstallOptions.destdir # To be deprecated once people move over to using --destdir option elsif not ENV['DESTDIR'].nil? destdir = ENV['DESTDIR'] warn "DESTDIR is deprecated. Use --destdir instead." else destdir = '' end configdir = join(destdir, configdir) bindir = join(destdir, bindir) mandir = join(destdir, mandir) sitelibdir = join(destdir, sitelibdir) FileUtils.makedirs(configdir) if InstallOptions.configs FileUtils.makedirs(bindir) FileUtils.makedirs(mandir) FileUtils.makedirs(sitelibdir) InstallOptions.site_dir = sitelibdir InstallOptions.config_dir = configdir InstallOptions.bin_dir = bindir InstallOptions.lib_dir = libdir InstallOptions.man_dir = mandir end ## # Join two paths. On Windows, dir must be converted to a relative path, # by stripping the drive letter, but only if the basedir is not empty. # def join(basedir, dir) return "#{basedir}#{dir[2..-1]}" if $operatingsystem == "windows" and basedir.length > 0 and dir.length > 2 "#{basedir}#{dir}" end ## # Build the rdoc documentation. Also, try to build the RI documentation. # def build_rdoc(files) return unless $haverdoc begin r = RDoc::RDoc.new r.document(["--main", "README", "--title", "Puppet -- Site Configuration Management", "--line-numbers"] + files) rescue RDoc::RDocError => e $stderr.puts e.message rescue Exception => e $stderr.puts "Couldn't build RDoc documentation\n#{e.message}" end end def build_ri(files) return unless $haverdoc begin ri = RDoc::RDoc.new #ri.document(["--ri-site", "--merge"] + files) ri.document(["--ri-site"] + files) rescue RDoc::RDocError => e $stderr.puts e.message rescue Exception => e $stderr.puts "Couldn't build Ri documentation\n#{e.message}" $stderr.puts "Continuing with install..." end end def run_tests(test_list) require 'test/unit/ui/console/testrunner' $LOAD_PATH.unshift "lib" test_list.each do |test| next if File.directory?(test) require test end tests = [] ObjectSpace.each_object { |o| tests << o if o.kind_of?(Class) } tests.delete_if { |o| !o.ancestors.include?(Test::Unit::TestCase) } tests.delete_if { |o| o == Test::Unit::TestCase } tests.each { |test| Test::Unit::UI::Console::TestRunner.run(test) } $LOAD_PATH.shift rescue LoadError puts "Missing testrunner library; skipping tests" end ## # Install file(s) from ./bin to RbConfig::CONFIG['bindir']. Patch it on the way # to insert a #! line; on a Unix install, the command is named as expected # (e.g., bin/rdoc becomes rdoc); the shebang line handles running it. Under # windows, we add an '.rb' extension and let file associations do their stuff. def install_binfile(from, op_file, target) tmp_file = Tempfile.new('puppet-binfile') if not InstallOptions.ruby.nil? ruby = InstallOptions.ruby else ruby = File.join(RbConfig::CONFIG['bindir'], RbConfig::CONFIG['ruby_install_name']) end File.open(from) do |ip| File.open(tmp_file.path, "w") do |op| op.puts "#!#{ruby}" contents = ip.readlines contents.shift if contents[0] =~ /^#!/ op.write contents.join end end if $operatingsystem == "windows" installed_wrapper = false if File.exists?("#{from}.bat") - FileUtils.install("#{from}.bat", File.join(target, "#{op_file}.bat"), :mode => 0755, :verbose => true) + FileUtils.install("#{from}.bat", File.join(target, "#{op_file}.bat"), :mode => 0755, :preserve => true, :verbose => true) installed_wrapper = true end if File.exists?("#{from}.cmd") - FileUtils.install("#{from}.cmd", File.join(target, "#{op_file}.cmd"), :mode => 0755, :verbose => true) + FileUtils.install("#{from}.cmd", File.join(target, "#{op_file}.cmd"), :mode => 0755, :preserve => true, :verbose => true) installed_wrapper = true end if not installed_wrapper tmp_file2 = Tempfile.new('puppet-wrapper') cwv = <<-EOS @echo off setlocal set RUBY_BIN=%~dp0 set RUBY_BIN=%RUBY_BIN:\\=/% "%RUBY_BIN%ruby.exe" -x "%RUBY_BIN%puppet" %* EOS File.open(tmp_file2.path, "w") { |cw| cw.puts cwv } - FileUtils.install(tmp_file2.path, File.join(target, "#{op_file}.bat"), :mode => 0755, :verbose => true) + FileUtils.install(tmp_file2.path, File.join(target, "#{op_file}.bat"), :mode => 0755, :preserve => true, :verbose => true) tmp_file2.unlink installed_wrapper = true end end - FileUtils.install(tmp_file.path, File.join(target, op_file), :mode => 0755, :verbose => true) + FileUtils.install(tmp_file.path, File.join(target, op_file), :mode => 0755, :preserve => true, :verbose => true) tmp_file.unlink end check_prereqs prepare_installation #run_tests(tests) if InstallOptions.tests #build_rdoc(rdoc) if InstallOptions.rdoc #build_ri(ri) if InstallOptions.ri do_configs(configs, InstallOptions.config_dir) if InstallOptions.configs do_bins(bins, InstallOptions.bin_dir) do_libs(libs) do_man(man) unless $operatingsystem == "windows" diff --git a/lib/puppet/parser/relationship.rb b/lib/puppet/parser/relationship.rb index 92ba4071a..ac525fcbe 100644 --- a/lib/puppet/parser/relationship.rb +++ b/lib/puppet/parser/relationship.rb @@ -1,60 +1,62 @@ class Puppet::Parser::Relationship attr_accessor :source, :target, :type PARAM_MAP = {:relationship => :before, :subscription => :notify} def arrayify(resources) case resources when Puppet::Parser::Collector resources.collected.values when Array resources else [resources] end end def evaluate(catalog) arrayify(source).each do |s| arrayify(target).each do |t| mk_relationship(s, t, catalog) end end end def initialize(source, target, type) @source, @target, @type = source, target, type end def param_name PARAM_MAP[type] || raise(ArgumentError, "Invalid relationship type #{type}") end def mk_relationship(source, target, catalog) # REVISIT: In Ruby 1.8 we applied `to_s` to source and target, rather than # `join` without an argument. In 1.9 the behaviour of Array#to_s changed, # and it gives a different representation than just concat the stringified # elements. # # This restores the behaviour, but doesn't address the underlying question # of what would happen when more than one item was passed in that array. # (Hint: this will not end well.) # # See http://projects.puppetlabs.com/issues/12076 for the ticket tracking # the fact that we should dig out the sane version of this behaviour, then # implement it - where we don't risk breaking a stable release series. # --daniel 2012-01-21 source = source.is_a?(Array) ? source.join : source.to_s target = target.is_a?(Array) ? target.join : target.to_s unless source_resource = catalog.resource(source) raise ArgumentError, "Could not find resource '#{source}' for relationship on '#{target}'" end unless target_resource = catalog.resource(target) raise ArgumentError, "Could not find resource '#{target}' for relationship from '#{source}'" end Puppet.debug "Adding relationship from #{source} to #{target} with '#{param_name}'" - source_resource[param_name] ||= [] + if source_resource[param_name].class != Array + source_resource[param_name] = [source_resource[param_name]].compact + end source_resource[param_name] << target end end diff --git a/spec/unit/parser/relationship_spec.rb b/spec/unit/parser/relationship_spec.rb index 51888805d..aaf229198 100755 --- a/spec/unit/parser/relationship_spec.rb +++ b/spec/unit/parser/relationship_spec.rb @@ -1,69 +1,93 @@ #! /usr/bin/env ruby require 'spec_helper' require 'puppet/parser/relationship' describe Puppet::Parser::Relationship do before do @source = Puppet::Resource.new(:mytype, "source") @target = Puppet::Resource.new(:mytype, "target") + @extra_resource = Puppet::Resource.new(:mytype, "extra") + @extra_resource2 = Puppet::Resource.new(:mytype, "extra2") @dep = Puppet::Parser::Relationship.new(@source, @target, :relationship) end describe "when evaluating" do before do @catalog = Puppet::Resource::Catalog.new @catalog.add_resource(@source) @catalog.add_resource(@target) + @catalog.add_resource(@extra_resource) + @catalog.add_resource(@extra_resource2) end it "should fail if the source resource cannot be found" do @catalog = Puppet::Resource::Catalog.new @catalog.add_resource @target lambda { @dep.evaluate(@catalog) }.should raise_error(ArgumentError) end it "should fail if the target resource cannot be found" do @catalog = Puppet::Resource::Catalog.new @catalog.add_resource @source lambda { @dep.evaluate(@catalog) }.should raise_error(ArgumentError) end it "should add the target as a 'before' value if the type is 'relationship'" do @dep.type = :relationship @dep.evaluate(@catalog) @source[:before].should be_include("Mytype[target]") end it "should add the target as a 'notify' value if the type is 'subscription'" do @dep.type = :subscription @dep.evaluate(@catalog) @source[:notify].should be_include("Mytype[target]") end it "should supplement rather than clobber existing relationship values" do @source[:before] = "File[/bar]" @dep.evaluate(@catalog) + # this test did not work before. It was appending the resources + # together as a string + (@source[:before].class == Array).should be_true @source[:before].should be_include("Mytype[target]") @source[:before].should be_include("File[/bar]") end + it "should supplement rather than clobber existing resource relationships" do + @source[:before] = @extra_resource + @dep.evaluate(@catalog) + (@source[:before].class == Array).should be_true + @source[:before].should be_include("Mytype[target]") + @source[:before].should be_include(@extra_resource) + end + + it "should supplement rather than clobber multiple existing resource relationships" do + @source[:before] = [@extra_resource, @extra_resource2] + @dep.evaluate(@catalog) + (@source[:before].class == Array).should be_true + @source[:before].should be_include("Mytype[target]") + @source[:before].should be_include(@extra_resource) + @source[:before].should be_include(@extra_resource2) + end + it "should use the collected retargets if the target is a Collector" do orig_target = @target @target = Puppet::Parser::Collector.new(stub("scope"), :file, "equery", "vquery", :virtual) @target.collected[:foo] = @target @dep.evaluate(@catalog) @source[:before].should be_include("Mytype[target]") end it "should use the collected resources if the source is a Collector" do orig_source = @source @source = Puppet::Parser::Collector.new(stub("scope"), :file, "equery", "vquery", :virtual) @source.collected[:foo] = @source @dep.evaluate(@catalog) orig_source[:before].should be_include("Mytype[target]") end end end diff --git a/tasks/rake/gem.rake b/tasks/rake/gem.rake new file mode 100644 index 000000000..c59864bb7 --- /dev/null +++ b/tasks/rake/gem.rake @@ -0,0 +1,62 @@ +require 'fileutils' +require 'puppet/version' + +GEM_FILES = FileList[ + '[A-Z]*', + 'install.rb', + 'bin/**/*', + 'lib/**/*', + 'conf/**/*', + 'man/**/*', + 'examples/**/*', + 'ext/**/*', + 'tasks/**/*', + 'test/**/*', + 'spec/**/*' +] + +EXECUTABLES = FileList[ + 'bin/**/*', + 'sbin/**/*' +] + +SBIN = Dir.glob("sbin/*") +GEMVERSION = Puppet.version.gsub('-','.') + +spec = Gem::Specification.new do |spec| + spec.platform = Gem::Platform::RUBY + spec.name = 'puppet' + spec.files = GEM_FILES.to_a + spec.executables = EXECUTABLES.gsub(/sbin\/|bin\//, '').to_a + spec.version = GEMVERSION + spec.add_dependency('facter', '~> 1.5') + spec.summary = 'Puppet, an automated configuration management tool' + spec.description = 'Puppet, an automated configuration management tool' + spec.author = 'Puppet Labs' + spec.email = 'puppet@puppetlabs.com' + spec.homepage = 'http://puppetlabs.com' + spec.rubyforge_project = 'puppet' + spec.has_rdoc = true + spec.rdoc_options << + '--title' << 'Puppet - Configuration Management' << + '--main' << 'README' << + '--line-numbers' +end + +desc "Prepare binaries for gem creation" +task :prepare_gem do + SBIN.each do |f| + FileUtils.copy(f,"bin") + end +end + +desc "Create the gem" +task :create_gem => :prepare_gem do + Dir.mkdir("pkg") rescue nil + Gem::Builder.new(spec).build + FileUtils.move("puppet-#{GEMVERSION}.gem", "pkg") + SBIN.each do |f| + fn = f.gsub(/sbin\/(.*)/, '\1') + FileUtils.rm_r "bin/" + fn + end +end