PageRenderTime 39ms CodeModel.GetById 0ms RepoModel.GetById 0ms app.codeStats 0ms

/cookbooks/python/providers/pip.rb

https://bitbucket.org/jimrhoskins/bam
Ruby | 170 lines | 115 code | 20 blank | 35 comment | 21 complexity | ce330ccf00dc2ad971d09794eb8134cd MD5 | raw file
Possible License(s): Apache-2.0
  1. #
  2. # Author:: Seth Chisamore <schisamo@opscode.com>
  3. # Cookbook Name:: python
  4. # Provider:: pip
  5. #
  6. # Copyright:: 2011, Opscode, Inc <legal@opscode.com>
  7. #
  8. # Licensed under the Apache License, Version 2.0 (the "License");
  9. # you may not use this file except in compliance with the License.
  10. # You may obtain a copy of the License at
  11. #
  12. # http://www.apache.org/licenses/LICENSE-2.0
  13. #
  14. # Unless required by applicable law or agreed to in writing, software
  15. # distributed under the License is distributed on an "AS IS" BASIS,
  16. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  17. # See the License for the specific language governing permissions and
  18. # limitations under the License.
  19. #
  20. require 'chef/mixin/shell_out'
  21. require 'chef/mixin/language'
  22. include Chef::Mixin::ShellOut
  23. def whyrun_supported?
  24. true
  25. end
  26. # the logic in all action methods mirror that of
  27. # the Chef::Provider::Package which will make
  28. # refactoring into core chef easy
  29. action :install do
  30. # If we specified a version, and it's not the current version, move to the specified version
  31. if @new_resource.version != nil && @new_resource.version != @current_resource.version
  32. install_version = @new_resource.version
  33. # If it's not installed at all, install it
  34. elsif @current_resource.version == nil
  35. install_version = candidate_version
  36. end
  37. if install_version
  38. description = "install package #{@new_resource} version #{install_version}"
  39. converge_by(description) do
  40. Chef::Log.info("Installing #{@new_resource} version #{install_version}")
  41. status = install_package(install_version)
  42. if status
  43. @new_resource.updated_by_last_action(true)
  44. end
  45. end
  46. end
  47. end
  48. action :upgrade do
  49. if @current_resource.version != candidate_version
  50. orig_version = @current_resource.version || "uninstalled"
  51. description = "upgrade #{@current_resource} version from #{@current_resource.version} to #{candidate_version}"
  52. converge_by(description) do
  53. Chef::Log.info("Upgrading #{@new_resource} version from #{orig_version} to #{candidate_version}")
  54. status = upgrade_package(candidate_version)
  55. if status
  56. @new_resource.updated_by_last_action(true)
  57. end
  58. end
  59. end
  60. end
  61. action :remove do
  62. if removing_package?
  63. description = "remove package #{@new_resource}"
  64. converge_by(description) do
  65. Chef::Log.info("Removing #{@new_resource}")
  66. remove_package(@new_resource.version)
  67. @new_resource.updated_by_last_action(true)
  68. end
  69. end
  70. end
  71. def removing_package?
  72. if @current_resource.version.nil?
  73. false # nothing to remove
  74. elsif @new_resource.version.nil?
  75. true # remove any version of a package
  76. elsif @new_resource.version == @current_resource.version
  77. true # remove the version we have
  78. else
  79. false # we don't have the version we want to remove
  80. end
  81. end
  82. # these methods are the required overrides of
  83. # a provider that extends from Chef::Provider::Package
  84. # so refactoring into core Chef should be easy
  85. def load_current_resource
  86. @current_resource = Chef::Resource::PythonPip.new(@new_resource.name)
  87. @current_resource.package_name(@new_resource.package_name)
  88. @current_resource.version(nil)
  89. unless current_installed_version.nil?
  90. @current_resource.version(current_installed_version)
  91. end
  92. @current_resource
  93. end
  94. def current_installed_version
  95. @current_installed_version ||= begin
  96. delimeter = /==/
  97. version_check_cmd = "#{which_pip(@new_resource)} freeze | grep -i '^#{@new_resource.package_name}=='"
  98. # incase you upgrade pip with pip!
  99. if @new_resource.package_name.eql?('pip')
  100. delimeter = /\s/
  101. version_check_cmd = "pip --version"
  102. end
  103. p = shell_out!(version_check_cmd)
  104. p.stdout.split(delimeter)[1].strip
  105. rescue Chef::Exceptions::ShellCommandFailed
  106. rescue Mixlib::ShellOut::ShellCommandFailed
  107. end
  108. end
  109. def candidate_version
  110. @candidate_version ||= begin
  111. # `pip search` doesn't return versions yet
  112. # `pip list` may be coming soon:
  113. # https://bitbucket.org/ianb/pip/issue/197/option-to-show-what-version-would-be
  114. @new_resource.version||'latest'
  115. end
  116. end
  117. def install_package(version)
  118. # if a version isn't specified (latest), is a source archive (ex. http://my.package.repo/SomePackage-1.0.4.zip),
  119. # or from a VCS (ex. git+https://git.repo/some_pkg.git) then do not append a version as this will break the source link
  120. if version == 'latest' || @new_resource.name.downcase.start_with?('http:', 'https:') || ['git', 'hg', 'svn'].include?(@new_resource.name.downcase.split('+')[0])
  121. version = ''
  122. else
  123. version = "==#{version}"
  124. end
  125. pip_cmd('install', version)
  126. end
  127. def upgrade_package(version)
  128. @new_resource.options "#{@new_resource.options} --upgrade"
  129. install_package(version)
  130. end
  131. def remove_package(version)
  132. @new_resource.options "#{@new_resource.options} --yes"
  133. pip_cmd('uninstall')
  134. end
  135. def pip_cmd(subcommand, version='')
  136. options = { :timeout => @new_resource.timeout, :user => @new_resource.user, :group => @new_resource.group }
  137. options[:environment] = { 'HOME' => ::File.expand_path("~#{@new_resource.user}") } if @new_resource.user
  138. shell_out!("#{which_pip(@new_resource)} #{subcommand} #{@new_resource.options} #{@new_resource.name}#{version}", options)
  139. end
  140. # TODO remove when provider is moved into Chef core
  141. # this allows PythonPip to work with Chef::Resource::Package
  142. def which_pip(nr)
  143. if (nr.respond_to?("virtualenv") && nr.virtualenv)
  144. ::File.join(nr.virtualenv,'/bin/pip')
  145. elsif "#{node['python']['install_method']}".eql?("source")
  146. ::File.join("#{node['python']['prefix_dir']}","/bin/pip")
  147. else
  148. 'pip'
  149. end
  150. end