Skip to content

Commit

Permalink
apt: add support for ppa.
Browse files Browse the repository at this point in the history
Add an `ppa` option to install from Ubuntu PPA.
  • Loading branch information
weakish committed May 3, 2016
1 parent 303b371 commit 45d11f8
Show file tree
Hide file tree
Showing 8 changed files with 121 additions and 57 deletions.
49 changes: 39 additions & 10 deletions lib/sprinkle/installers/apt.rb
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
module Sprinkle
module Installers
# The Apt package installer uses the +apt-get+ command to install
# packages. The apt installer has only one option which can be
# packages. The apt installer has one option which can be
# modified which is the +dependencies_only+ option. When this is
# set to true, the installer uses +build-dep+ instead of +install+
# to only build the dependencies.
#
# to only build the dependencies. If you want to install from Ubuntu
# PPA, set the `ppa` option.
#
# == Example Usage
#
# First, a simple installation of the magic_beans package:
Expand All @@ -19,23 +20,31 @@ module Installers
#
# package :magic_beans_depends do
# apt 'magic_beans_package' do
# dependencies_only true
# dependencies_only true
# end
# end
#
# Third, get magic_beans from ppa:user/ppa-name:
#
# package :magic_beans do
# apt 'magic_bean' do
# ppa 'user/ppa-name'
# end
# end
#
# As you can see, setting options is as simple as creating a
# block and calling the option as a method with the value as
# block and calling the option as a method with the value as
# its parameter.
class Apt < PackageInstaller
def initialize(parent, *packages, &block) #:nodoc:
super parent, *packages, &block
@options.reverse_merge!(:dependencies_only => false)
@options.reverse_merge!(:dependencies_only => false, :ppa => nil)
end
attributes :dependencies_only

attributes :dependencies_only, :ppa

auto_api

verify_api do
def has_apt(package)
@commands << "dpkg --status #{package} | grep \"ok installed\""
Expand All @@ -44,12 +53,32 @@ def has_apt(package)

protected

def ppa_repository_exist?(ppa) #:nodoc:
ppa_user, ppa_name = ppa.split('/')
sources_glob = ['/etc/apt/sources.list', '/etc/apt/sources.list.d/*.list']
ppa_pattern = /^deb http:\/\/ppa.launchpad.net\/#{ppa}/
Dir.glob(sources_glob).any? do |f|
open(f).any? do |line|
line =~ ppa_pattern
end
end
end

def install_commands #:nodoc:
command = @options[:dependencies_only] ? 'build-dep' : 'install'
noninteractive = "#{sudo_cmd}env DEBCONF_TERSE='yes' DEBIAN_PRIORITY='critical' DEBIAN_FRONTEND=noninteractive"
"#{noninteractive} apt-get --force-yes -qyu #{command} #{@packages.join(' ')}"
if @options[:ppa]
ppa = @options[:ppa]
unless ppa_repository_exist?(ppa)
add_ppa = "#{sudo_cmd}add-apt-repository ppa:#{ppa}"
apt_update = "#{noninteractive} apt-get update"
ppa_cmd = "#{add_ppa} && #{apt_update} &&"
end
end
"#{ppa_cmd} #{noninteractive} apt-get --force-yes -qyu #{command} #{@packages.join(' ')}"
end


end
end
end
17 changes: 14 additions & 3 deletions lib/sprinkle/installers/deb.rb
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,25 @@ class Deb < PackageInstaller
# install deb packages from an external URL
# :call-seq:
# deb(*package_urls)
auto_api :deb
api do
def deb(url, options = {}, &block)
install Deb.new(self, url, options, &block)
end
end

attr_accessor :url #:nodoc:

def initialize(parent, url, options = {}, &block) #:nodoc:
super parent, options, &block
@url = url
end

protected

def install_commands #:nodoc:
[
"wget -cq --directory-prefix=/tmp #{@packages.join(' ')}",
"dpkg -i #{@packages.collect{|p| "/tmp/#{package_name(p)}"}.join(" ")}"
"wget -cq --directory-prefix=/tmp #{@url}",
"#{sudo_cmd}dpkg -i /tmp/#{package_name(@url)}"
]
end

Expand Down
14 changes: 8 additions & 6 deletions lib/sprinkle/installers/gem.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,10 @@ module Installers
# The gem package installer installs Ruby gems.
#
# The installer has a single optional configuration: source.
# FIXME single? source code seems not agree.
# By changing source you can specify a given ruby gems
# repository from which to install.
#
#
# == Example Usage
#
# First, a simple installation of the magic_beans gem:
Expand All @@ -24,25 +25,26 @@ module Installers
# end
#
# As you can see, setting options is as simple as creating a
# block and calling the option as a method with the value as
# block and calling the option as a method with the value as
# its parameter.
class Gem < Installer

api do
def gem(name, options = {}, &block)
recommends :rubygems
install Gem.new(self, name, options, &block)
end
end

attr_accessor :gem #:nodoc:

def initialize(parent, gem, options = {}, &block) #:nodoc:
super parent, options, &block
@gem = gem
end

attributes :source, :repository, :http_proxy, :build_flags, :version
# FIXME Why is ':build_docs' not included?

protected

Expand All @@ -58,7 +60,7 @@ def install_commands #:nodoc:
cmd << " -- #{build_flags}" if option?(:build_flags)
cmd
end

end
end
end
12 changes: 6 additions & 6 deletions lib/sprinkle/installers/npm.rb
Original file line number Diff line number Diff line change
Expand Up @@ -16,26 +16,26 @@ class Npm < Installer
attr_accessor :package_name

api do
def npm(package, &block)
install Npm.new(self, package, &block)
def npm(package, options={}, &block)
install Npm.new(self, package, options, &block)
end
end

verify_api do
def has_npm(package)
@commands << "npm --global list | grep \"#{package}@\""
@commands << "npm --global list | fgrep \"#{package}@\""
end
end

def initialize(parent, package_name, &block) #:nodoc:
super parent, &block
def initialize(parent, package_name, options={}, &block) #:nodoc:
super parent, options, &block
@package_name = package_name
end

protected

def install_commands #:nodoc:
"npm install --global #{@package_name}"
"#{sudo_cmd}npm install --global #{@package_name}"
end

end
Expand Down
20 changes: 11 additions & 9 deletions lib/sprinkle/installers/replace_text.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,20 @@ module Sprinkle
module Installers
# = Replace text installer
#
# This installer replaces a text with another one in a file.
#
# This installer replaces a text matching the regex with another one in a file.
#
# == Example Usage
#
# Change ssh port in /etc/ssh/sshd_config
#
# package :magic_beans do
# replace_text 'Port 22', 'Port 2500', '/etc/ssh/sshd_config'
# replace_text 'Port [0-9]+', 'Port 2500', '/etc/ssh/sshd_config'
# end
#
# Because we use sed under the hood, the regex is extended regex.
#
# If you user has access to 'sudo' and theres a file that requires
# privileges, you can pass :sudo => true
# privileges, you can pass :sudo => true
#
# package :magic_beans do
# replace_text 'Port 22', 'Port 2500', '/etc/ssh/sshd_config', :sudo => true
Expand All @@ -25,7 +27,7 @@ module Installers
#
class ReplaceText < Installer
attr_accessor :regex, :text, :path #:nodoc:

api do
def replace_text(regex, text, path, options={}, &block)
install ReplaceText.new(self, regex, text, path, options, &block)
Expand All @@ -38,19 +40,19 @@ def initialize(parent, regex, text, path, options={}, &block) #:nodoc:
@text = text
@path = path
end

def announce
log "--> Replace '#{@regex}' with '#{@text}' in file #{@path}"
end

protected

def escape_sed_arg(s)
escape_shell_arg(s).gsub("/", "\\\\/").gsub('&', '\\\&')
end

def install_commands #:nodoc:
"#{sudo_cmd}sed -i 's/#{escape_sed_arg(@regex)}/#{escape_sed_arg(@text)}/g' #{@path}"
"#{sudo_cmd}sed -r -i 's/#{escape_sed_arg(@regex)}/#{escape_sed_arg(@text)}/g' #{@path}"
end

end
Expand Down
14 changes: 9 additions & 5 deletions lib/sprinkle/installers/source.rb
Original file line number Diff line number Diff line change
Expand Up @@ -47,12 +47,16 @@ module Installers
# source 'http://magicbeansland.com/latest-1.1.1.tar.gz' do
# prefix '/usr/local'
#
# pre :prepare { 'echo "Here we go folks."' }
# post :extract { 'echo "I believe..."' }
# pre :build { 'echo "Cross your fingers!"' }
# pre :prepare, 'echo "Here we go folks."'
# post :extract, 'echo "I believe..."'
# pre :build, 'echo "Cross your fingers!"'
# end
# end
#
# Be careful! Hooks will get logged via appending '>> LOG_FILE 2&>1'.
# Thus if you use '>> FILE' in hooks, the output won't go to the FILE
# you specified. You can use '| tee -a FILE' instead.
#
# Fourth, specifying a custom archive name because the downloaded file name
# differs from the source URL:
#
Expand Down Expand Up @@ -158,7 +162,7 @@ def build_commands #:nodoc:

def install_commands #:nodoc:
return custom_install_commands if custom_install?
[ in_build_dir(with_log("#{install_command || "make install"}",:install)) ]
[ in_build_dir(with_log("#{install_command || "#{sudo_cmd}make install"}",:install)) ]
end

def custom_install? #:nodoc:
Expand Down Expand Up @@ -189,7 +193,7 @@ def post_commands(stage) #:nodoc:
end


# dress is overriden from the base Sprinkle::Installers::Installer class so that the command changes
# dress is overridden from the base Sprinkle::Installers::Installer class so that the command changes
# directory to the build directory first. Also, the result of the command is logged.
def dress(commands, pre_or_post, stage)
chdir = "cd #{build_dir} && "
Expand Down
28 changes: 16 additions & 12 deletions lib/sprinkle/verifiers/file.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ module Verifiers
# = File Verifier
#
# Contains a verifier to check the existance of a file.
#
#
# == Example Usage
#
# verify { has_file '/etc/apache2/apache2.conf' }
Expand All @@ -17,13 +17,13 @@ module File
def has_file(path)
test "-f #{path}"
end

# Tests that the directory <tt>dir</tt> exists.
def has_directory(dir)
test "-d #{dir}"
end
# Checks that <tt>symlink</tt> is a symbolic link. If <tt>file</tt> is

# Checks that <tt>symlink</tt> is a symbolic link. If <tt>file</tt> is
# given, it checks that <tt>symlink</tt> points to <tt>file</tt>
def has_symlink(symlink, file = nil)
if file.nil?
Expand All @@ -32,25 +32,29 @@ def has_symlink(symlink, file = nil)
test "'#{file}' = `readlink #{symlink}`"
end
end

def no_file(path)
test "! -f #{path}"
end

def md5_of_file(path, md5)
test "\"`#{sudo_cmd}md5sum #{path} | cut -f1 -d' '`\" = \"#{md5}\""
end


def sha1_of_file(path, sha1)
test "\"`#{sudo_cmd}sha1sum #{path} | cut -f1 -d' '`\" = \"#{sha1}\""
end

def file_contains(path, text)
@commands << "grep '#{text}' #{path}"
@commands << "egrep '#{text}' #{path}"
end

# TODO: remove 0.9
def user_present(username)
ActiveSupport::Deprecation.warn("user_present is depreciated. Use has_user instead.")
def user_present(username)
ActiveSupport::Deprecation.warn("user_present is depreciated. Use has_user instead.")
has_user username
end

def matches_local(localfile, remotefile, mode=nil)
raise "Couldn't find local file #{localfile}" unless ::File.exists?(localfile)
require 'digest/md5'
Expand Down
Loading

0 comments on commit 45d11f8

Please sign in to comment.