puppet 2.7.13 → 2.7.14

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of puppet might be problematic. Click here for more details.

Files changed (215) hide show
  1. data/CHANGELOG +144 -1
  2. data/conf/osx/preflight +1 -1
  3. data/conf/redhat/puppet.spec +9 -5
  4. data/conf/suse/puppet.spec +4 -1
  5. data/conf/windows/eventlog/Rakefile +32 -0
  6. data/conf/windows/eventlog/puppetres.dll +0 -0
  7. data/conf/windows/eventlog/puppetres.mc +18 -0
  8. data/ext/rack/files/apache2.conf +3 -0
  9. data/install.rb +23 -1
  10. data/lib/puppet.rb +1 -1
  11. data/lib/puppet/agent.rb +1 -14
  12. data/lib/puppet/application/kick.rb +1 -1
  13. data/lib/puppet/application/module.rb +11 -0
  14. data/lib/puppet/daemon.rb +74 -3
  15. data/lib/puppet/defaults.rb +1 -1
  16. data/lib/puppet/face/certificate.rb +1 -1
  17. data/lib/puppet/face/help/man.erb +1 -1
  18. data/lib/puppet/face/module.rb +17 -0
  19. data/lib/puppet/face/module/build.rb +10 -4
  20. data/lib/puppet/face/module/changes.rb +5 -5
  21. data/lib/puppet/face/module/generate.rb +6 -4
  22. data/lib/puppet/face/module/install.rb +122 -32
  23. data/lib/puppet/face/module/list.rb +234 -33
  24. data/lib/puppet/face/module/search.rb +56 -23
  25. data/lib/puppet/face/module/uninstall.rb +33 -38
  26. data/lib/puppet/face/module/upgrade.rb +84 -0
  27. data/lib/puppet/feature/eventlog.rb +6 -0
  28. data/lib/puppet/forge.rb +67 -122
  29. data/lib/puppet/forge/cache.rb +1 -1
  30. data/lib/puppet/forge/repository.rb +6 -25
  31. data/lib/puppet/indirector/facts/network_device.rb +1 -1
  32. data/lib/puppet/interface/action.rb +1 -1
  33. data/lib/puppet/module.rb +79 -28
  34. data/lib/puppet/module_tool.rb +72 -34
  35. data/lib/puppet/module_tool/applications.rb +12 -14
  36. data/lib/puppet/module_tool/applications/application.rb +21 -19
  37. data/lib/puppet/module_tool/applications/builder.rb +4 -4
  38. data/lib/puppet/module_tool/applications/checksummer.rb +12 -3
  39. data/lib/puppet/module_tool/applications/generator.rb +1 -1
  40. data/lib/puppet/module_tool/applications/installer.rb +163 -34
  41. data/lib/puppet/module_tool/applications/searcher.rb +2 -3
  42. data/lib/puppet/module_tool/applications/uninstaller.rb +84 -36
  43. data/lib/puppet/module_tool/applications/unpacker.rb +4 -26
  44. data/lib/puppet/module_tool/applications/upgrader.rb +109 -0
  45. data/lib/puppet/module_tool/checksums.rb +2 -2
  46. data/lib/puppet/module_tool/contents_description.rb +1 -1
  47. data/lib/puppet/module_tool/dependency.rb +2 -2
  48. data/lib/puppet/module_tool/errors.rb +9 -0
  49. data/lib/puppet/module_tool/errors/base.rb +15 -0
  50. data/lib/puppet/module_tool/errors/installer.rb +90 -0
  51. data/lib/puppet/module_tool/errors/shared.rb +115 -0
  52. data/lib/puppet/module_tool/errors/uninstaller.rb +45 -0
  53. data/lib/puppet/module_tool/errors/upgrader.rb +72 -0
  54. data/lib/puppet/module_tool/metadata.rb +2 -2
  55. data/lib/puppet/module_tool/modulefile.rb +7 -7
  56. data/lib/puppet/module_tool/shared_behaviors.rb +161 -0
  57. data/lib/puppet/module_tool/skeleton.rb +1 -1
  58. data/lib/puppet/node/environment.rb +4 -2
  59. data/lib/puppet/parser/ast/leaf.rb +1 -1
  60. data/lib/puppet/parser/functions/create_resources.rb +3 -2
  61. data/lib/puppet/parser/scope.rb +44 -9
  62. data/lib/puppet/provider/augeas/augeas.rb +2 -2
  63. data/lib/puppet/provider/exec.rb +8 -3
  64. data/lib/puppet/provider/exec/shell.rb +1 -2
  65. data/lib/puppet/provider/nameservice/directoryservice.rb +10 -4
  66. data/lib/puppet/provider/package/gem.rb +1 -1
  67. data/lib/puppet/provider/package/pkg.rb +10 -21
  68. data/lib/puppet/provider/selmodule/semodule.rb +1 -2
  69. data/lib/puppet/provider/service/upstart.rb +33 -17
  70. data/lib/puppet/provider/ssh_authorized_key/parsed.rb +1 -1
  71. data/lib/puppet/rails/inventory_node.rb +7 -7
  72. data/lib/puppet/reports/http.rb +4 -1
  73. data/lib/puppet/reports/tagmail.rb +8 -1
  74. data/lib/puppet/resource/type.rb +1 -1
  75. data/lib/puppet/test/test_helper.rb +138 -0
  76. data/lib/puppet/type.rb +9 -1
  77. data/lib/puppet/type/file.rb +18 -10
  78. data/lib/puppet/type/package.rb +13 -9
  79. data/lib/puppet/type/resources.rb +1 -1
  80. data/lib/puppet/type/ssh_authorized_key.rb +3 -4
  81. data/lib/puppet/type/sshkey.rb +4 -4
  82. data/lib/puppet/type/user.rb +1 -0
  83. data/lib/puppet/type/vlan.rb +1 -1
  84. data/lib/puppet/util.rb +31 -14
  85. data/lib/puppet/util/autoload.rb +1 -1
  86. data/lib/puppet/util/command_line.rb +2 -6
  87. data/lib/puppet/util/instrumentation/indirection_probe.rb +1 -1
  88. data/lib/puppet/util/instrumentation/instrumentable.rb +1 -1
  89. data/lib/puppet/util/instrumentation/listeners/log.rb +1 -1
  90. data/lib/puppet/util/instrumentation/listeners/performance.rb +1 -1
  91. data/lib/puppet/util/log.rb +3 -1
  92. data/lib/puppet/util/log/destinations.rb +38 -0
  93. data/lib/puppet/util/monkey_patches.rb +45 -0
  94. data/lib/puppet/util/network_device/base.rb +1 -1
  95. data/lib/puppet/util/network_device/cisco.rb +1 -1
  96. data/lib/puppet/util/network_device/cisco/facts.rb +1 -1
  97. data/lib/puppet/util/network_device/cisco/interface.rb +1 -1
  98. data/lib/puppet/util/network_device/config.rb +1 -1
  99. data/lib/puppet/util/network_device/ipcalc.rb +1 -1
  100. data/lib/puppet/util/network_device/transport.rb +1 -1
  101. data/lib/puppet/util/network_device/transport/base.rb +1 -1
  102. data/lib/puppet/util/network_device/transport/ssh.rb +1 -1
  103. data/lib/puppet/util/settings.rb +2 -11
  104. data/lib/puppet/util/settings/file_setting.rb +3 -5
  105. data/lib/puppet/util/terminal.rb +16 -0
  106. data/lib/puppet/util/zaml.rb +3 -1
  107. data/lib/semver.rb +15 -7
  108. data/spec/fixtures/releases/jamtur01-apache/metadata.json +1 -1
  109. data/spec/fixtures/unit/parser/lexer/arithmetic_expression.pp +1 -1
  110. data/spec/fixtures/unit/provider/package/pkg/dummy +1 -0
  111. data/spec/fixtures/unit/provider/package/pkg/incomplete +1 -0
  112. data/spec/fixtures/unit/provider/package/pkg/publisher +2 -0
  113. data/spec/fixtures/unit/provider/package/pkg/simple +4 -0
  114. data/spec/fixtures/unit/reports/tagmail/tagmail_email.conf +2 -0
  115. data/spec/fixtures/yaml/report0.25.x.yaml +1 -1
  116. data/spec/fixtures/yaml/report2.6.x.yaml +1 -1
  117. data/spec/integration/faces/documentation_spec.rb +1 -1
  118. data/spec/integration/network/rest_authconfig_spec.rb +1 -1
  119. data/spec/lib/puppet_spec/compiler.rb +6 -0
  120. data/spec/lib/puppet_spec/database.rb +30 -0
  121. data/spec/lib/puppet_spec/files.rb +4 -2
  122. data/spec/shared_behaviours/path_parameters.rb +2 -29
  123. data/spec/shared_contexts/platform.rb +43 -0
  124. data/spec/spec_helper.rb +36 -65
  125. data/spec/unit/agent_spec.rb +0 -32
  126. data/spec/unit/application/kick_spec.rb +2 -2
  127. data/spec/unit/daemon_spec.rb +1 -17
  128. data/spec/unit/face/module/install_spec.rb +158 -0
  129. data/spec/unit/face/module/list_spec.rb +182 -0
  130. data/spec/unit/face/module/search_spec.rb +163 -0
  131. data/spec/unit/face/module/uninstall_spec.rb +77 -0
  132. data/spec/unit/face/module/upgrade_spec.rb +26 -0
  133. data/spec/unit/forge/repository_spec.rb +0 -30
  134. data/spec/unit/forge_spec.rb +28 -86
  135. data/spec/unit/indirector/catalog/active_record_spec.rb +45 -65
  136. data/spec/unit/indirector/facts/inventory_active_record_spec.rb +5 -18
  137. data/spec/unit/indirector/resource/active_record_spec.rb +2 -11
  138. data/spec/unit/indirector/resource/ral_spec.rb +7 -2
  139. data/spec/unit/module_spec.rb +240 -107
  140. data/spec/unit/module_tool/application_spec.rb +3 -5
  141. data/spec/unit/module_tool/applications/application_spec.rb +19 -0
  142. data/spec/unit/module_tool/applications/installer_spec.rb +205 -0
  143. data/spec/unit/module_tool/applications/uninstaller_spec.rb +206 -0
  144. data/spec/unit/module_tool/applications/upgrader_spec.rb +37 -0
  145. data/spec/unit/module_tool/metadata_spec.rb +2 -2
  146. data/spec/unit/module_tool_spec.rb +109 -1
  147. data/spec/unit/node/environment_spec.rb +16 -1
  148. data/spec/unit/parser/ast/leaf_spec.rb +16 -1
  149. data/spec/unit/parser/collector_spec.rb +2 -12
  150. data/spec/unit/parser/functions/create_resources_spec.rb +135 -86
  151. data/spec/unit/parser/functions/generate_spec.rb +2 -10
  152. data/spec/unit/parser/scope_spec.rb +345 -16
  153. data/spec/unit/provider/augeas/augeas_spec.rb +19 -0
  154. data/spec/unit/provider/exec/shell_spec.rb +17 -14
  155. data/spec/unit/provider/exec/windows_spec.rb +1 -7
  156. data/spec/unit/provider/exec_spec.rb +35 -0
  157. data/spec/unit/provider/nameservice/directoryservice_spec.rb +10 -0
  158. data/spec/unit/provider/package/dpkg_spec.rb +2 -1
  159. data/spec/unit/provider/package/gem_spec.rb +15 -0
  160. data/spec/unit/provider/package/openbsd_spec.rb +5 -4
  161. data/spec/unit/provider/package/pacman_spec.rb +3 -2
  162. data/spec/unit/provider/package/pkg_spec.rb +56 -33
  163. data/spec/unit/provider/selmodule_spec.rb +11 -4
  164. data/spec/unit/provider/service/redhat_spec.rb +1 -3
  165. data/spec/unit/provider/service/smf_spec.rb +1 -3
  166. data/spec/unit/provider/service/upstart_spec.rb +38 -0
  167. data/spec/unit/provider/ssh_authorized_key/parsed_spec.rb +28 -0
  168. data/spec/unit/rails/host_spec.rb +6 -12
  169. data/spec/unit/rails/param_value_spec.rb +3 -8
  170. data/spec/unit/rails/resource_spec.rb +2 -8
  171. data/spec/unit/reports/http_spec.rb +47 -31
  172. data/spec/unit/reports/tagmail_spec.rb +77 -0
  173. data/spec/unit/resource/type_spec.rb +2 -2
  174. data/spec/unit/resource_spec.rb +18 -20
  175. data/spec/unit/semver_spec.rb +31 -13
  176. data/spec/unit/type/exec_spec.rb +8 -15
  177. data/spec/unit/type/group_spec.rb +0 -9
  178. data/spec/unit/type/package_spec.rb +10 -0
  179. data/spec/unit/type/resources_spec.rb +4 -5
  180. data/spec/unit/type/ssh_authorized_key_spec.rb +4 -15
  181. data/spec/unit/type/sshkey_spec.rb +9 -11
  182. data/spec/unit/type/user_spec.rb +123 -127
  183. data/spec/unit/type_spec.rb +20 -0
  184. data/spec/unit/util/command_line_spec.rb +2 -2
  185. data/spec/unit/util/instrumentation/data_spec.rb +1 -1
  186. data/spec/unit/util/instrumentation/indirection_probe_spec.rb +1 -1
  187. data/spec/unit/util/instrumentation/instrumentable_spec.rb +1 -1
  188. data/spec/unit/util/instrumentation/listener_spec.rb +1 -1
  189. data/spec/unit/util/instrumentation/listeners/log_spec.rb +1 -1
  190. data/spec/unit/util/instrumentation/listeners/performance_spec.rb +1 -1
  191. data/spec/unit/util/instrumentation_spec.rb +1 -1
  192. data/spec/unit/util/log/destinations_spec.rb +4 -8
  193. data/spec/unit/util/log_spec.rb +47 -0
  194. data/spec/unit/util/reference_spec.rb +1 -1
  195. data/spec/unit/util/settings/file_setting_spec.rb +9 -0
  196. data/spec/unit/util/settings_spec.rb +0 -53
  197. data/spec/unit/util/terminal_spec.rb +42 -0
  198. data/spec/unit/util/zaml_spec.rb +7 -0
  199. data/spec/unit/util_spec.rb +63 -20
  200. data/tasks/rake/manpages.rake +1 -1
  201. data/test/data/snippets/arithmetic_expression.pp +1 -1
  202. data/test/other/puppet.rb +0 -1
  203. data/test/util/log.rb +6 -6
  204. metadata +41 -16
  205. data/lib/puppet/external/event-loop.rb +0 -1
  206. data/lib/puppet/external/event-loop/better-definers.rb +0 -367
  207. data/lib/puppet/external/event-loop/event-loop.rb +0 -355
  208. data/lib/puppet/external/event-loop/signal-system.rb +0 -218
  209. data/lib/puppet/face/module/clean.rb +0 -30
  210. data/lib/puppet/module_tool/applications/cleaner.rb +0 -16
  211. data/lib/puppet/module_tool/skeleton/templates/generator/metadata.json +0 -12
  212. data/lib/puppet/module_tool/utils.rb +0 -5
  213. data/lib/puppet/module_tool/utils/interrogation.rb +0 -25
  214. data/spec/integration/module_tool_spec.rb +0 -475
  215. data/spec/unit/module_tool/uninstaller_spec.rb +0 -124
@@ -1,11 +1,11 @@
1
1
  require 'fileutils'
2
2
 
3
- module Puppet::Module::Tool
3
+ module Puppet::ModuleTool
4
4
  module Applications
5
5
  class Builder < Application
6
6
 
7
7
  def initialize(path, options = {})
8
- @path = File.expand_path(Puppet::Module::Tool.find_module_root(path))
8
+ @path = File.expand_path(Puppet::ModuleTool.find_module_root(path))
9
9
  @pkg_path = File.join(@path, 'pkg')
10
10
  super(options)
11
11
  end
@@ -61,7 +61,7 @@ module Puppet::Module::Tool
61
61
  def create_directory
62
62
  FileUtils.mkdir(@pkg_path) rescue nil
63
63
  if File.directory?(build_path)
64
- FileUtils.rm_rf(build_path)
64
+ FileUtils.rm_rf(build_path, :secure => true)
65
65
  end
66
66
  FileUtils.mkdir(build_path)
67
67
  end
@@ -69,7 +69,7 @@ module Puppet::Module::Tool
69
69
  def copy_contents
70
70
  Dir[File.join(@path, '*')].each do |path|
71
71
  case File.basename(path)
72
- when *Puppet::Module::Tool::ARTIFACTS
72
+ when *Puppet::ModuleTool::ARTIFACTS
73
73
  next
74
74
  else
75
75
  FileUtils.cp_r path, build_path
@@ -1,4 +1,6 @@
1
- module Puppet::Module::Tool
1
+ require 'puppet/module_tool/checksums'
2
+
3
+ module Puppet::ModuleTool
2
4
  module Applications
3
5
  class Checksummer < Application
4
6
 
@@ -10,8 +12,15 @@ module Puppet::Module::Tool
10
12
  def run
11
13
  changes = []
12
14
  if metadata_file.exist?
13
- sums = Checksums.new(@path)
15
+ sums = Puppet::ModuleTool::Checksums.new(@path)
14
16
  (metadata['checksums'] || {}).each do |child_path, canonical_checksum|
17
+
18
+ # Work around an issue where modules built with an older version
19
+ # of PMT would include the metadata.json file in the list of files
20
+ # checksummed. This causes metadata.json to always report local
21
+ # changes.
22
+ next if File.basename(child_path) == "metadata.json"
23
+
15
24
  path = @path + child_path
16
25
  if canonical_checksum != sums.checksum(path)
17
26
  changes << child_path
@@ -28,7 +37,7 @@ module Puppet::Module::Tool
28
37
  #
29
38
  # Example return value:
30
39
  #
31
- # [ "REVISION", "metadata.json", "manifests/init.pp"]
40
+ # [ "REVISION", "manifests/init.pp"]
32
41
  #
33
42
  changes
34
43
  end
@@ -2,7 +2,7 @@ require 'pathname'
2
2
  require 'fileutils'
3
3
  require 'erb'
4
4
 
5
- module Puppet::Module::Tool
5
+ module Puppet::ModuleTool
6
6
  module Applications
7
7
  class Generator < Application
8
8
 
@@ -1,53 +1,182 @@
1
1
  require 'open-uri'
2
2
  require 'pathname'
3
3
  require 'tmpdir'
4
+ require 'semver'
5
+ require 'puppet/forge'
6
+ require 'puppet/module_tool'
7
+ require 'puppet/module_tool/shared_behaviors'
4
8
 
5
- module Puppet::Module::Tool
9
+ module Puppet::ModuleTool
6
10
  module Applications
7
11
  class Installer < Application
8
12
 
13
+ include Puppet::ModuleTool::Errors
14
+
9
15
  def initialize(name, options = {})
10
- @forge = Puppet::Forge::Forge.new
11
- @install_params = {}
16
+ @action = :install
17
+ @environment = Puppet::Node::Environment.new(Puppet.settings[:environment])
18
+ @force = options[:force]
19
+ @ignore_dependencies = options[:force] || options[:ignore_dependencies]
20
+ @name = name
21
+ super(options)
22
+ end
23
+
24
+ def run
25
+ begin
26
+ if is_module_package?(@name)
27
+ @source = :filesystem
28
+ @filename = File.expand_path(@name)
29
+ raise MissingPackageError, :requested_package => @filename unless File.exist?(@filename)
12
30
 
13
- if File.exist?(name)
14
- if File.directory?(name)
15
- # TODO Unify this handling with that of Unpacker#check_clobber!
16
- raise ArgumentError, "Module already installed: #{name}"
31
+ parsed = parse_filename(@filename)
32
+ @module_name = parsed[:module_name]
33
+ @version = parsed[:version]
34
+ else
35
+ @source = :repository
36
+ @module_name = @name.gsub('/', '-')
37
+ @version = options[:version]
17
38
  end
18
- @filename = File.expand_path(name)
19
- @install_params[:source] = :filesystem
20
- @install_params[:filename] = @filename
21
- parse_filename!
22
- else
23
- @install_params[:source] = :repository
24
- begin
25
- @install_params[:author], @install_params[:modname] = Puppet::Module::Tool::username_and_modname_from(name)
26
- rescue ArgumentError
27
- raise "Could not install module with invalid name: #{name}"
39
+
40
+ results = {
41
+ :module_name => @module_name,
42
+ :module_version => @version,
43
+ :install_dir => options[:target_dir],
44
+ }
45
+
46
+ unless File.directory? options[:target_dir]
47
+ raise MissingInstallDirectoryError,
48
+ :requested_module => @module_name,
49
+ :requested_version => @version || 'latest',
50
+ :directory => options[:target_dir]
28
51
  end
29
- @install_params[:version_requirement] = options[:version]
52
+
53
+ cached_paths = get_release_packages
54
+
55
+ unless @graph.empty?
56
+ Puppet.notice 'Installing -- do not interrupt ...'
57
+ cached_paths.each do |hash|
58
+ hash.each do |dir, path|
59
+ Unpacker.new(path, @options.merge(:target_dir => dir)).run
60
+ end
61
+ end
62
+ end
63
+ rescue ModuleToolError => err
64
+ results[:error] = {
65
+ :oneline => err.message,
66
+ :multiline => err.multiline,
67
+ }
68
+ else
69
+ results[:result] = :success
70
+ results[:installed_modules] = @graph
71
+ ensure
72
+ results[:result] ||= :failure
30
73
  end
31
- super(options)
74
+
75
+ results
76
+ end
77
+
78
+ private
79
+
80
+ include Puppet::ModuleTool::Shared
81
+
82
+ # Return a Pathname object representing the path to the module
83
+ # release package in the `Puppet.settings[:module_working_dir]`.
84
+ def get_release_packages
85
+ get_local_constraints
86
+
87
+ if !@force && @installed.include?(@module_name)
88
+
89
+ raise AlreadyInstalledError,
90
+ :module_name => @module_name,
91
+ :installed_version => @installed[@module_name].first.version,
92
+ :requested_version => @version || (@conditions[@module_name].empty? ? :latest : :best),
93
+ :local_changes => @installed[@module_name].first.local_changes
94
+ end
95
+
96
+ if @ignore_dependencies && @source == :filesystem
97
+ @urls = {}
98
+ @remote = { "#{@module_name}@#{@version}" => { } }
99
+ @versions = {
100
+ @module_name => [
101
+ { :vstring => @version, :semver => SemVer.new(@version) }
102
+ ]
103
+ }
104
+ else
105
+ get_remote_constraints
106
+ end
107
+
108
+ @graph = resolve_constraints({ @module_name => @version })
109
+ @graph.first[:tarball] = @filename if @source == :filesystem
110
+ resolve_install_conflicts(@graph) unless @force
111
+
112
+ # This clean call means we never "cache" the module we're installing, but this
113
+ # is desired since module authors can easily rerelease modules different content but the same
114
+ # version number, meaning someone with the old content cached will be very confused as to why
115
+ # they can't get new content.
116
+ # Long term we should just get rid of this caching behavior and cleanup downloaded modules after they install
117
+ # but for now this is a quick fix to disable caching
118
+ Puppet::Forge::Cache.clean
119
+ download_tarballs(@graph, @graph.last[:path])
32
120
  end
33
121
 
34
- def force?
35
- options[:force]
122
+ #
123
+ # Resolve installation conflicts by checking if the requested module
124
+ # or one of it's dependencies conflicts with an installed module.
125
+ #
126
+ # Conflicts occur under the following conditions:
127
+ #
128
+ # When installing 'puppetlabs-foo' and an existing directory in the
129
+ # target install path contains a 'foo' directory and we cannot determine
130
+ # the "full name" of the installed module.
131
+ #
132
+ # When installing 'puppetlabs-foo' and 'pete-foo' is already installed.
133
+ # This is considered a conflict because 'puppetlabs-foo' and 'pete-foo'
134
+ # install into the same directory 'foo'.
135
+ #
136
+ def resolve_install_conflicts(graph, is_dependency = false)
137
+ graph.each do |release|
138
+ @environment.modules_by_path[options[:target_dir]].each do |mod|
139
+ if mod.has_metadata?
140
+ metadata = {
141
+ :name => mod.forge_name.gsub('/', '-'),
142
+ :version => mod.version
143
+ }
144
+ next if release[:module] == metadata[:name]
145
+ else
146
+ metadata = nil
147
+ end
148
+
149
+ if release[:module] =~ /-#{mod.name}$/
150
+ dependency_info = {
151
+ :name => release[:module],
152
+ :version => release[:version][:vstring]
153
+ }
154
+ dependency = is_dependency ? dependency_info : nil
155
+ latest_version = @versions["#{@module_name}"].sort_by { |h| h[:semver] }.last[:vstring]
156
+
157
+ raise InstallConflictError,
158
+ :requested_module => @module_name,
159
+ :requested_version => @version || "latest: v#{latest_version}",
160
+ :dependency => dependency,
161
+ :directory => mod.path,
162
+ :metadata => metadata
163
+ end
164
+
165
+ resolve_install_conflicts(release[:dependencies], true)
166
+ end
167
+ end
36
168
  end
37
169
 
38
- def run
39
- cache_path = @forge.get_release_package(@install_params)
40
-
41
- module_dir = Unpacker.run(cache_path, options)
42
- # Return the Pathname object representing the path to the installed
43
- # module. This return value is used by the module_tool face install
44
- # action, and displayed to on the console.
45
- #
46
- # Example return value:
47
- #
48
- # "/etc/puppet/modules/apache"
49
- #
50
- module_dir
170
+ #
171
+ # Check if a file is a vaild module package.
172
+ # ---
173
+ # FIXME: Checking for a valid module package should be more robust and
174
+ # use the acutal metadata contained in the package. 03132012 - Hightower
175
+ # +++
176
+ #
177
+ def is_module_package?(name)
178
+ filename = File.expand_path(name)
179
+ filename =~ /.tar.gz$/
51
180
  end
52
181
  end
53
182
  end
@@ -1,15 +1,14 @@
1
- module Puppet::Module::Tool
1
+ module Puppet::ModuleTool
2
2
  module Applications
3
3
  class Searcher < Application
4
4
 
5
5
  def initialize(term, options = {})
6
6
  @term = term
7
- @forge = Puppet::Forge::Forge.new
8
7
  super(options)
9
8
  end
10
9
 
11
10
  def run
12
- @forge.search(@term)
11
+ Puppet::Forge.search(@term)
13
12
  end
14
13
  end
15
14
  end
@@ -1,57 +1,105 @@
1
- module Puppet::Module::Tool
1
+ module Puppet::ModuleTool
2
2
  module Applications
3
3
  class Uninstaller < Application
4
+ include Puppet::ModuleTool::Errors
4
5
 
5
6
  def initialize(name, options)
6
- @name = name
7
- @options = options
8
- @errors = Hash.new {|h, k| h[k] = []}
9
- @removed_mods = []
7
+ @name = name
8
+ @options = options
9
+ @errors = Hash.new {|h, k| h[k] = {}}
10
+ @unfiltered = []
11
+ @installed = []
12
+ @suggestions = []
10
13
  @environment = Puppet::Node::Environment.new(options[:environment])
11
14
  end
12
15
 
13
16
  def run
14
- if module_installed?
15
- uninstall
16
- else
17
- @errors[@name] << "Module #{@name} is not installed"
17
+ results = {
18
+ :module_name => @name,
19
+ :requested_version => @version,
20
+ }
21
+
22
+ begin
23
+ find_installed_module
24
+ validate_module
25
+ FileUtils.rm_rf(@installed.first.path, :secure => true)
26
+
27
+ results[:affected_modules] = @installed
28
+ results[:result] = :success
29
+ rescue ModuleToolError => err
30
+ results[:error] = {
31
+ :oneline => err.message,
32
+ :multiline => err.multiline,
33
+ }
34
+ rescue => e
35
+ results[:error] = {
36
+ :oneline => e.message,
37
+ :multiline => e.respond_to?(:multiline) ? e.multiline : [e.to_s, e.backtrace].join("\n")
38
+ }
39
+ ensure
40
+ results[:result] ||= :failure
18
41
  end
19
- { :removed_mods => @removed_mods, :errors => @errors, :options => @options }
42
+
43
+ results
20
44
  end
21
45
 
22
46
  private
23
47
 
24
- def version_match?(mod)
25
- if @options[:version]
26
- mod.version == @options[:version]
27
- else
28
- true
48
+ def find_installed_module
49
+ @environment.modules_by_path.values.flatten.each do |mod|
50
+ mod_name = (mod.forge_name || mod.name).gsub('/', '-')
51
+ if mod_name == @name
52
+ @unfiltered << {
53
+ :name => mod_name,
54
+ :version => mod.version,
55
+ :path => mod.modulepath,
56
+ }
57
+ if @options[:version] && mod.version
58
+ next unless SemVer[@options[:version]].include?(SemVer.new(mod.version))
59
+ end
60
+ @installed << mod
61
+ elsif mod_name =~ /#{@name}/
62
+ @suggestions << mod_name
63
+ end
29
64
  end
30
- end
31
65
 
32
- def module_installed?
33
- @environment.module(@name)
66
+ if @installed.length > 1
67
+ raise MultipleInstalledError,
68
+ :action => :uninstall,
69
+ :module_name => @name,
70
+ :installed_modules => @installed.sort_by { |mod| @environment.modulepath.index(mod.modulepath) }
71
+ elsif @installed.empty?
72
+ if @unfiltered.empty?
73
+ raise NotInstalledError,
74
+ :action => :uninstall,
75
+ :suggestions => @suggestions,
76
+ :module_name => @name
77
+ else
78
+ raise NoVersionMatchesError,
79
+ :installed_modules => @unfiltered.sort_by { |mod| @environment.modulepath.index(mod[:path]) },
80
+ :version_range => @options[:version],
81
+ :module_name => @name
82
+ end
83
+ end
34
84
  end
35
85
 
36
- def has_changes?
37
- Puppet::Module::Tool::Applications::Checksummer.run(@module.path)
38
- end
86
+ def validate_module
87
+ mod = @installed.first
39
88
 
40
- def uninstall
41
- # TODO: #11803 Check for broken dependencies before uninstalling modules.
42
- @environment.modules_by_path.each do |path, modules|
43
- modules.each do |mod|
44
- if mod.name == @name
45
- unless version_match?(mod)
46
- @errors[@name] << "Installed version of #{mod.name} (v#{mod.version}) does not match version range"
47
- end
48
-
49
- if @errors[@name].empty?
50
- FileUtils.rm_rf(mod.path)
51
- @removed_mods << mod
52
- end
53
- end
54
- end
89
+ if !@options[:force] && mod.has_metadata? && mod.has_local_changes?
90
+ raise LocalChangesError,
91
+ :action => :uninstall,
92
+ :module_name => (mod.forge_name || mod.name).gsub('/', '-'),
93
+ :requested_version => @options[:version],
94
+ :installed_version => mod.version
95
+ end
96
+
97
+ if !@options[:force] && !mod.required_by.empty?
98
+ raise ModuleIsRequiredError,
99
+ :module_name => (mod.forge_name || mod.name).gsub('/', '-'),
100
+ :required_by => mod.required_by,
101
+ :requested_version => @options[:version],
102
+ :installed_version => mod.version
55
103
  end
56
104
  end
57
105
  end