bits-installer 0.1.1 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
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