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 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/setup'
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/external_interface'
20
- require 'bits/user'
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
- subcommands = Hash.new
28
- available_providers = Array.new
29
- unavailable_providers = Array.new
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
- Bits.commands.values.sort_by{|c| c.command_id.to_s}.each do |klass|
46
- global_opts.separator " #{klass.command_id}: #{klass.desc}"
47
- subcommands[klass.command_id] = klass
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
- Bits.providers.values.sort_by{|p| p.provider_id.to_s}.each do |provider_class|
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
- available_providers.each do |provider_class|
61
- global_opts.separator " #{provider_class.provider_id}: #{provider_class.desc}"
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
- command = command.to_sym
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
- command_klass = subcommands[command]
87
- command = command_klass.new ns
84
+ bits_dir = setup_bits_dir
85
+ repo_dir = setup_repo_dir bits_dir
86
+ backend = setup_backend repo_dir
88
87
 
89
- command_parser = OptionParser.new do |opts|
90
- command.setup opts
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
- command_parser.order!
98
+ repository = Bits::Repository.new(providers, backend)
94
99
 
95
- ns[:user] = setup_user
96
- ns[:local_repository_dir] = setup_local_repository_dir 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
- ns[:repository] = Bits::Repository.new(providers, backend)
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
- # Setup the path to the local repository directory.
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 = Log4r::INFO
131
+ log.level = Log4r::INFO
118
132
  log
119
133
  end
120
134
 
121
- def setup_providers(available_providers, ns)
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 initialize(ns)
13
- @ns = ns
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, :desc => 'Install a package' do
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 install <bit>"
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.on('--force', "Insist on installing even if packages already installed") do |v|
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
- p = repository.find_package atom, criteria
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