From 6981ee5f526e00f46f6b5460662bf09cddf832ef Mon Sep 17 00:00:00 2001 From: Jesse Wolfe Date: Wed, 20 Apr 2011 15:41:52 -0700 Subject: Maint: Fix a #4655 introduced log inconsistency When we moved code from the compiler to parser/resource, we lost a conditional that prevented defined resources from gaining containment edges to stages. Adding a stage to a defined resource was usually harmless, but it violated the invariant of "resources should only have exactly one container as their direct parent", producing a 50% chance of a malformed containment path in log messages. Reviewed-By: Jacob Helwig --- lib/puppet/parser/resource.rb | 2 ++ 1 file changed, 2 insertions(+) (limited to 'lib') diff --git a/lib/puppet/parser/resource.rb b/lib/puppet/parser/resource.rb index cd0e8c742..3bb5f8601 100644 --- a/lib/puppet/parser/resource.rb +++ b/lib/puppet/parser/resource.rb @@ -66,6 +66,8 @@ class Puppet::Parser::Resource < Puppet::Resource # is drawn from the class to the stage. The stage for containment # defaults to main, if none is specified. def add_edge_to_stage + return unless self.type.to_s.downcase == "class" + unless stage = catalog.resource(:stage, self[:stage] || (scope && scope.resource && scope.resource[:stage]) || :main) raise ArgumentError, "Could not find stage #{self[:stage] || :main} specified by #{self}" end -- cgit From ac0581f16ca17962a23c244424d83dbd6e721479 Mon Sep 17 00:00:00 2001 From: Max Martin Date: Wed, 27 Apr 2011 13:09:30 -0700 Subject: (#7101) Fix template error messages in Ruby 1.8.5 lib/puppet/parser/templatewrapper.rb#script_line was calling .first on a String object, which in Ruby > 1.8.5 will return the entire string, but in 1.8.5 will cause an exception. This change (proposed by Markus Roberts) removes the call to .first and adds a condition for when the template error involves the file not being found. Reviewed-by: Jesse Wolfe --- lib/puppet/parser/templatewrapper.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/puppet/parser/templatewrapper.rb b/lib/puppet/parser/templatewrapper.rb index 180a03dc9..27d75bf92 100644 --- a/lib/puppet/parser/templatewrapper.rb +++ b/lib/puppet/parser/templatewrapper.rb @@ -20,7 +20,7 @@ class Puppet::Parser::TemplateWrapper def script_line # find which line in the template (if any) we were called from - caller.find { |l| l =~ /#{file}:/ }.first[/:(\d+):/,1] + (caller.find { |l| l =~ /#{file}:/ }||"")[/:(\d+):/,1] end # Should return true if a variable is defined, false if it is not -- cgit From 1695daca385bb0aef16cdb6aa840ca16a8823b11 Mon Sep 17 00:00:00 2001 From: nfagerlund Date: Wed, 11 May 2011 13:49:24 -0700 Subject: (#7264) Docs: Clarify that subscribe/notify imply require/before This is a doc string only commit. The metaparameter reference was not clear about subscribe and notify being supersets of require and before, respectively. This commit also cleans up some unrelated quoting, arrow-alignment, and language flow issues. --- lib/puppet/type.rb | 84 ++++++++++++++++++++++++++++-------------------------- 1 file changed, 44 insertions(+), 40 deletions(-) (limited to 'lib') diff --git a/lib/puppet/type.rb b/lib/puppet/type.rb index 656b8f264..1dbf12451 100644 --- a/lib/puppet/type.rb +++ b/lib/puppet/type.rb @@ -957,13 +957,13 @@ class Type schedule object, and then reference the name of that object to use that for your schedule: - schedule { daily: + schedule { 'daily': period => daily, - range => \"2-4\" + range => \"2-4\" } exec { \"/usr/bin/apt-get update\": - schedule => daily + schedule => 'daily' } The creation of the schedule object does not need to appear in the @@ -1055,9 +1055,9 @@ class Type newmetaparam(:alias) do desc "Creates an alias for the object. Puppet uses this internally when you - provide a symbolic name: + provide a symbolic title: - file { sshdconfig: + file { 'sshdconfig': path => $operatingsystem ? { solaris => \"/usr/local/etc/ssh/sshd_config\", default => \"/etc/ssh/sshd_config\" @@ -1065,30 +1065,30 @@ class Type source => \"...\" } - service { sshd: - subscribe => File[sshdconfig] + service { 'sshd': + subscribe => File['sshdconfig'] } - When you use this feature, the parser sets `sshdconfig` as the name, + When you use this feature, the parser sets `sshdconfig` as the title, and the library sets that as an alias for the file so the dependency - lookup for `sshd` works. You can use this parameter yourself, + lookup in `Service['sshd']` works. You can use this metaparameter yourself, but note that only the library can use these aliases; for instance, the following code will not work: file { \"/etc/ssh/sshd_config\": owner => root, group => root, - alias => sshdconfig + alias => 'sshdconfig' } - file { sshdconfig: + file { 'sshdconfig': mode => 644 } There's no way here for the Puppet parser to know that these two stanzas should be affecting the same file. - See the [Language Tutorial](http://docs.puppetlabs.com/guides/language_tutorial.html) for more information. + See the [Language Guide](http://docs.puppetlabs.com/guides/language_guide.html) for more information. " @@ -1222,7 +1222,7 @@ class Type # solution, but it works. newmetaparam(:require, :parent => RelationshipMetaparam, :attributes => {:direction => :in, :events => :NONE}) do - desc "One or more objects that this object depends on. + desc "References to one or more objects that this object depends on. This is used purely for guaranteeing that changes to required objects happen before the dependent object. For instance: @@ -1232,8 +1232,8 @@ class Type } file { \"/usr/local/scripts/myscript\": - source => \"puppet://server/module/myscript\", - mode => 755, + source => \"puppet://server/module/myscript\", + mode => 755, require => File[\"/usr/local/scripts\"] } @@ -1247,7 +1247,7 @@ class Type ways to autorequire objects, so if you think Puppet could be smarter here, let us know. - In fact, the above code was redundant -- Puppet will autorequire + In fact, the above code was redundant --- Puppet will autorequire any parent directories that are being managed; it will automatically realize that the parent directory should be created before the script is pulled down. @@ -1263,40 +1263,41 @@ class Type end newmetaparam(:subscribe, :parent => RelationshipMetaparam, :attributes => {:direction => :in, :events => :ALL_EVENTS, :callback => :refresh}) do - desc "One or more objects that this object depends on. Changes in the - subscribed to objects result in the dependent objects being - refreshed (e.g., a service will get restarted). For instance: + desc "References to one or more objects that this object depends on. This + metaparameter creates a dependency relationship like **require,** + and also causes the dependent object to be refreshed when the + subscribed object is changed. For instance: class nagios { - file { \"/etc/nagios/nagios.conf\": + file { 'nagconf': + path => \"/etc/nagios/nagios.conf\" source => \"puppet://server/module/nagios.conf\", - alias => nagconf # just to make things easier for me } - service { nagios: - ensure => running, - subscribe => File[nagconf] + service { 'nagios': + ensure => running, + subscribe => File['nagconf'] } } - Currently the `exec`, `mount` and `service` type support + Currently the `exec`, `mount` and `service` types support refreshing. " end newmetaparam(:before, :parent => RelationshipMetaparam, :attributes => {:direction => :out, :events => :NONE}) do - desc %{This parameter is the opposite of **require** -- it guarantees - that the specified object is applied later than the specifying - object: + desc %{References to one or more objects that depend on this object. This + parameter is the opposite of **require** --- it guarantees that + the specified object is applied later than the specifying object: file { "/var/nagios/configuration": source => "...", recurse => true, - before => Exec["nagios-rebuid"] + before => Exec["nagios-rebuid"] } exec { "nagios-rebuild": command => "/usr/bin/make", - cwd => "/var/nagios/configuration" + cwd => "/var/nagios/configuration" } This will make sure all of the files are up to date before the @@ -1304,15 +1305,18 @@ class Type end newmetaparam(:notify, :parent => RelationshipMetaparam, :attributes => {:direction => :out, :events => :ALL_EVENTS, :callback => :refresh}) do - desc %{This parameter is the opposite of **subscribe** -- it sends events - to the specified object: + desc %{References to one or more objects that depend on this object. This + parameter is the opposite of **subscribe** --- it creates a + dependency relationship like **before,** and also causes the + dependent object(s) to be refreshed when this object is changed. For + instance: file { "/etc/sshd_config": source => "....", - notify => Service[sshd] + notify => Service['sshd'] } - service { sshd: + service { 'sshd': ensure => running } @@ -1328,24 +1332,24 @@ class Type By default, all classes get directly added to the 'main' stage. You can create new stages as resources: - stage { [pre, post]: } + stage { ['pre', 'post']: } To order stages, use standard relationships: - stage { pre: before => Stage[main] } + stage { 'pre': before => Stage['main'] } Or use the new relationship syntax: - Stage[pre] -> Stage[main] -> Stage[post] + Stage['pre'] -> Stage['main'] -> Stage['post'] Then use the new class parameters to specify a stage: - class { foo: stage => pre } + class { 'foo': stage => 'pre' } Stages can only be set on classes, not individual resources. This will fail: - file { '/foo': stage => pre, ensure => file } + file { '/foo': stage => 'pre', ensure => file } } end @@ -1478,7 +1482,7 @@ class Type newparam(:provider) do desc "The specific backend for #{self.name.to_s} to use. You will - seldom need to specify this -- Puppet will usually discover the + seldom need to specify this --- Puppet will usually discover the appropriate provider for your platform." # This is so we can refer back to the type to get a list of -- cgit From 81d566f216468c69d5c2e592afb66fe834261aa7 Mon Sep 17 00:00:00 2001 From: James Turnbull Date: Wed, 11 May 2011 10:03:36 +1000 Subject: Fixed #7481 - Added MIT license to Thomas Bellman's function code --- lib/puppet/parser/functions/regsubst.rb | 26 ++++++++++++++++++++++++++ lib/puppet/parser/functions/shellquote.rb | 26 ++++++++++++++++++++++++++ lib/puppet/parser/functions/sprintf.rb | 26 ++++++++++++++++++++++++++ 3 files changed, 78 insertions(+) (limited to 'lib') diff --git a/lib/puppet/parser/functions/regsubst.rb b/lib/puppet/parser/functions/regsubst.rb index b6bb5afcf..397d2b2ee 100644 --- a/lib/puppet/parser/functions/regsubst.rb +++ b/lib/puppet/parser/functions/regsubst.rb @@ -1,3 +1,29 @@ +# Copyright (C) 2009 Thomas Bellman +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be +# included in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +# IN NO EVENT SHALL THOMAS BELLMAN BE LIABLE FOR ANY CLAIM, DAMAGES OR +# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +# OTHER DEALINGS IN THE SOFTWARE. +# +# Except as contained in this notice, the name of Thomas Bellman shall +# not be used in advertising or otherwise to promote the sale, use or +# other dealings in this Software without prior written authorization +# from Thomas Bellman. + module Puppet::Parser::Functions newfunction( diff --git a/lib/puppet/parser/functions/shellquote.rb b/lib/puppet/parser/functions/shellquote.rb index 3ddb988f2..ee070c740 100644 --- a/lib/puppet/parser/functions/shellquote.rb +++ b/lib/puppet/parser/functions/shellquote.rb @@ -1,3 +1,29 @@ +# Copyright (C) 2009 Thomas Bellman +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be +# included in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +# IN NO EVENT SHALL THOMAS BELLMAN BE LIABLE FOR ANY CLAIM, DAMAGES OR +# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +# OTHER DEALINGS IN THE SOFTWARE. +# +# Except as contained in this notice, the name of Thomas Bellman shall +# not be used in advertising or otherwise to promote the sale, use or +# other dealings in this Software without prior written authorization +# from Thomas Bellman. + module Puppet::Parser::Functions Safe = 'a-zA-Z0-9@%_+=:,./-' # Safe unquoted diff --git a/lib/puppet/parser/functions/sprintf.rb b/lib/puppet/parser/functions/sprintf.rb index 5eb4a4f9d..118020412 100644 --- a/lib/puppet/parser/functions/sprintf.rb +++ b/lib/puppet/parser/functions/sprintf.rb @@ -1,3 +1,29 @@ +# Copyright (C) 2009 Thomas Bellman +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be +# included in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +# IN NO EVENT SHALL THOMAS BELLMAN BE LIABLE FOR ANY CLAIM, DAMAGES OR +# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +# OTHER DEALINGS IN THE SOFTWARE. +# +# Except as contained in this notice, the name of Thomas Bellman shall +# not be used in advertising or otherwise to promote the sale, use or +# other dealings in this Software without prior written authorization +# from Thomas Bellman. + module Puppet::Parser::Functions newfunction( -- cgit From 6bb2a85a2d1bfdf0fd3fb09339c4b98c627610bf Mon Sep 17 00:00:00 2001 From: Paul Boyd Date: Wed, 11 May 2011 21:21:38 -0400 Subject: (#1853) Pacman package provider Adds support for use Archlinux's pacman package manager in Puppet. Originally written by Miah Johnson, with bug fixes from Thomas Hatch and myself. --- lib/puppet/provider/package/pacman.rb | 94 +++++++++++++++++++++++++++++++++++ 1 file changed, 94 insertions(+) create mode 100644 lib/puppet/provider/package/pacman.rb (limited to 'lib') diff --git a/lib/puppet/provider/package/pacman.rb b/lib/puppet/provider/package/pacman.rb new file mode 100644 index 000000000..6eb7dbe3d --- /dev/null +++ b/lib/puppet/provider/package/pacman.rb @@ -0,0 +1,94 @@ +require 'puppet/provider/package' + +Puppet::Type.type(:package).provide :pacman, :parent => Puppet::Provider::Package do + desc "Support for the Package Manager Utility (pacman) used in Archlinux." + + commands :pacman => "/usr/bin/pacman" + defaultfor :operatingsystem => :archlinux + confine :operatingsystem => :archlinux + has_feature :upgradeable + + # Install a package using 'pacman'. + # Installs quietly, without confirmation or progressbar, updates package + # list from servers defined in pacman.conf. + def install + pacman "--noconfirm", "--noprogressbar", "-Sy", @resource[:name] + + unless self.query + raise Puppet::ExecutionFailure.new("Could not find package %s" % self.name) + end + end + + def self.listcmd + [command(:pacman), " -Q"] + end + + # Fetch the list of packages currently installed on the system. + def self.instances + packages = [] + begin + execpipe(listcmd()) do |process| + # pacman -Q output is 'packagename version-rel' + regex = %r{^(\S+)\s(\S+)} + fields = [:name, :ensure] + hash = {} + + process.each { |line| + if match = regex.match(line) + fields.zip(match.captures) { |field,value| + hash[field] = value + } + + name = hash[:name] + hash[:provider] = self.name + + packages << new(hash) + hash = {} + else + warning("Failed to match line %s" % line) + end + } + end + rescue Puppet::ExecutionFailure + return nil + end + packages + end + + # Because Archlinux is a rolling release based distro, installing a package + # should always result in the newest release. + def update + # Install in pacman can be used for update, too + self.install + end + + def latest + pacman "-Sy" + output = pacman "-Sp", "--print-format", "%v", @resource[:name] + output.chomp + end + + # Querys the pacman master list for information about the package. + def query + begin + output = pacman("-Qi", @resource[:name]) + + if output =~ /Version.*:\s(.+)/ + return { :ensure => $1 } + end + rescue Puppet::ExecutionFailure + return { + :ensure => :purged, + :status => 'missing', + :name => @resource[:name], + :error => 'ok', + } + end + nil + end + + # Removes a package from the system. + def uninstall + pacman "--noconfirm", "--noprogressbar", "-R", @resource[:name] + end +end -- cgit From 8f0cecfb46aface34d5189e60e924c9bfa7f4b13 Mon Sep 17 00:00:00 2001 From: James Turnbull Date: Mon, 23 May 2011 06:19:28 +1000 Subject: Added the vcsrepo type and providers to the core --- lib/puppet/provider/vcsrepo.rb | 34 +++++ lib/puppet/provider/vcsrepo/bzr.rb | 64 +++++++++ lib/puppet/provider/vcsrepo/cvs.rb | 80 +++++++++++ lib/puppet/provider/vcsrepo/git.rb | 264 +++++++++++++++++++++++++++++++++++++ lib/puppet/provider/vcsrepo/hg.rb | 101 ++++++++++++++ lib/puppet/provider/vcsrepo/svn.rb | 82 ++++++++++++ lib/puppet/type/vcsrepo.rb | 138 +++++++++++++++++++ 7 files changed, 763 insertions(+) create mode 100644 lib/puppet/provider/vcsrepo.rb create mode 100644 lib/puppet/provider/vcsrepo/bzr.rb create mode 100644 lib/puppet/provider/vcsrepo/cvs.rb create mode 100644 lib/puppet/provider/vcsrepo/git.rb create mode 100644 lib/puppet/provider/vcsrepo/hg.rb create mode 100644 lib/puppet/provider/vcsrepo/svn.rb create mode 100644 lib/puppet/type/vcsrepo.rb (limited to 'lib') diff --git a/lib/puppet/provider/vcsrepo.rb b/lib/puppet/provider/vcsrepo.rb new file mode 100644 index 000000000..2c026ba86 --- /dev/null +++ b/lib/puppet/provider/vcsrepo.rb @@ -0,0 +1,34 @@ +require 'tmpdir' +require 'digest/md5' +require 'fileutils' + +# Abstract +class Puppet::Provider::Vcsrepo < Puppet::Provider + + private + + def set_ownership + owner = @resource.value(:owner) || nil + group = @resource.value(:group) || nil + FileUtils.chown_R(owner, group, @resource.value(:path)) + end + + def path_exists? + File.directory?(@resource.value(:path)) + end + + # Note: We don't rely on Dir.chdir's behavior of automatically returning the + # value of the last statement -- for easier stubbing. + def at_path(&block) #:nodoc: + value = nil + Dir.chdir(@resource.value(:path)) do + value = yield + end + value + end + + def tempdir + @tempdir ||= File.join(Dir.tmpdir, 'vcsrepo-' + Digest::MD5.hexdigest(@resource.value(:path))) + end + +end diff --git a/lib/puppet/provider/vcsrepo/bzr.rb b/lib/puppet/provider/vcsrepo/bzr.rb new file mode 100644 index 000000000..a0605624b --- /dev/null +++ b/lib/puppet/provider/vcsrepo/bzr.rb @@ -0,0 +1,64 @@ +require File.join(File.dirname(__FILE__), '..', 'vcsrepo') + +Puppet::Type.type(:vcsrepo).provide(:bzr, :parent => Puppet::Provider::Vcsrepo) do + desc "Supports Bazaar repositories" + + commands :bzr => 'bzr' + defaultfor :bzr => :exists + has_features :reference_tracking + + def create + if !@resource.value(:source) + create_repository(@resource.value(:path)) + else + clone_repository(@resource.value(:revision)) + end + end + + def exists? + File.directory?(File.join(@resource.value(:path), '.bzr')) + end + + def destroy + FileUtils.rm_rf(@resource.value(:path)) + end + + def revision + at_path do + current_revid = bzr('version-info')[/^revision-id:\s+(\S+)/, 1] + desired = @resource.value(:revision) + begin + desired_revid = bzr('revision-info', desired).strip.split(/\s+/).last + rescue Puppet::ExecutionFailure + # Possible revid available during update (but definitely not current) + desired_revid = nil + end + if current_revid == desired_revid + desired + else + current_revid + end + end + end + + def revision=(desired) + bzr('update', '-r', desired, @resource.value(:path)) + end + + private + + def create_repository(path) + bzr('init', path) + end + + def clone_repository(revision) + args = ['branch'] + if revision + args.push('-r', revision) + end + args.push(@resource.value(:source), + @resource.value(:path)) + bzr(*args) + end + +end diff --git a/lib/puppet/provider/vcsrepo/cvs.rb b/lib/puppet/provider/vcsrepo/cvs.rb new file mode 100644 index 000000000..e82c23afe --- /dev/null +++ b/lib/puppet/provider/vcsrepo/cvs.rb @@ -0,0 +1,80 @@ +require File.join(File.dirname(__FILE__), '..', 'vcsrepo') + +Puppet::Type.type(:vcsrepo).provide(:cvs, :parent => Puppet::Provider::Vcsrepo) do + desc "Supports CVS repositories/workspaces" + + commands :cvs => 'cvs' + defaultfor :cvs => :exists + has_features :gzip_compression, :reference_tracking + + def create + if !@resource.value(:source) + create_repository(@resource.value(:path)) + else + checkout_repository + end + end + + def exists? + if @resource.value(:source) + directory = File.join(@resource.value(:path), 'CVS') + else + directory = File.join(@resource.value(:path), 'CVSROOT') + end + File.directory?(directory) + end + + def destroy + FileUtils.rm_rf(@resource.value(:path)) + end + + def revision + if File.exist?(tag_file) + contents = File.read(tag_file) + # Note: Doesn't differentiate between N and T entries + contents[1..-1] + else + 'MAIN' + end + end + + def revision=(desired) + at_path do + cvs('update', '-r', desired, '.') + end + end + + private + + def tag_file + File.join(@resource.value(:path), 'CVS', 'Tag') + end + + def checkout_repository + dirname, basename = File.split(@resource.value(:path)) + Dir.chdir(dirname) do + args = ['-d', @resource.value(:source)] + if @resource.value(:compression) + args.push('-z', @resource.value(:compression)) + end + args.push('checkout', '-d', basename, module_name) + cvs(*args) + end + if @resource.value(:revision) + self.revision = @resource.value(:revision) + end + end + + # When the source: + # * Starts with ':' (eg, :pserver:...) + def module_name + if (source = @resource.value(:source)) + source[0, 1] == ':' ? File.basename(source) : '.' + end + end + + def create_repository(path) + cvs('-d', path, 'init') + end + +end diff --git a/lib/puppet/provider/vcsrepo/git.rb b/lib/puppet/provider/vcsrepo/git.rb new file mode 100644 index 000000000..fa7e492cf --- /dev/null +++ b/lib/puppet/provider/vcsrepo/git.rb @@ -0,0 +1,264 @@ +require File.join(File.dirname(__FILE__), '..', 'vcsrepo') + +Puppet::Type.type(:vcsrepo).provide(:git, :parent => Puppet::Provider::Vcsrepo) do + desc "Supports Git repositories" + + ##TODO modify the commands below so that the su - is included + commands :git => 'git' + defaultfor :git => :exists + has_features :bare_repositories, :reference_tracking + + def create + if !@resource.value(:source) + init_repository(@resource.value(:path)) + else + clone_repository(@resource.value(:source), @resource.value(:path)) + if @resource.value(:revision) + if @resource.value(:ensure) == :bare + notice "Ignoring revision for bare repository" + else + checkout_or_reset + end + end + if @resource.value(:ensure) != :bare + update_submodules + end + end + update_owner_and_excludes + end + + def destroy + FileUtils.rm_rf(@resource.value(:path)) + end + + def latest? + at_path do + return self.revision == self.latest + end + end + + def latest + branch = on_branch? + if branch == 'master' + return get_revision('origin/HEAD') + else + return get_revision('origin/%s' % branch) + end + end + + def revision + update_references + current = at_path { git('rev-parse', 'HEAD') } + canonical = at_path { git('rev-parse', @resource.value(:revision)) } + if current == canonical + @resource.value(:revision) + else + current + end + end + + def revision=(desired) + checkout_or_reset(desired) + if local_branch_revision?(desired) + # reset instead of pull to avoid merge conflicts. assuming remote is + # authoritative. + # might be worthwhile to have an allow_local_changes param to decide + # whether to reset or pull when we're ensuring latest. + at_path { git('reset', '--hard', "origin/#{desired}") } + end + if @resource.value(:ensure) != :bare + update_submodules + end + update_owner_and_excludes + end + + def bare_exists? + bare_git_config_exists? && !working_copy_exists? + end + + def working_copy_exists? + File.directory?(File.join(@resource.value(:path), '.git')) + end + + def exists? + working_copy_exists? || bare_exists? + end + + def update_references + at_path do + git('fetch', '--tags', 'origin') + end + end + + private + + def bare_git_config_exists? + File.exist?(File.join(@resource.value(:path), 'config')) + end + + def clone_repository(source, path) + check_force + args = ['clone'] + if @resource.value(:ensure) == :bare + args << '--bare' + end + if !File.exist?(File.join(@resource.value(:path), '.git')) + args.push(source, path) + git(*args) + else + notice "Repo has already been cloned" + end + end + + def check_force + if path_exists? + if @resource.value(:force) + notice "Removing %s to replace with vcsrepo." % @resource.value(:path) + destroy + else + raise Puppet::Error, "Could not create repository (non-repository at path)" + end + end + end + + def init_repository(path) + check_force + if @resource.value(:ensure) == :bare && working_copy_exists? + convert_working_copy_to_bare + elsif @resource.value(:ensure) == :present && bare_exists? + convert_bare_to_working_copy + else + # normal init + FileUtils.mkdir(@resource.value(:path)) + args = ['init'] + if @resource.value(:ensure) == :bare + args << '--bare' + end + at_path do + git(*args) + end + end + end + + # Convert working copy to bare + # + # Moves: + # /.git + # to: + # / + def convert_working_copy_to_bare + notice "Converting working copy repository to bare repository" + FileUtils.mv(File.join(@resource.value(:path), '.git'), tempdir) + FileUtils.rm_rf(@resource.value(:path)) + FileUtils.mv(tempdir, @resource.value(:path)) + end + + # Convert bare to working copy + # + # Moves: + # / + # to: + # /.git + def convert_bare_to_working_copy + notice "Converting bare repository to working copy repository" + FileUtils.mv(@resource.value(:path), tempdir) + FileUtils.mkdir(@resource.value(:path)) + FileUtils.mv(tempdir, File.join(@resource.value(:path), '.git')) + if commits_in?(File.join(@resource.value(:path), '.git')) + reset('HEAD') + git('checkout', '-f') + update_owner_and_excludes + end + end + + def commits_in?(dot_git) + Dir.glob(File.join(dot_git, 'objects/info/*'), File::FNM_DOTMATCH) do |e| + return true unless %w(. ..).include?(File::basename(e)) + end + false + end + + def checkout_or_reset(revision = @resource.value(:revision)) + if local_branch_revision? + reset(revision) + elsif tag_revision? + at_path { git('checkout', '-b', revision) } + elsif remote_branch_revision? + at_path { git('checkout', '-b', revision, '--track', "origin/#{revision}") } + end + end + + def reset(desired) + at_path do + git('reset', '--hard', desired) + end + end + + def update_submodules + at_path do + git('submodule', 'init') + git('submodule', 'update') + git('submodule', 'foreach', 'git', 'submodule', 'init') + git('submodule', 'foreach', 'git', 'submodule', 'update') + end + end + + def remote_branch_revision?(revision = @resource.value(:revision)) + # git < 1.6 returns 'origin/#{revision}' + # git 1.6+ returns 'remotes/origin/#{revision}' + at_path { branches.grep /(remotes\/)?origin\/#{revision}/ } + end + + def local_branch_revision?(revision = @resource.value(:revision)) + at_path { branches.include?(revision) } + end + + def tag_revision?(revision = @resource.value(:revision)) + at_path { tags.include?(revision) } + end + + def branches + at_path { git('branch', '-a') }.gsub('*', ' ').split(/\n/).map { |line| line.strip } + end + + def on_branch? + at_path { git('branch', '-a') }.split(/\n/).grep(/\*/).to_s.gsub('*', '').strip + end + + def tags + at_path { git('tag', '-l') }.split(/\n/).map { |line| line.strip } + end + + def set_excludes + at_path { open('.git/info/exclude', 'w') { |f| @resource.value(:excludes).each { |ex| f.write(ex + "\n") }}} + end + + def get_revision(rev) + if !working_copy_exists? + create + end + at_path do + git('fetch', 'origin') + git('fetch', '--tags', 'origin') + end + current = at_path { git('rev-parse', rev).strip } + if @resource.value(:revision) + if local_branch_revision? + canonical = at_path { git('rev-parse', @resource.value(:revision)).strip } + elsif remote_branch_revision? + canonical = at_path { git('rev-parse', 'origin/' + @resource.value(:revision)).strip } + end + current = @resource.value(:revision) if current == canonical + end + return current + end + + def update_owner_and_excludes + if @resource.value(:owner) or @resource.value(:group) + set_ownership + end + if @resource.value(:excludes) + set_excludes + end + end +end diff --git a/lib/puppet/provider/vcsrepo/hg.rb b/lib/puppet/provider/vcsrepo/hg.rb new file mode 100644 index 000000000..f96758612 --- /dev/null +++ b/lib/puppet/provider/vcsrepo/hg.rb @@ -0,0 +1,101 @@ +require File.join(File.dirname(__FILE__), '..', 'vcsrepo') + +Puppet::Type.type(:vcsrepo).provide(:hg, :parent => Puppet::Provider::Vcsrepo) do + desc "Supports Mercurial repositories" + + commands :hg => 'hg' + defaultfor :hg => :exists + has_features :reference_tracking + + def create + if !@resource.value(:source) + create_repository(@resource.value(:path)) + else + clone_repository(@resource.value(:revision)) + end + update_owner + end + + def working_copy_exists? + File.directory?(File.join(@resource.value(:path), '.hg')) + end + + def exists? + working_copy_exists? + end + + def destroy + FileUtils.rm_rf(@resource.value(:path)) + end + + def latest? + at_path do + return self.revision == self.latest + end + end + + def latest + at_path do + begin + hg('incoming', '--branch', '.', '--newest-first', '--limit', '1')[/^changeset:\s+(?:-?\d+):(\S+)/m, 1] + rescue Puppet::ExecutionFailure + # If there are no new changesets, return the current nodeid + self.revision + end + end + end + + def revision + at_path do + current = hg('parents')[/^changeset:\s+(?:-?\d+):(\S+)/m, 1] + desired = @resource.value(:revision) + if desired + # Return the tag name if it maps to the current nodeid + mapped = hg('tags')[/^#{Regexp.quote(desired)}\s+\d+:(\S+)/m, 1] + if current == mapped + desired + else + current + end + else + current + end + end + end + + def revision=(desired) + at_path do + hg('pull') + begin + hg('merge') + rescue Puppet::ExecutionFailure + # If there's nothing to merge, just skip + end + hg('update', '--clean', '-r', desired) + end + update_owner + end + + private + + def create_repository(path) + hg('init', path) + end + + def clone_repository(revision) + args = ['clone'] + if revision + args.push('-u', revision) + end + args.push(@resource.value(:source), + @resource.value(:path)) + hg(*args) + end + + def update_owner + if @resource.value(:owner) or @resource.value(:group) + set_ownership + end + end + +end diff --git a/lib/puppet/provider/vcsrepo/svn.rb b/lib/puppet/provider/vcsrepo/svn.rb new file mode 100644 index 000000000..680188c1e --- /dev/null +++ b/lib/puppet/provider/vcsrepo/svn.rb @@ -0,0 +1,82 @@ +require File.join(File.dirname(__FILE__), '..', 'vcsrepo') + +Puppet::Type.type(:vcsrepo).provide(:svn, :parent => Puppet::Provider::Vcsrepo) do + desc "Supports Subversion repositories" + + commands :svn => 'svn', + :svnadmin => 'svnadmin' + + defaultfor :svn => :exists + has_features :filesystem_types, :reference_tracking + + def create + if !@resource.value(:source) + create_repository(@resource.value(:path)) + else + checkout_repository(@resource.value(:source), + @resource.value(:path), + @resource.value(:revision)) + end + end + + def working_copy_exists? + File.directory?(File.join(@resource.value(:path), '.svn')) + end + + def exists? + working_copy_exists? + end + + def destroy + FileUtils.rm_rf(@resource.value(:path)) + end + + def latest? + at_path do + if self.revision < self.latest then + return false + else + return true + end + end + end + + def latest + at_path do + svn('info', '-r', 'HEAD')[/^Revision:\s+(\d+)/m, 1] + end + end + + def revision + at_path do + svn('info')[/^Revision:\s+(\d+)/m, 1] + end + end + + def revision=(desired) + at_path do + svn('update', '-r', desired) + end + end + + private + + def checkout_repository(source, path, revision = nil) + args = ['checkout'] + if revision + args.push('-r', revision) + end + args.push(source, path) + svn(*args) + end + + def create_repository(path) + args = ['create'] + if @resource.value(:fstype) + args.push('--fs-type', @resource.value(:fstype)) + end + args << path + svnadmin(*args) + end + +end diff --git a/lib/puppet/type/vcsrepo.rb b/lib/puppet/type/vcsrepo.rb new file mode 100644 index 000000000..f0d2613ca --- /dev/null +++ b/lib/puppet/type/vcsrepo.rb @@ -0,0 +1,138 @@ +require 'pathname' + +Puppet::Type.newtype(:vcsrepo) do + desc "A local version control repository" + + feature :gzip_compression, + "The provider supports explicit GZip compression levels" + + feature :bare_repositories, + "The provider differentiates between bare repositories + and those with working copies", + :methods => [:bare_exists?, :working_copy_exists?] + + feature :filesystem_types, + "The provider supports different filesystem types" + + feature :reference_tracking, + "The provider supports tracking revision references that can change + over time (eg, some VCS tags and branch names)" + + ensurable do + attr_accessor :latest + + def insync?(is) + @should ||= [] + + case should + when :present + return true unless [:absent, :purged, :held].include?(is) + when :latest + if is == :latest + return true + else + self.debug "%s repo revision is %s, latest is %s" % + [@resource.name, provider.revision, provider.latest] + return false + end + end + end + + newvalue :present do + provider.create + end + + newvalue :bare, :required_features => [:bare_repositories] do + provider.create + end + + newvalue :absent do + provider.destroy + end + + newvalue :latest, :required_features => [:reference_tracking] do + if provider.exists? + if provider.respond_to?(:update_references) + provider.update_references + end + if provider.respond_to?(:latest?) + reference = provider.latest || provider.revision + else + reference = resource.value(:revision) || provider.revision + end + notice "Updating to latest '#{reference}' revision" + provider.revision = reference + else + provider.create + end + end + + def retrieve + prov = @resource.provider + if prov + if prov.working_copy_exists? + prov.latest? ? :latest : :present + elsif prov.class.feature?(:bare_repositories) and prov.bare_exists? + :bare + else + :absent + end + else + raise Puppet::Error, "Could not find provider" + end + end + + end + + newparam(:path) do + desc "Absolute path to repository" + isnamevar + validate do |value| + path = Pathname.new(value) + unless path.absolute? + raise ArgumentError, "Path must be absolute: #{path}" + end + end + end + + newparam(:source) do + desc "The source URI for the repository" + end + + newparam(:fstype, :required_features => [:filesystem_types]) do + desc "Filesystem type" + end + + newproperty(:revision) do + desc "The revision of the repository" + newvalue(/^\S+$/) + end + + newparam(:owner) do + desc "The user/uid that owns the repository files" + end + + newparam(:group) do + desc "The group/gid that owns the repository files" + end + + newparam(:excludes) do + desc "Files to be excluded from the repository" + end + + newparam(:force) do + desc "Force repository creation, destroying any files on the path in the process." + newvalues(:true, :false) + defaultto false + end + + newparam :compression, :required_features => [:gzip_compression] do + desc "Compression level" + validate do |amount| + unless Integer(amount).between?(0, 6) + raise ArgumentError, "Unsupported compression level: #{amount} (expected 0-6)" + end + end + end + +end -- cgit From 107b38a94f8b4e4a0fcca4879a167ab4c955fe4d Mon Sep 17 00:00:00 2001 From: Matt Robinson Date: Tue, 24 May 2011 09:31:39 -0700 Subject: maint: Fix pacman provider to work with Ruby 1.9 Ruby 1.9 doesn't allow the lambda to walk up the directory structure to require the spec helper This is the same issue as with commit: f6da3339f59bbd9243a03dc1e417b1fed7955c7e Also, you can't call each on a string in Ruby 1.9 directly since it doesn't implicitly do a split on \n like it did in older Rubies, but each_line works all the way back to 1.8.5 Reviewed-by: Nick Lewis --- lib/puppet/provider/package/pacman.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/puppet/provider/package/pacman.rb b/lib/puppet/provider/package/pacman.rb index 6eb7dbe3d..5e05d147e 100644 --- a/lib/puppet/provider/package/pacman.rb +++ b/lib/puppet/provider/package/pacman.rb @@ -33,7 +33,7 @@ Puppet::Type.type(:package).provide :pacman, :parent => Puppet::Provider::Packag fields = [:name, :ensure] hash = {} - process.each { |line| + process.each_line { |line| if match = regex.match(line) fields.zip(match.captures) { |field,value| hash[field] = value -- cgit From 51608221da248e679326087303ecd0c649225d5b Mon Sep 17 00:00:00 2001 From: Jacob Helwig Date: Fri, 17 Jun 2011 11:26:58 -0700 Subject: Clean up indentation, whitespace, and commented out code The mis-indented code, extra newlines, and commented out code were noticed while investigating the order dependent test failure fixed in 4365c8ba. Reviewed-by: Max Martin --- lib/puppet/parser/functions.rb | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) (limited to 'lib') diff --git a/lib/puppet/parser/functions.rb b/lib/puppet/parser/functions.rb index 5807c0bbe..e19ac127f 100644 --- a/lib/puppet/parser/functions.rb +++ b/lib/puppet/parser/functions.rb @@ -16,11 +16,9 @@ module Puppet::Parser::Functions def self.autoloader unless defined?(@autoloader) - - @autoloader = Puppet::Util::Autoload.new( + @autoloader = Puppet::Util::Autoload.new( self, "puppet/parser/functions", - :wrap => false ) end @@ -88,7 +86,6 @@ module Puppet::Parser::Functions ret = "" functions.sort { |a,b| a[0].to_s <=> b[0].to_s }.each do |name, hash| - #ret += "#{name}\n#{hash[:type]}\n" ret += "#{name}\n#{"-" * name.to_s.length}\n" if hash[:doc] ret += Puppet::Util::Docs.scrub(hash[:doc]) @@ -114,11 +111,9 @@ module Puppet::Parser::Functions end # Runs a newfunction to create a function for each of the log levels - Puppet::Util::Log.levels.each do |level| newfunction(level, :doc => "Log a message on the server at level #{level.to_s}.") do |vals| send(level, vals.join(" ")) end end - end -- cgit