bits-installer 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/bin/bits +20 -0
- data/ext/apt/Cache.cpp +68 -0
- data/ext/apt/Cache.h +18 -0
- data/ext/apt/Package.cpp +63 -0
- data/ext/apt/Package.h +30 -0
- data/ext/apt/PackageVersion.cpp +49 -0
- data/ext/apt/PackageVersion.h +24 -0
- data/ext/apt/apt_ext.cpp +38 -0
- data/ext/apt/apt_ext.h +4 -0
- data/ext/apt/extconf.rb +12 -0
- data/lib/bits/backend/join.rb +26 -0
- data/lib/bits/backend/local.rb +24 -0
- data/lib/bits/backend.rb +9 -0
- data/lib/bits/bit.rb +33 -0
- data/lib/bits/bit_declaration.rb +143 -0
- data/lib/bits/bit_reader/local.rb +13 -0
- data/lib/bits/bit_reader.rb +7 -0
- data/lib/bits/command.rb +48 -0
- data/lib/bits/command_provider.rb +39 -0
- data/lib/bits/commands/install.rb +75 -0
- data/lib/bits/commands/remove.rb +35 -0
- data/lib/bits/commands/show.rb +49 -0
- data/lib/bits/commands/sync.rb +34 -0
- data/lib/bits/exceptions.rb +12 -0
- data/lib/bits/execute_context.rb +24 -0
- data/lib/bits/external_interface.rb +204 -0
- data/lib/bits/logging.rb +24 -0
- data/lib/bits/package.rb +27 -0
- data/lib/bits/package_proxy.rb +61 -0
- data/lib/bits/provider/apt.rb +75 -0
- data/lib/bits/provider/homebrew.rb +59 -0
- data/lib/bits/provider/portage.rb +69 -0
- data/lib/bits/provider/python.rb +86 -0
- data/lib/bits/provider.rb +77 -0
- data/lib/bits/provider_reporting.rb +24 -0
- data/lib/bits/repository.rb +118 -0
- data/lib/bits/spawn.rb +89 -0
- data/lib/bits/user.rb +27 -0
- data/lib/bits/version.rb +3 -0
- data/lib/bits.rb +156 -0
- data/lib/libexec/bits-python +157 -0
- metadata +153 -0
data/lib/bits/logging.rb
ADDED
@@ -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
|
data/lib/bits/package.rb
ADDED
@@ -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
|