baha 0.0.1

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.
Files changed (61) hide show
  1. checksums.yaml +15 -0
  2. data/.gitignore +15 -0
  3. data/.travis.yml +11 -0
  4. data/Gemfile +4 -0
  5. data/LICENSE.txt +22 -0
  6. data/README.md +156 -0
  7. data/Rakefile +21 -0
  8. data/baha.gemspec +31 -0
  9. data/bin/baha +5 -0
  10. data/example/.gitignore +1 -0
  11. data/example/base/init.sh.erb +11 -0
  12. data/example/base/test-template.erb +22 -0
  13. data/example/example.yml +54 -0
  14. data/example/rvm/image.yml +33 -0
  15. data/example/rvm/init.sh.erb +12 -0
  16. data/lib/baha/builder.rb +130 -0
  17. data/lib/baha/cli.rb +69 -0
  18. data/lib/baha/config.rb +142 -0
  19. data/lib/baha/container_options/cmd.rb +33 -0
  20. data/lib/baha/container_options/entrypoint.rb +10 -0
  21. data/lib/baha/container_options/env.rb +21 -0
  22. data/lib/baha/container_options/exposed_ports.rb +35 -0
  23. data/lib/baha/container_options/invalid_option_error.rb +15 -0
  24. data/lib/baha/container_options/option.rb +59 -0
  25. data/lib/baha/container_options/volumes.rb +24 -0
  26. data/lib/baha/container_options.rb +38 -0
  27. data/lib/baha/image.rb +154 -0
  28. data/lib/baha/log.rb +80 -0
  29. data/lib/baha/pre_build/command.rb +51 -0
  30. data/lib/baha/pre_build/download.rb +28 -0
  31. data/lib/baha/pre_build/template.rb +48 -0
  32. data/lib/baha/pre_build.rb +47 -0
  33. data/lib/baha/version.rb +3 -0
  34. data/lib/baha/workspace.rb +13 -0
  35. data/lib/baha.rb +5 -0
  36. data/spec/builder_spec.rb +103 -0
  37. data/spec/config_spec.rb +93 -0
  38. data/spec/container_options/cmd_spec.rb +46 -0
  39. data/spec/container_options/entrypoint_spec.rb +32 -0
  40. data/spec/container_options/env_spec.rb +26 -0
  41. data/spec/container_options/exposed_ports_spec.rb +32 -0
  42. data/spec/container_options/option_spec.rb +43 -0
  43. data/spec/container_options/volumes_spec.rb +25 -0
  44. data/spec/fixtures/base_image.yml +5 -0
  45. data/spec/fixtures/config_build.yml +12 -0
  46. data/spec/fixtures/config_build_image.yml +10 -0
  47. data/spec/fixtures/config_eachimage.yml +12 -0
  48. data/spec/fixtures/config_embedded.yml +11 -0
  49. data/spec/fixtures/config_include.yml +7 -0
  50. data/spec/fixtures/config_ssl.yml +13 -0
  51. data/spec/fixtures/config_sslpath.yml +11 -0
  52. data/spec/helpers/docker_helpers.rb +31 -0
  53. data/spec/image_spec.rb +167 -0
  54. data/spec/log_spec.rb +89 -0
  55. data/spec/options_spec.rb +52 -0
  56. data/spec/pre_build/command_spec.rb +69 -0
  57. data/spec/pre_build/download_spec.rb +43 -0
  58. data/spec/pre_build/template_spec.rb +55 -0
  59. data/spec/pre_build_spec.rb +29 -0
  60. data/spec/spec_helper.rb +39 -0
  61. metadata +255 -0
@@ -0,0 +1,142 @@
1
+ require 'yaml'
2
+ require 'pathname'
3
+ require 'baha/log'
4
+
5
+ class Baha::Config
6
+ DEFAULTS = {
7
+ :parent => 'ubuntu:14.04.1',
8
+ :bind => '/.baha',
9
+ :command => ['/bin/bash','./init.sh'],
10
+ :repository => nil,
11
+ :maintainer => nil,
12
+ :timeout => 1200
13
+ }
14
+ LOG = Baha::Log.for_name("Config")
15
+ class << self
16
+ def load(file)
17
+ LOG.debug { "Loading file #{file}"}
18
+ filepath = Pathname.new(file)
19
+ raise ArgumentError.new("Cannot read config file #{file}") unless filepath.readable?
20
+ config = YAML.load_file(filepath)
21
+ config['configdir'] ||= filepath.dirname
22
+ Baha::Config.new(config)
23
+ end
24
+ end
25
+
26
+ attr_reader :configdir, :workspace, :secure, :options
27
+ attr_reader :defaults
28
+
29
+ def initialize(config)
30
+ @config = config
31
+
32
+ # Defaults
33
+ defaults = config['defaults'] || {}
34
+ raise ArgumentError.new("Expected Hash for defaults") unless defaults.is_a?(Hash)
35
+ @defaults = {}
36
+ DEFAULTS.keys.each do |k|
37
+ @defaults[k] = defaults[k] || defaults[k.to_s] || DEFAULTS[k]
38
+ end
39
+
40
+ @configdir = Pathname.new(config['configdir'] || Pathname.pwd)
41
+ @workspace = Pathname.new(config['workspace'] || @configdir + 'workspace')
42
+ @secure = false
43
+ @options = {}
44
+ init_security if ENV.has_key?('DOCKER_CERT_PATH') || config.has_key?('ssl')
45
+ end
46
+
47
+ def init_security
48
+ @secure = true
49
+ cert_path = ''
50
+ ssl_options = { }
51
+ if ENV['DOCKER_CERT_PATH']
52
+ cert_path = Pathname.new(ENV['DOCKER_CERT_PATH'])
53
+ ssl_options[:ssl_verify_peer] = (ENV['DOCKER_TLS_VERIFY'] == '1')
54
+ ssl_options[:client_cert] = (cert_path + 'cert.pem').expand_path.to_s
55
+ ssl_options[:client_key] = (cert_path + 'key.pem').expand_path.to_s
56
+ ssl_options[:ssl_ca_file] = (cert_path + 'ca.pem').expand_path.to_s
57
+ elsif @config.has_key?('ssl')
58
+ ssl = @config['ssl']
59
+ ssl_options[:ssl_verify_peer] = ssl['verify'] || false
60
+ if ssl.has_key?('cert_path')
61
+ cert_path = Pathname.new(ssl['cert_path'])
62
+ ssl_options[:client_cert] = (cert_path + 'cert.pem').expand_path.to_s
63
+ ssl_options[:client_key] = (cert_path + 'key.pem').expand_path.to_s
64
+ ssl_options[:ssl_ca_file] = (cert_path + 'ca.pem').expand_path.to_s
65
+ else
66
+ ssl_options[:client_cert] = ssl['cert']
67
+ ssl_options[:client_key] = ssl['key']
68
+ ssl_options[:ssl_ca_file] = ssl['ca']
69
+ end
70
+ end
71
+ @options.merge!(ssl_options)
72
+ end
73
+
74
+ def each_image
75
+ return unless @config.has_key?('images')
76
+ @config['images'].each do |image|
77
+ if image.has_key?('include')
78
+ path = Pathname.new(image['include'])
79
+ file = resolve_file(path)
80
+ if file
81
+ yml = YAML.load_file(file)
82
+ yield Baha::Image.new(self,yml)
83
+ else
84
+ LOG.error { "Unable to find image include: #{path}"}
85
+ next
86
+ end
87
+ else
88
+ yield Baha::Image.new(self,image)
89
+ end
90
+ end
91
+ end
92
+
93
+ def resolve_file(file)
94
+ filepath = Pathname.new(file)
95
+ LOG.debug { "resolve_file(#{file})" }
96
+ paths = [
97
+ filepath, # 0. Absolute path
98
+ @workspace + file, # 1. Workspace
99
+ @configdir + file, # 2. Config
100
+ Pathname.pwd + file # 3. Current directory
101
+ ]
102
+ paths.reduce(nil) do |result,path|
103
+ if result.nil?
104
+ if path.exist?
105
+ result = path
106
+ LOG.debug("found file at: #{path}")
107
+ else
108
+ LOG.debug("did not find file at: #{path}")
109
+ end
110
+ end
111
+ result
112
+ end
113
+ end
114
+
115
+ # Initialize Docker Client
116
+ def init_docker!
117
+ Docker.options = @options
118
+ if @config.has_key?('docker_url')
119
+ url = @config['docker_url']
120
+ Docker.url = url
121
+ end
122
+ if @secure
123
+ Docker.url = Docker.url.gsub(/^tcp:/,'https:')
124
+ end
125
+ LOG.debug { "Docker URL: #{Docker.url}"}
126
+ LOG.debug { "Docker Options: #{Docker.options.inspect}"}
127
+ Docker.validate_version!
128
+ end
129
+
130
+ def inspect
131
+ <<-eos.gsub(/\n?\s{2,}/,'')
132
+ #{self.class.name}<
133
+ @config=#{@config.inspect},
134
+ @configdir=#{@configdir},
135
+ @workspace=#{@workspace},
136
+ @defaults=#{@defaults.inspect},
137
+ @secure=#{@secure},
138
+ @options=#{@options.inspect}
139
+ >
140
+ eos
141
+ end
142
+ end
@@ -0,0 +1,33 @@
1
+ require 'baha/container_options/invalid_option_error'
2
+ require 'baha/container_options/option'
3
+ module Baha
4
+ module ContainerOptions
5
+ class Cmd < Option
6
+
7
+ def self.split_command(cmd)
8
+ require 'csv'
9
+ CSV.parse_line(cmd,{:col_sep => ' ', :skip_blanks => true, :quote_char => '"'})
10
+ end
11
+
12
+ def initialize(*args)
13
+ if args.length < 2 then
14
+ @conf = 'Cmd'
15
+ super('Cmd',*args)
16
+ else
17
+ @conf = args[0]
18
+ super(*args)
19
+ end
20
+ end
21
+ def apply(config)
22
+ if @value.kind_of?(Array)
23
+ config[@conf] = @value
24
+ else
25
+ config[@conf] = Cmd::split_command(@value)
26
+ end
27
+ end
28
+ def validate!
29
+ raise ERROR("should be an array or string") unless @value.kind_of?(Array) or @value.kind_of?(String)
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,10 @@
1
+ require 'baha/container_options/cmd'
2
+ module Baha
3
+ module ContainerOptions
4
+ class Entrypoint < Cmd
5
+ def initialize(*args)
6
+ super('Entrypoint',*args)
7
+ end
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,21 @@
1
+ require 'baha/container_options/option'
2
+ module Baha
3
+ module ContainerOptions
4
+ class Env < Option
5
+ def initialize(*args)
6
+ super(:env,*args)
7
+ end
8
+ def apply(config)
9
+ unless config.has_key?('Env')
10
+ config['Env'] = []
11
+ end
12
+ @value.each_pair do |k,v|
13
+ config['Env'] << "#{k}=#{v}"
14
+ end
15
+ end
16
+ def validate!
17
+ raise ERROR("should be a hash") unless @value.kind_of?(Hash)
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,35 @@
1
+ require 'baha/container_options/invalid_option_error'
2
+ require 'baha/container_options/option'
3
+ module Baha
4
+ module ContainerOptions
5
+ class ExposedPorts < Option
6
+ def initialize(*args)
7
+ super(:exposedports,*args)
8
+ end
9
+ def apply(config)
10
+ unless config.has_key?('ExposedPorts')
11
+ config['ExposedPorts'] = {}
12
+ end
13
+ @value.each do |port|
14
+ case port
15
+ when Fixnum
16
+ config['ExposedPorts']["#{port}/tcp"] = {}
17
+ when String
18
+ config['ExposedPorts'][port] = {}
19
+ end
20
+ end
21
+ end
22
+
23
+ def validate!
24
+ raise ERROR("should be an array") unless @value.kind_of?(Array)
25
+ @value.each_with_index do |item,index|
26
+ if item.kind_of?(String)
27
+ unless /(\d+)\/(tcp|udp)/ =~ item
28
+ raise ERROR("#{index}: '#{item}' should be in the form 8080/tcp")
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,15 @@
1
+ module Baha
2
+ module ContainerOptions
3
+ class InvalidOptionError < RuntimeError
4
+ attr_reader :key
5
+ attr_reader :value
6
+ attr_reader :reason
7
+ def initialize(key,value,reason)
8
+ super("Unable to validate option: #{key}. '#{value}' #{reason}")
9
+ @key = key
10
+ @value = value
11
+ @reason = reason
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,59 @@
1
+ require 'baha/container_options/invalid_option_error'
2
+ module Baha
3
+ module ContainerOptions
4
+ class Option
5
+ KEYS = {
6
+ :cmd => 'Cmd',
7
+ :cpushares => 'CpuShares',
8
+ :cpuset => 'Cpuset',
9
+ :domainname => 'Domainname',
10
+ :entrypoint => 'Entrypoint',
11
+ :env => 'Env',
12
+ :exposedports => 'ExposedPorts',
13
+ :hostname => 'Hostname',
14
+ :image => 'Image',
15
+ :memory => 'Memory',
16
+ :memoryswap => 'MemorySwap',
17
+ :networkdisabled => 'NetworkDisabled',
18
+ :user => 'User',
19
+ :volumes => 'Volumes',
20
+ :workingdir => 'WorkingDir',
21
+ }
22
+
23
+ attr_reader :key
24
+ attr_reader :config_key
25
+ attr_reader :value
26
+
27
+ def initialize(*args)
28
+ k,@value = args
29
+ raise ArgumentError, "Cannot understand option key '#{k}'" unless k.respond_to?(:to_sym)
30
+ @key = k.to_sym.downcase
31
+ raise ERROR("Option with key '#{@key}' is not found. Expecting #{KEYS.keys.inspect}") unless KEYS.has_key?(@key)
32
+ @config_key = KEYS[@key]
33
+ end
34
+
35
+ def eql?(other)
36
+ @key == other.key and @value == other.value
37
+ end
38
+
39
+ # Apply this option to the container's config hash
40
+ def apply(config)
41
+ config[@config_key] = @value
42
+ end
43
+
44
+ # Validate the option's value
45
+ def validate!
46
+ KEYS.has_key?(@key)
47
+ end
48
+
49
+ def inspect
50
+ "#{self.class.name}<@key=#{@key.inspect},@value=#{@value.inspect}>"
51
+ end
52
+
53
+ private
54
+ def ERROR(reason)
55
+ InvalidOptionError.new(@key,@value,reason)
56
+ end
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,24 @@
1
+ require 'baha/container_options/option'
2
+ module Baha
3
+ module ContainerOptions
4
+ class Volumes < Option
5
+ def initialize(*args)
6
+ super(:volumes,*args)
7
+ end
8
+ def apply(config)
9
+ unless config.has_key?('Volumes')
10
+ config['Volumes'] = {}
11
+ end
12
+ @value.each do |mount|
13
+ config['Volumes'][mount] = {}
14
+ end
15
+ end
16
+ def validate!
17
+ raise ERROR("should be an array") unless @value.kind_of?(Array)
18
+ @value.each_with_index do |item,index|
19
+ raise ERROR("#{index}: '#{item}' should be a string") unless item.kind_of?(String)
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,38 @@
1
+ require 'baha/container_options/cmd'
2
+ require 'baha/container_options/entrypoint'
3
+ require 'baha/container_options/env'
4
+ require 'baha/container_options/exposed_ports'
5
+ require 'baha/container_options/invalid_option_error'
6
+ require 'baha/container_options/option'
7
+ require 'baha/container_options/volumes'
8
+ module Baha
9
+ module ContainerOptions
10
+ def self.parse_options(options)
11
+ if options
12
+ Hash[options.map { |k,v| opt = self.parse_option(k,v)
13
+ [opt.key,opt] }]
14
+ else
15
+ {}
16
+ end
17
+ end
18
+ def self.parse_option(key,value)
19
+ k = key.to_sym.downcase
20
+ option = case k
21
+ when :volumes
22
+ Volumes.new(value)
23
+ when :env
24
+ Env.new(value)
25
+ when :cmd
26
+ Cmd.new(value)
27
+ when :entrypoint
28
+ Entrypoint.new(value)
29
+ when :exposedports
30
+ ExposedPorts.new(value)
31
+ else
32
+ Option.new(key,value)
33
+ end
34
+ option.validate!
35
+ option
36
+ end
37
+ end
38
+ end
data/lib/baha/image.rb ADDED
@@ -0,0 +1,154 @@
1
+ require 'docker'
2
+ require 'baha/container_options'
3
+ require 'baha/log'
4
+ require 'set'
5
+
6
+ module Baha
7
+ class ImageNotFoundError < RuntimeError
8
+ attr_reader :image
9
+ def initialize(image)
10
+ super("Unable to locate image : #{image[:name]}:#{image[:tag]}")
11
+ @image = image
12
+ end
13
+ end
14
+ class Image
15
+ LOG = Baha::Log.for_name("Image")
16
+ class << self
17
+ # Parses an image name
18
+ def parse_name(image)
19
+ m = /(?:([a-z0-9\-._\/]+))(?::([a-zA-Z0-9\-._]+))?/.match(image)
20
+ unless m
21
+ raise ArgumentError.new("Unable to parse image name #{image}")
22
+ end
23
+ tag = m.captures[1]
24
+ tag ||= 'latest'
25
+ imagename = m.captures[0]
26
+ m2 = /(?:(.+)\/)?(.+)/.match(imagename)
27
+ ns = m2.captures[0]
28
+ name = m2.captures[1]
29
+ {
30
+ :ns => ns,
31
+ :name => name,
32
+ :tag => tag
33
+ }
34
+ end
35
+
36
+ def parse_with_default(image,repository)
37
+ i = parse_name(image)
38
+ unless i[:ns]
39
+ i[:ns] = repository
40
+ end
41
+ i
42
+ end
43
+
44
+ def get_image!(image)
45
+ LOG.debug { "get_image!(#{image.inspect})" }
46
+ tag = image[:tag] || 'latest'
47
+ repo = "#{image[:ns]}/#{image[:name]}"
48
+ img = [
49
+ lambda { Docker::Image.get("#{image[:name]}:#{image[:tag]}") },
50
+ lambda { Docker::Image.create('fromImage'=> image[:name], 'tag' => tag) },
51
+ lambda { Docker::Image.create('fromImage' => repo, 'tag' => tag) }
52
+ ].reduce(nil) do |result,block|
53
+ unless result
54
+ begin
55
+ result = block.call
56
+ result = Docker::Image.get(result.id)
57
+ rescue
58
+ result = nil
59
+ end
60
+ end
61
+ result
62
+ end
63
+ raise Baha::ImageNotFoundError.new(image) unless img
64
+ img
65
+ end
66
+
67
+ end
68
+ attr_reader :parent, :image, :maintainer, :options, :pre_build, :bind, :command, :timeout, :workspace, :name, :tags
69
+
70
+ def initialize(config,image)
71
+ @parent = Baha::Image.parse_with_default(image['parent'] || config.defaults[:parent], config.defaults[:repository])
72
+ @image = Baha::Image.parse_with_default(image['name'], config.defaults[:repository])
73
+ @image[:tag] = image['tag'] if image.has_key?('tag')
74
+ @maintainer = image['maintainer'] || config.defaults[:maintainer]
75
+ @options = Baha::ContainerOptions::parse_options(image['config'])
76
+ @pre_build = image['pre_build']
77
+ @bind = image['bind'] || config.defaults[:bind]
78
+ @command = image['command'] || config.defaults[:command]
79
+ @timeout = image['timeout'] || config.defaults[:timeout]
80
+ @workspace = config.workspace + (image['workspace'] || @image[:name])
81
+ @name = @image[:name]
82
+ @tags = Set.new [
83
+ "#{@image[:name]}:#{@image[:tag]}",
84
+ "#{@image[:name]}:latest"
85
+ ]
86
+ if @image[:ns]
87
+ @tags << "#{@image[:ns]}/#{@image[:name]}:#{@image[:tag]}"
88
+ @tags << "#{@image[:ns]}/#{@image[:name]}:latest"
89
+ end
90
+ end
91
+
92
+ def env
93
+ {
94
+ :parent => @parent,
95
+ :maintainer => @maintainer,
96
+ :bind => @bind,
97
+ :name => @image[:name],
98
+ :tag => @image[:tag],
99
+ :workspace => @workspace.expand_path.to_s
100
+ }
101
+ end
102
+
103
+ def parent_id
104
+ parent = Baha::Image.get_image!(@parent)
105
+ parent.id
106
+ end
107
+
108
+ def commit_config
109
+ @options.values.reduce({}) do |memo,option|
110
+ option.apply(memo)
111
+ memo
112
+ end
113
+ end
114
+
115
+ # Checks if the image needs updating
116
+ # 1. If it's parent image has changed
117
+ # 2. If the desired tag is not found
118
+ # Will raise Baha::ImageNotFoundError if the parent image can not be found
119
+ def needs_update?
120
+ LOG.debug { "needs_update?(#{@image.inspect})" }
121
+ parent = Baha::Image.get_image!(@parent)
122
+ LOG.debug { "got parent: #{parent.inspect}" }
123
+ begin
124
+ image = Baha::Image.get_image!(@image)
125
+ LOG.debug { "got image: #{image.inspect}" }
126
+ parent_id = image.info['Parent']
127
+ this_tags = image.history[0]["Tags"]
128
+ local_tag = "#{@image[:name]}:#{@image[:tag]}"
129
+ remote_tag = "#{@image[:ns]}/#{local_tag}"
130
+ LOG.debug { "current parent id = #{parent_id}" }
131
+ LOG.debug { "current image tags = #{parent_id}" }
132
+ LOG.debug { "current parent id = #{parent_id}" }
133
+ parent_id != parent.id or not ( this_tags.include?(local_tag) or this_tags.include?(remote_tag) )
134
+ rescue
135
+ true
136
+ end
137
+ end
138
+
139
+ def inspect
140
+ <<-eos.gsub(/\n?\s{2,}/,'')
141
+ #{self.class.name}<
142
+ @parent=#{@parent.inspect},
143
+ @image=#{@image.inspect},
144
+ @maintainer=#{@maintainer},
145
+ @options=#{@options.inspect},
146
+ @pre_build=#{@pre_build.inspect},
147
+ @bind=#{@bind},
148
+ @command=#{@command.inspect},
149
+ @timeout=#{@timeout}
150
+ >
151
+ eos
152
+ end
153
+ end
154
+ end
data/lib/baha/log.rb ADDED
@@ -0,0 +1,80 @@
1
+ class Baha::Log
2
+ require 'logger'
3
+ LEVELS = {
4
+ :debug => Logger::DEBUG,
5
+ :info => Logger::INFO,
6
+ :warn => Logger::WARN,
7
+ :error => Logger::ERROR,
8
+ :fatal => Logger::FATAL
9
+ }
10
+ class Formatter
11
+ Format = "%s [%5s] %s -- %s\n"
12
+
13
+ def call(severity, time, progname, msg)
14
+ Format % [time.strftime('%Y-%m-%d %H:%M:%S.%L'), severity, progname, msg2str(msg)]
15
+ end
16
+
17
+ private
18
+
19
+ def msg2str(msg)
20
+ case msg
21
+ when ::String
22
+ msg
23
+ when ::Exception
24
+ "#{ msg.message } (#{ msg.class })\n\t" <<
25
+ (msg.backtrace || []).join("\n\t")
26
+ else
27
+ msg.inspect
28
+ end
29
+ end
30
+ end
31
+ class << self
32
+ attr_reader :level, :logfile, :io
33
+ def logfile=(io)
34
+ @io = io
35
+ @logfile = Logger.new(io)
36
+ @logfile.formatter = Baha::Log::Formatter.new()
37
+ self.level = :error
38
+ end
39
+ def level=(level)
40
+ key = case level
41
+ when String
42
+ @level = level.downcase.to_sym
43
+ when Symbol
44
+ @level = level.downcase
45
+ else
46
+ raise ArgumentError.new("level must be a string or symbol")
47
+ end
48
+ raise ArgumentError.new("level must be in #{LEVELS.keys}") unless LEVELS.has_key?(key)
49
+ @level = key
50
+ self.logfile.sev_threshold = LEVELS[@level]
51
+ end
52
+ def close!
53
+ if @logfile
54
+ @logfile.close
55
+ @logfile = nil
56
+ end
57
+ end
58
+ def for_name(progname)
59
+ Baha::Log.new(progname)
60
+ end
61
+ end
62
+
63
+ attr_reader :progname
64
+
65
+ def initialize(progname)
66
+ @progname = progname
67
+ end
68
+
69
+ LEVELS.keys.each do |level|
70
+ define_method(level) do |*message, &block|
71
+ if Baha::Log.logfile
72
+ if block
73
+ Baha::Log.logfile.send(level, @progname, &block)
74
+ else
75
+ Baha::Log.logfile.send(level, @progname) { message[0] }
76
+ end
77
+ end
78
+ end
79
+ end
80
+ end
@@ -0,0 +1,51 @@
1
+ require 'baha/pre_build'
2
+ require 'open3'
3
+
4
+ class Baha::PreBuild::Module::Command
5
+ LOG = Baha::Log.for_name("Module::Command")
6
+
7
+ def self.execute(mod)
8
+ LOG.debug("execute(#{mod.args.inspect})")
9
+ command = mod.args['command']
10
+ creates = mod.args['creates']
11
+ onlyif = mod.args['only_if']
12
+
13
+ cwd = mod.image.workspace.expand_path
14
+
15
+ if creates
16
+ filepath = cwd + creates
17
+ LOG.debug { "Checking if file exists #{filepath}"}
18
+ if filepath.exist?
19
+ LOG.info("#{creates} exists - skipping command")
20
+ return
21
+ end
22
+ end
23
+
24
+ if onlyif
25
+ exit_status = 0
26
+ LOG.info { "Running test [onlyif] #{onlyif.inspect}" }
27
+ Open3.popen2e(onlyif,:chdir=>cwd.to_s) do |stdin, oe, wait_thr|
28
+ oe.each do |line|
29
+ LOG.debug { "++ " + line }
30
+ end
31
+ exit_status = wait_thr.value # Process::Status object returned.
32
+ end
33
+ unless exit_status.success?
34
+ LOG.debug { "onlyif did not exist successfully - skipping command" }
35
+ return
36
+ end
37
+ end
38
+
39
+ LOG.info { "Running command #{command.inspect}" }
40
+ Open3.popen2e(command,:chdir=>cwd.to_s) do |stdin, oe, wait_thr|
41
+ oe.each do |line|
42
+ LOG.debug { "++ " + line.chomp }
43
+ end
44
+ end
45
+
46
+ end
47
+ end
48
+
49
+ Baha::PreBuild::Module.register(:command) do |mod|
50
+ Baha::PreBuild::Module::Command.execute(mod)
51
+ end
@@ -0,0 +1,28 @@
1
+ require 'baha/pre_build'
2
+ require 'open-uri'
3
+
4
+ class Baha::PreBuild::Module::Download
5
+ LOG = Baha::Log.for_name("Module::Download")
6
+
7
+ def self.execute(mod)
8
+ LOG.debug("execute(#{mod.args.inspect})")
9
+
10
+ filename = mod.image.workspace + mod.args['file']
11
+ url = mod.args['download']
12
+ overwrite = mod.args['overwrite'] || false
13
+ if Pathname.new(filename).exist? and not overwrite
14
+ LOG.info("#{filename} already exists")
15
+ else
16
+ LOG.info("Download #{url} -> #{filename}")
17
+ File.open(filename, "w") do |saved_file|
18
+ open(url, "rb") do |read_file|
19
+ saved_file.write(read_file.read)
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
25
+
26
+ Baha::PreBuild::Module.register(:download) do |mod|
27
+ Baha::PreBuild::Module::Download.execute(mod)
28
+ end