bits-installer 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,24 @@
1
+ require 'log4r'
2
+
3
+ module Bits
4
+ module Logging
5
+ module ClassMethods
6
+ def setup_logging(name)
7
+ @logging_name = name
8
+ end
9
+
10
+ def log
11
+ @logging_logger ||= Log4r::Logger.new(@logging_name)
12
+ end
13
+ end
14
+
15
+ def log
16
+ self.class.log
17
+ end
18
+
19
+ def self.included(mod)
20
+ mod.extend ClassMethods
21
+ mod.setup_logging mod.to_s
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,27 @@
1
+ module Bits
2
+ class Package
3
+ attr_reader :atom, :installed, :candidate
4
+
5
+ def initialize(atom, installed, candidate)
6
+ @atom = atom
7
+ @installed = installed
8
+ @candidate = candidate
9
+ end
10
+
11
+ def installed_s
12
+ return "(not installed)" if installed.nil?
13
+ installed
14
+ end
15
+
16
+ def candidate_s
17
+ return "(no candidate)" if candidate.nil?
18
+ candidate
19
+ end
20
+
21
+ def to_s
22
+ installed_s = @installed || "(not installed)"
23
+ candidate_s = @candidate || "(no candidate)"
24
+ "<Package atom='#{@atom}' installed='#{installed_s}' candidate='#{candidate_s}'>"
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,61 @@
1
+ module Bits
2
+ # Data class used to keep track of all found ppps (package, provider, params)
3
+ # for a specific bit and the supplied criteria.
4
+ #
5
+ # This allows for eager loading and lazy lookup of if a specific atom can be
6
+ # considered as 'installed' or not.
7
+ class PackageProxy
8
+ attr_accessor :ppps, :criteria
9
+
10
+ def initialize(ppps, criteria)
11
+ @ppps = ppps
12
+ @criteria = criteria
13
+ end
14
+
15
+ # Check if the following set of parameters matches the specified criteria.
16
+ def matches_criteria?(params)
17
+ criteria.all?{|key, value| value.nil? or params[key] == value}
18
+ end
19
+
20
+ def dependencies
21
+ ppps.collect{|ppp| ppp.bit.dependencies}.flatten
22
+ end
23
+
24
+ def matching_ppps
25
+ ppps.select do |ppp|
26
+ matches_criteria? ppp.parameters
27
+ end
28
+ end
29
+
30
+ # Remove the specified package.
31
+ # The package will be removed from all matching PPPs.
32
+ def remove
33
+ ppps.each do |ppp|
34
+ ppp.provider.remove ppp.package
35
+ end
36
+ end
37
+
38
+ # Determines if the specified package is installed or not.
39
+ def installed?
40
+ ppps.any? do |ppp|
41
+ not ppp.package.installed.nil?
42
+ end
43
+ end
44
+
45
+ def installed
46
+ ppps.select do |ppp|
47
+ not ppp.package.installed.nil?
48
+ end
49
+ end
50
+
51
+ def providers
52
+ ppps.map do |ppp|
53
+ ppp.provider
54
+ end
55
+ end
56
+
57
+ def providers_s
58
+ providers.map(&:provider_id).join ', '
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,75 @@
1
+ require 'bits/provider'
2
+ require 'bits/provider_reporting'
3
+ require 'bits/package'
4
+ require 'bits/logging'
5
+ require 'bits/spawn'
6
+ require 'bits/exceptions'
7
+
8
+ require 'bits/command_provider'
9
+
10
+ HAS_APT_NATIVE_EXT = begin
11
+ require 'apt/apt_ext'
12
+ true
13
+ rescue LoadError
14
+ false
15
+ end
16
+
17
+ module Bits
18
+ define_provider :apt, \
19
+ :desc => "Provides interface for Debian APT" \
20
+ do
21
+ include Bits::Logging
22
+ include Bits::CommandProvider
23
+ include Bits::ProviderReporting
24
+
25
+ APT_GET = 'apt-get'
26
+
27
+ def self.check
28
+ unless HAS_APT_NATIVE_EXT
29
+ check_error "APT native extension could not be loaded"
30
+ return false
31
+ end
32
+
33
+ unless Apt::initialize
34
+ check_error "APT native extension could not be initialized"
35
+ return false
36
+ end
37
+
38
+ log.debug "APT native extension is available"
39
+ true
40
+ end
41
+
42
+ def query(atom)
43
+ result = Apt::Cache::policy(atom)
44
+
45
+ raise MissingPackage.new atom if result.empty?
46
+ raise "Too many packages '#{atom}'" if result.size > 1
47
+
48
+ package = result[0]
49
+
50
+ current = nil
51
+ candidate = nil
52
+
53
+ current = package.current.version if package.current
54
+ candidate = package.candidate.version if package.candidate
55
+
56
+ return Bits::Package.new(package.name, current, candidate)
57
+ end
58
+
59
+ def install(package)
60
+ execute do
61
+ unless run [APT_GET, 'install', package.atom], :superuser => true
62
+ raise "Could not install package '#{package.atom}'"
63
+ end
64
+ end
65
+ end
66
+
67
+ def remove(package)
68
+ execute do
69
+ unless run [APT_GET, 'remove', package.atom], :superuser => true
70
+ raise "Could not remove package '#{package.atom}'"
71
+ end
72
+ end
73
+ end
74
+ end
75
+ end
@@ -0,0 +1,59 @@
1
+ $old = Array.new $:
2
+
3
+ HAS_HOMEBREW = begin
4
+ $: << '/usr/local/Library/Homebrew'
5
+ require 'global'
6
+ require 'formula'
7
+ true
8
+ rescue LoadError
9
+ $:.replace $old
10
+ false
11
+ end
12
+
13
+ module Bits
14
+ define_provider :homebrew, \
15
+ :desc => "Provides interface for Homebrew" \
16
+ do
17
+ include Bits::Logging
18
+ include Bits::CommandProvider
19
+ include Bits::ProviderReporting
20
+
21
+ BREW = 'apt-get'
22
+
23
+ def self.check
24
+ unless HAS_HOMEBREW
25
+ check_error "homebrew is not available on this system"
26
+ return false
27
+ end
28
+
29
+ log.debug "homebrew is available"
30
+ true
31
+ end
32
+
33
+ def query(atom)
34
+ begin
35
+ f = Formula.factory(atom)
36
+ rescue FormulaUnavailableError
37
+ raise MissingPackage.new(atom)
38
+ end
39
+
40
+ Bits::Package.new(atom, f.installed_version, f.version)
41
+ end
42
+
43
+ def install(package)
44
+ execute do
45
+ unless run [BREW, 'install', package.atom]
46
+ raise "Could not install package '#{package.atom}'"
47
+ end
48
+ end
49
+ end
50
+
51
+ def remove(package)
52
+ execute do
53
+ unless spawn [BREW, 'uninstall', package.atom]
54
+ raise "Could not remove package '#{package.atom}'"
55
+ end
56
+ end
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,69 @@
1
+ require 'bits/provider'
2
+ require 'bits/provider_reporting'
3
+ require 'bits/command_provider'
4
+ require 'bits/package'
5
+ require 'bits/logging'
6
+ require 'bits/spawn'
7
+
8
+ require 'json'
9
+
10
+ module Bits
11
+ define_provider :portage, \
12
+ :desc => "Provides interface to Gentoo Portage" \
13
+ do
14
+ include Bits::Logging
15
+ include Bits::CommandProvider
16
+ include Bits::ExternalInterface
17
+ include Bits::ProviderReporting
18
+
19
+ # bridge command
20
+ EMERGE = 'emerge'
21
+
22
+ def self.check
23
+ unless self.check_command [EMERGE, '--version'], "EMERGE"
24
+ check_error "Could not execute '#{EMERGE} --version'"
25
+ return false
26
+ end
27
+
28
+ unless self.setup_interface :python, :capabilities => [:portage]
29
+ check_error "Could not setup require python interface"
30
+ return false
31
+ end
32
+
33
+ log.debug "portage is available"
34
+ true
35
+ end
36
+
37
+ def initialize(ns)
38
+ super ns
39
+ @client = interfaces[:python]
40
+ end
41
+
42
+ def query(package_name)
43
+ type, info = @client.request :portage_info, :package => package_name
44
+ raise "Expected info response but got: #{type}" unless type == :info
45
+
46
+ name = info['name']
47
+ installed = info['installed']
48
+ candidate = info['candidate']
49
+
50
+ return Bits::Package.new(name, installed, candidate)
51
+ end
52
+
53
+ def install(package)
54
+ execute do
55
+ unless run [EMERGE, package.atom]
56
+ raise "Could not install package '#{package.atom}'"
57
+ end
58
+ end
59
+ end
60
+
61
+ def remove(package)
62
+ execute do
63
+ unless run [EMERGE, "--unmerge", package.atom]
64
+ raise "Could not remove package '#{package.atom}'"
65
+ end
66
+ end
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,86 @@
1
+ require 'bits/provider'
2
+ require 'bits/provider_reporting'
3
+ require 'bits/command_provider'
4
+ require 'bits/spawn'
5
+ require 'bits/package'
6
+ require 'bits/logging'
7
+ require 'bits/exceptions'
8
+
9
+ require 'bits/external_interface'
10
+
11
+ require "xmlrpc/client"
12
+
13
+ module Bits
14
+ define_provider :python,
15
+ :desc => "Provides interface for Python Packages" \
16
+ do
17
+ include Bits::Logging
18
+ include Bits::CommandProvider
19
+ include Bits::ExternalInterface
20
+ include Bits::ProviderReporting
21
+
22
+ PIP = 'pip'
23
+ INDEX = 'https://pypi.python.org/pypi'
24
+
25
+ def self.check
26
+ unless self.check_command [PIP, '--version'], 'PIP'
27
+ check_error "Could not execute '#{PIP} --version'"
28
+ return false
29
+ end
30
+
31
+ unless self.setup_interface :python, :capabilities => [:pkg_resources]
32
+ check_error "Could not setup require python interface"
33
+ return false
34
+ end
35
+
36
+ log.debug "python extensions is available"
37
+ true
38
+ end
39
+
40
+ def initialize(ns)
41
+ super ns
42
+ @client = XMLRPC::Client.new_from_uri(INDEX)
43
+ @client.http_header_extra = {'Content-Type' => 'text/xml'}
44
+ @python = self.class.interfaces[:python]
45
+ end
46
+
47
+ def get_installed_version(package_atom)
48
+ type, response = @python.request :python_info, :atom => package_atom
49
+ return nil if type == :missing_atom
50
+ response['installed']
51
+ end
52
+
53
+ def get_candidate_version(package_atom)
54
+ begin
55
+ result = @client.call(:package_releases, package_atom)
56
+ rescue SocketError
57
+ return nil
58
+ end
59
+
60
+ raise MissingPackage.new package_atom if result.empty?
61
+ return result[0]
62
+ end
63
+
64
+ def query(package_atom)
65
+ candidate = get_candidate_version package_atom
66
+ current = get_installed_version package_atom
67
+ return Bits::Package.new(package_atom, current, candidate)
68
+ end
69
+
70
+ def install(package)
71
+ execute do
72
+ unless run [PIP, 'install', package.atom], :superuser => true
73
+ raise "Could not install package '#{package.atom}'"
74
+ end
75
+ end
76
+ end
77
+
78
+ def remove(package)
79
+ execute do
80
+ unless run [PIP, 'uninstall', package.atom], :superuser => true
81
+ raise "Could not remove package '#{package.atom}'"
82
+ end
83
+ end
84
+ end
85
+ end
86
+ end
@@ -0,0 +1,77 @@
1
+ require 'bits/execute_context'
2
+
3
+ module Bits
4
+ class Provider
5
+ class << self
6
+ # Override to provide custom static initialization code for provider.
7
+ # Should return true if the specified provider can be used in this system.
8
+ def check
9
+ true
10
+ end
11
+ end
12
+
13
+ attr_reader :ns
14
+
15
+ def initialize(ns)
16
+ @ns = ns
17
+ end
18
+
19
+ def query(atom)
20
+ raise "not implemented: query"
21
+ end
22
+
23
+ def install(atom)
24
+ raise "not implemented: install"
25
+ end
26
+
27
+ def remove(atom)
28
+ raise "not implemented: remove"
29
+ end
30
+
31
+ def execute(&block)
32
+ raise "Missing user from namespace" if ns[:user].nil?
33
+ context = ExecuteContext.new ns[:user]
34
+ return context.instance_eval(&block)
35
+ end
36
+ end
37
+
38
+ class << self
39
+ def providers
40
+ @providers ||= {}
41
+ end
42
+
43
+ def define_provider(provider_id, params={}, &block)
44
+ if providers[provider_id]
45
+ raise "Provider already defined: #{provider_id}"
46
+ end
47
+
48
+ desc = params[:desc] || "(no description)"
49
+
50
+ klass = Class.new Provider do
51
+ @provider_id = provider_id
52
+ @name = provider_id.to_s.capitalize
53
+ @desc = desc
54
+
55
+ def to_s
56
+ self.class.to_s
57
+ end
58
+
59
+ def provider_id
60
+ self.class.provider_id
61
+ end
62
+
63
+ class << self
64
+ attr_reader :provider_id, :desc, :name
65
+
66
+ def to_s
67
+ "#<Bits::Provider::#{@name}>"
68
+ end
69
+ end
70
+ end
71
+
72
+ klass.class_eval(&block)
73
+
74
+ providers[provider_id] = klass
75
+ end
76
+ end
77
+ end