bits-installer 0.1.1 → 0.3.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/lib/bits.rb +69 -58
- data/lib/bits/cache.rb +67 -0
- data/lib/bits/command.rb +18 -4
- data/lib/bits/commands/install.rb +10 -43
- data/lib/bits/commands/manifest.rb +71 -0
- data/lib/bits/commands/provider_query.rb +43 -0
- data/lib/bits/commands/provider_sync.rb +49 -0
- data/lib/bits/commands/show.rb +1 -1
- data/lib/bits/commands/sync.rb +10 -7
- data/lib/bits/exceptions.rb +21 -0
- data/lib/bits/execute_context.rb +1 -0
- data/lib/bits/external_interface.rb +14 -8
- data/lib/bits/installer_mixin.rb +96 -0
- data/lib/bits/package_proxy.rb +3 -2
- data/lib/bits/provider.rb +9 -1
- data/lib/bits/provider/apt.rb +10 -0
- data/lib/bits/provider/homebrew.rb +23 -22
- data/lib/bits/provider/portage.rb +2 -2
- data/lib/bits/provider/python.rb +89 -15
- data/lib/bits/provider/rubygems.rb +88 -0
- data/lib/bits/repository.rb +1 -1
- data/lib/bits/version.rb +1 -1
- data/lib/libexec/bits-python +10 -10
- data/lib/libexec/bits-ruby +198 -0
- metadata +9 -2
data/lib/bits.rb
CHANGED
@@ -1,40 +1,44 @@
|
|
1
1
|
require 'optparse'
|
2
2
|
|
3
|
-
require 'bits/backend/local'
|
4
3
|
require 'bits/backend/join'
|
4
|
+
require 'bits/backend/local'
|
5
|
+
require 'bits/external_interface'
|
6
|
+
require 'bits/logging'
|
5
7
|
require 'bits/package'
|
6
8
|
require 'bits/repository'
|
9
|
+
require 'bits/user'
|
7
10
|
|
8
11
|
require 'bits/commands/install'
|
9
12
|
require 'bits/commands/remove'
|
13
|
+
require 'bits/commands/setup'
|
10
14
|
require 'bits/commands/show'
|
11
15
|
require 'bits/commands/sync'
|
12
|
-
require 'bits/commands/
|
16
|
+
require 'bits/commands/query'
|
17
|
+
require 'bits/commands/manifest'
|
18
|
+
require 'bits/commands/provider_query'
|
19
|
+
require 'bits/commands/provider_sync'
|
13
20
|
|
14
|
-
require 'bits/provider/python'
|
15
21
|
require 'bits/provider/apt'
|
16
|
-
require 'bits/provider/portage'
|
17
22
|
require 'bits/provider/homebrew'
|
18
|
-
|
19
|
-
require 'bits/
|
20
|
-
require 'bits/
|
23
|
+
require 'bits/provider/portage'
|
24
|
+
require 'bits/provider/python'
|
25
|
+
require 'bits/provider/rubygems'
|
21
26
|
|
22
27
|
module Bits
|
23
28
|
class << self
|
29
|
+
DEFAULT_COMMAND = 'manifest'
|
30
|
+
|
24
31
|
def parse_options(args)
|
25
32
|
ns = {}
|
26
33
|
|
27
|
-
|
28
|
-
|
29
|
-
|
34
|
+
avail_commands = Bits.commands.values.sort_by{|c| c.command_id.to_s}
|
35
|
+
avail_providers = Bits.providers.values.sort_by{|p| p.provider_id.to_s}
|
36
|
+
|
37
|
+
commands = Hash.new
|
30
38
|
|
31
39
|
global = OptionParser.new do |global_opts|
|
32
40
|
global_opts.banner = "Usage: bits <command> [options]"
|
33
41
|
|
34
|
-
global_opts.on("-v", "--[no-]verbose", "Run verbosely") do |v|
|
35
|
-
ns[:verbose] = v
|
36
|
-
end
|
37
|
-
|
38
42
|
global_opts.on("-d", "--debug", "Enable debug logging") do |v|
|
39
43
|
@log.level = Log4r::DEBUG
|
40
44
|
end
|
@@ -42,91 +46,94 @@ module Bits
|
|
42
46
|
global_opts.separator ""
|
43
47
|
global_opts.separator "Available commands:"
|
44
48
|
|
45
|
-
|
46
|
-
global_opts.separator " #{klass.
|
47
|
-
|
49
|
+
avail_commands.each do |klass|
|
50
|
+
global_opts.separator " #{klass.switch}: #{klass.desc}"
|
51
|
+
commands[klass.switch] = klass
|
48
52
|
end
|
49
53
|
|
50
|
-
|
51
|
-
if provider_class.check
|
52
|
-
available_providers << provider_class
|
53
|
-
else
|
54
|
-
unavailable_providers << provider_class
|
55
|
-
end
|
56
|
-
end
|
54
|
+
global_opts.separator ""
|
57
55
|
|
58
56
|
global_opts.separator "Providers:"
|
59
57
|
|
60
|
-
|
61
|
-
global_opts.separator " #{
|
62
|
-
end
|
63
|
-
|
64
|
-
global_opts.separator "Unavailable providers:"
|
65
|
-
unavailable_providers.each do |klass|
|
66
|
-
global_opts.separator " #{klass.provider_id}: #{klass.last_check_error}"
|
58
|
+
avail_providers.each do |klass|
|
59
|
+
global_opts.separator " #{klass.provider_id}: #{klass.desc}"
|
67
60
|
end
|
68
61
|
end
|
69
62
|
|
70
63
|
global.order!
|
71
64
|
command = ARGV.shift
|
72
65
|
|
66
|
+
checked_providers = avail_providers.select do |klass|
|
67
|
+
@log.debug "Checking provider: #{klass.provider_id}"
|
68
|
+
klass.check
|
69
|
+
end
|
70
|
+
|
71
|
+
command = DEFAULT_COMMAND if command.nil?
|
72
|
+
|
73
73
|
if command.nil? then
|
74
74
|
$stderr.puts global.help
|
75
75
|
exit 0
|
76
76
|
end
|
77
77
|
|
78
|
-
|
79
|
-
|
80
|
-
if subcommands[command].nil? then
|
78
|
+
if commands[command].nil? then
|
81
79
|
$stderr.puts "No such command: #{command}"
|
82
80
|
$stderr.puts global.help
|
83
81
|
exit 0
|
84
82
|
end
|
85
83
|
|
86
|
-
|
87
|
-
|
84
|
+
bits_dir = setup_bits_dir
|
85
|
+
repo_dir = setup_repo_dir bits_dir
|
86
|
+
backend = setup_backend repo_dir
|
88
87
|
|
89
|
-
|
90
|
-
|
88
|
+
ns[:user] = setup_user
|
89
|
+
ns[:bits_dir] = bits_dir
|
90
|
+
ns[:repo_dir] = repo_dir
|
91
|
+
|
92
|
+
providers = checked_providers.collect do |klass|
|
93
|
+
provider = klass.new ns
|
94
|
+
provider.setup
|
95
|
+
provider
|
91
96
|
end
|
92
97
|
|
93
|
-
|
98
|
+
repository = Bits::Repository.new(providers, backend)
|
94
99
|
|
95
|
-
ns[:
|
96
|
-
ns[:
|
100
|
+
ns[:providers] = providers
|
101
|
+
ns[:repository] = repository
|
97
102
|
|
103
|
+
command_klass = commands[command]
|
98
104
|
command = command_klass.new ns
|
99
|
-
providers = setup_providers available_providers, ns
|
100
|
-
backend = setup_backend ns
|
101
105
|
|
102
|
-
|
106
|
+
command_parser = OptionParser.new do |opts|
|
107
|
+
command.setup opts
|
108
|
+
end
|
109
|
+
|
110
|
+
command_parser.order!
|
103
111
|
|
104
|
-
return ARGV, command
|
112
|
+
return ARGV, command, command_parser
|
105
113
|
end
|
106
114
|
|
107
|
-
|
108
|
-
def setup_local_repository_dir(ns)
|
115
|
+
def setup_bits_dir
|
109
116
|
home = ENV['HOME']
|
110
117
|
raise "HOME environment variable not defined" if home.nil?
|
111
|
-
File.join home, '.bits'
|
118
|
+
bits_dir = File.join home, '.bits'
|
119
|
+
FileUtils.mkdir_p bits_dir unless File.directory? bits_dir
|
120
|
+
bits_dir
|
121
|
+
end
|
122
|
+
|
123
|
+
# Setup the path to the local repository directory.
|
124
|
+
def setup_repo_dir(bits_dir)
|
125
|
+
File.join bits_dir, 'bits'
|
112
126
|
end
|
113
127
|
|
114
128
|
def setup_logging
|
115
129
|
log = Log4r::Logger.new 'Bits'
|
116
130
|
log.outputters << Log4r::Outputter.stdout
|
117
|
-
log.level =
|
131
|
+
log.level = Log4r::INFO
|
118
132
|
log
|
119
133
|
end
|
120
134
|
|
121
|
-
def
|
122
|
-
available_providers.collect do |provider_class|
|
123
|
-
provider_class.new ns
|
124
|
-
end
|
125
|
-
end
|
126
|
-
|
127
|
-
def setup_backend(ns)
|
135
|
+
def setup_backend(local_dir)
|
128
136
|
cwd_dir = File.join Dir.pwd, 'bits'
|
129
|
-
local_dir = ns[:local_repository_dir]
|
130
137
|
|
131
138
|
backends = Array.new
|
132
139
|
|
@@ -139,10 +146,14 @@ module Bits
|
|
139
146
|
def main(args)
|
140
147
|
@log = setup_logging
|
141
148
|
|
142
|
-
args, command = parse_options(args)
|
149
|
+
args, command, command_parser = parse_options(args)
|
143
150
|
|
144
151
|
begin
|
145
152
|
command.entry args
|
153
|
+
rescue InvalidArgument => e
|
154
|
+
$stderr.puts "Argument Error: #{e}"
|
155
|
+
$stderr.puts command_parser.help
|
156
|
+
return 1
|
146
157
|
ensure
|
147
158
|
Bits::ExternalInterface.close_interfaces
|
148
159
|
end
|
data/lib/bits/cache.rb
ADDED
@@ -0,0 +1,67 @@
|
|
1
|
+
require 'fileutils'
|
2
|
+
|
3
|
+
module Bits::Cache
|
4
|
+
class FileCache
|
5
|
+
attr_reader :cache
|
6
|
+
|
7
|
+
def initialize(path)
|
8
|
+
@path = path
|
9
|
+
@cache = Hash.new
|
10
|
+
end
|
11
|
+
|
12
|
+
def bucket_for(bucket_name)
|
13
|
+
bucket = cache[bucket_name]
|
14
|
+
return bucket unless bucket.nil?
|
15
|
+
cache[bucket_name] = load_bucket bucket_name
|
16
|
+
end
|
17
|
+
|
18
|
+
def []=(key, value)
|
19
|
+
bucket = bucket_for(bucket_name key)
|
20
|
+
bucket[key] = value
|
21
|
+
end
|
22
|
+
|
23
|
+
def [](key)
|
24
|
+
bucket = bucket_for(bucket_name key)
|
25
|
+
return nil if bucket.nil?
|
26
|
+
bucket[key]
|
27
|
+
end
|
28
|
+
|
29
|
+
def set(content)
|
30
|
+
content.each do |key, value|
|
31
|
+
self[key] = value
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def save
|
36
|
+
FileUtils.mkdir_p @path unless File.directory? @path
|
37
|
+
|
38
|
+
@cache.each do |bucket_name, bucket|
|
39
|
+
path = File.join @path, "#{bucket_name}.yml"
|
40
|
+
|
41
|
+
File.open path, 'w' do |f|
|
42
|
+
YAML.dump bucket, f
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def bucket_name(string)
|
48
|
+
string[0..1].each_byte.map { |b| sprintf("%02x",b) }.join
|
49
|
+
end
|
50
|
+
|
51
|
+
private
|
52
|
+
|
53
|
+
def load_bucket(bucket_name)
|
54
|
+
path = File.join @path, "#{bucket_name}.yml"
|
55
|
+
|
56
|
+
return {} unless File.file? path
|
57
|
+
|
58
|
+
File.open path do |f|
|
59
|
+
return YAML.load_file f
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def setup_cache(directory, cache_id)
|
65
|
+
FileCache.new File.join(directory, cache_id.to_s)
|
66
|
+
end
|
67
|
+
end
|
data/lib/bits/command.rb
CHANGED
@@ -5,12 +5,16 @@ module Bits
|
|
5
5
|
class Command
|
6
6
|
attr_reader :ns
|
7
7
|
|
8
|
+
def initialize(ns)
|
9
|
+
@ns = ns
|
10
|
+
end
|
11
|
+
|
8
12
|
def setup(opts)
|
9
13
|
raise "not implemented: setup"
|
10
14
|
end
|
11
15
|
|
12
|
-
def
|
13
|
-
|
16
|
+
def entry(args)
|
17
|
+
raise "not implemented: entry"
|
14
18
|
end
|
15
19
|
end
|
16
20
|
|
@@ -25,17 +29,27 @@ module Bits
|
|
25
29
|
end
|
26
30
|
|
27
31
|
desc = params[:desc] || "(no description)"
|
32
|
+
switch = params[:switch] || command_id.to_s
|
28
33
|
|
29
34
|
klass = Class.new(Command) do
|
30
35
|
@command_id = command_id
|
31
36
|
@name = command_id.to_s.capitalize
|
32
37
|
@desc = desc
|
38
|
+
@switch = switch
|
39
|
+
|
40
|
+
def switch
|
41
|
+
self.class.switch
|
42
|
+
end
|
43
|
+
|
44
|
+
def to_s
|
45
|
+
self.class.to_s
|
46
|
+
end
|
33
47
|
|
34
48
|
class << self
|
35
|
-
attr_reader :command_id, :name, :desc
|
49
|
+
attr_reader :command_id, :name, :desc, :switch
|
36
50
|
|
37
51
|
def to_s
|
38
|
-
"Bits::#{@name}"
|
52
|
+
"Bits::Command::#{@name}"
|
39
53
|
end
|
40
54
|
end
|
41
55
|
end
|
@@ -1,24 +1,25 @@
|
|
1
1
|
require 'bits/command'
|
2
2
|
require 'bits/logging'
|
3
|
-
|
4
|
-
require 'highline'
|
3
|
+
require 'bits/installer_mixin'
|
5
4
|
|
6
5
|
module Bits
|
7
|
-
define_command :install,
|
6
|
+
define_command :install, \
|
7
|
+
:desc => 'Install a package' \
|
8
|
+
do
|
8
9
|
include Bits::Logging
|
10
|
+
include Bits::InstallerMixin
|
9
11
|
|
10
12
|
def setup(opts)
|
11
13
|
ns[:force] = false
|
12
14
|
ns[:compiled] = nil
|
13
15
|
|
14
|
-
opts.banner = "Usage: bits
|
16
|
+
opts.banner = "Usage: bits #{switch} <bit>"
|
17
|
+
|
15
18
|
opts.on('--[no-]compiled', "Insist on installing an already compiled variant or not") do |v|
|
16
19
|
ns[:compiled] = v
|
17
20
|
end
|
18
21
|
|
19
|
-
opts
|
20
|
-
ns[:force] = v
|
21
|
-
end
|
22
|
+
setup_installer_opts opts
|
22
23
|
end
|
23
24
|
|
24
25
|
def entry(args)
|
@@ -35,42 +36,8 @@ module Bits
|
|
35
36
|
:compiled => ns[:compiled]
|
36
37
|
}
|
37
38
|
|
38
|
-
|
39
|
-
|
40
|
-
if p.installed? and not ns[:force]
|
41
|
-
log.info "Already installed '#{atom}' using provider(s): #{p.providers_s}"
|
42
|
-
return 0
|
43
|
-
end
|
44
|
-
|
45
|
-
matching = p.matching_ppps
|
46
|
-
|
47
|
-
raise "No matching PPP could be found" if matching.empty?
|
48
|
-
|
49
|
-
ppp = pick_one atom, matching
|
50
|
-
|
51
|
-
install_ppp atom, ppp
|
52
|
-
return 0
|
53
|
-
end
|
54
|
-
|
55
|
-
def pick_one(atom, matching)
|
56
|
-
return matching[0] if matching.size == 1
|
57
|
-
|
58
|
-
hl = HighLine.new $stdin
|
59
|
-
|
60
|
-
hl.choose do |menu|
|
61
|
-
menu.prompt = "Which provider would you like to install '#{atom}' with?"
|
62
|
-
matching.each do |match|
|
63
|
-
menu.choice(match.provider.provider_id) { match }
|
64
|
-
end
|
65
|
-
end
|
66
|
-
end
|
67
|
-
|
68
|
-
def install_ppp(atom, ppp)
|
69
|
-
provider = ppp.provider
|
70
|
-
package = ppp.package
|
71
|
-
|
72
|
-
log.info "Installing '#{atom}' using provider: #{provider.provider_id}"
|
73
|
-
provider.install package
|
39
|
+
package = repository.find_package atom, criteria
|
40
|
+
install_package package, force=ns[:force]
|
74
41
|
end
|
75
42
|
end
|
76
43
|
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
require 'bits/command'
|
2
|
+
require 'bits/logging'
|
3
|
+
require 'bits/installer_mixin'
|
4
|
+
require 'yaml'
|
5
|
+
|
6
|
+
module Bits
|
7
|
+
define_command :manifest, :desc => 'Run a manifest (this is the default action)' do
|
8
|
+
include Bits::Logging
|
9
|
+
include Bits::InstallerMixin
|
10
|
+
|
11
|
+
BITS_MANIFEST = "Bits"
|
12
|
+
|
13
|
+
def setup(opts)
|
14
|
+
ns[:compiled] = nil
|
15
|
+
|
16
|
+
opts.banner = "Usage: bits manifest [path]"
|
17
|
+
|
18
|
+
setup_installer_opts opts
|
19
|
+
end
|
20
|
+
|
21
|
+
def entry(args)
|
22
|
+
if args.empty? then
|
23
|
+
path = File.join Dir.pwd, BITS_MANIFEST
|
24
|
+
else
|
25
|
+
path = args.first
|
26
|
+
end
|
27
|
+
|
28
|
+
raise "No manifest in path: #{path}" unless File.file? path
|
29
|
+
|
30
|
+
manifest = YAML.load File.new(path)
|
31
|
+
|
32
|
+
unless manifest.kind_of? Hash
|
33
|
+
raise "Manifest is not of type Hash: #{path}"
|
34
|
+
end
|
35
|
+
|
36
|
+
depends = manifest[:depends]
|
37
|
+
|
38
|
+
criteria = {
|
39
|
+
:compiled => ns[:compiled]
|
40
|
+
}
|
41
|
+
|
42
|
+
log.info "Running manifest: #{path}"
|
43
|
+
|
44
|
+
unless depends.nil?
|
45
|
+
begin
|
46
|
+
packages = resolve_packages depends, criteria
|
47
|
+
rescue Bits::MissingDependencies => e
|
48
|
+
puts "Missing Dependencies:"
|
49
|
+
|
50
|
+
e.missing.each do |m|
|
51
|
+
puts " - #{m}"
|
52
|
+
end
|
53
|
+
|
54
|
+
return 1
|
55
|
+
end
|
56
|
+
|
57
|
+
packages.each do |package|
|
58
|
+
log.info "Installing package: #{package}"
|
59
|
+
install_package package, force=ns[:force]
|
60
|
+
end
|
61
|
+
else
|
62
|
+
log.info "No dependencies specified"
|
63
|
+
end
|
64
|
+
|
65
|
+
return 0
|
66
|
+
end
|
67
|
+
|
68
|
+
private
|
69
|
+
|
70
|
+
end
|
71
|
+
end
|