devinstall 1.0.1 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/bin/pkg-tool CHANGED
@@ -1,36 +1,7 @@
1
1
  #!/usr/bin/env ruby
2
2
  require 'rubygems'
3
3
  require 'bundler/setup'
4
- require 'devinstall/cli'
4
+ require 'devinstall'
5
5
 
6
- unless ARGV[0]
7
- puts 'You must specify an action'
8
- exit! ''
9
- end
10
-
11
- package = [] # creata a new Array
12
- command = ARGV.shift
13
-
14
- while ARGV[0] and ARGV[0][0..1] != '--'
15
- package << ARGV.shift
16
- end
17
-
18
- if %w"version --version -v".include? command
19
- command = 'version'
20
- end
21
-
22
- if %w"help --help -h".include? command
23
- command = 'help'
24
- end
25
-
26
- unless %w"build install upload test help version".include? command
27
- puts "Unknown command #{command}"
28
- exit! 1
29
- end
30
-
31
- ## the next should be the package
32
- # so if ARGV[0] don't start with --
33
- # we name it package
34
- cli=Devinstall::Cli.new(*package) ## Cli can be called for multiple packages
35
- cli.send(command.to_sym)
6
+ include Cli
36
7
 
data/devinstall.gemspec CHANGED
@@ -22,4 +22,5 @@ Gem::Specification.new do |spec|
22
22
  spec.add_development_dependency 'rake'
23
23
  spec.add_development_dependency 'getopt'
24
24
  spec.add_development_dependency 'rspec'
25
+ spec.add_development_dependency 'commander'
25
26
  end
data/doc/example.yml CHANGED
@@ -12,7 +12,7 @@ base:
12
12
  arch: debian64
13
13
  defaults:
14
14
  package: devinstall
15
- env: dev
15
+ # env: dev
16
16
  type: deb
17
17
  tests:
18
18
  # dev is the environment
@@ -1,95 +1,94 @@
1
- require 'devinstall'
1
+ require 'devinstall/pkg'
2
2
  require 'getopt/long'
3
3
  require 'devinstall/settings'
4
+ require 'commander/import'
4
5
 
5
- module Devinstall
6
- class Cli
6
+ module Cli
7
7
 
8
- include Utils
8
+ program :name, 'DevInstall'
9
+ program :version, Devinstall::VERSION
10
+ program :description, 'Poor man builder/installer'
9
11
 
10
- def get_config(*fnames)
11
- config=nil
12
- fnames.each do |f|
13
- (config ||= (File.expand_path(f) if File.exist? f)) and break
14
- end
15
- config
12
+ global_option('--config FILE' 'Configuration file to be used') do |file|
13
+ unless Devinstall::Settings.instance.load! file
14
+ puts "Couldn't find #{file}"
15
+ exit!
16
16
  end
17
+ end
17
18
 
18
- def initialize(*package)
19
- begin
20
- opt = Getopt::Long.getopts(
21
- %w(--config -c),
22
- %w(--type -t),
23
- %w(--env -e),
24
- %w(--verbose -v),
25
- %w(--dry-run -d),
26
- )
27
- rescue
28
- puts 'Invalid option at command line'
29
- help
30
- end
31
- #verbose and dry-run
32
- $verbose ||= opt['verbose']
33
- $dry ||= opt['dry-run']
34
- # get config file
35
- config = Devinstall::Settings.instance # is a singleton so we don't use new here
36
- cfgfile = get_config('./devinstall.yml', '~/.devinstall.yml', opt['config'])
37
- exit! 'You must specify the config file' if cfgfile.empty?
38
- config.load! cfgfile # load cfgfile
39
- config.env = opt['env'] || config.env
40
- config.type = opt['type'] || config.type
41
- @packages = package || []
42
- @packages = config.defaults(:package) if @packages.empty?
43
- exit! 'You must ask for a package' if @packages.empty?
44
- config.validate
45
- rescue KeyNotDefinedError => e
46
- exit! e.message
19
+ global_option('--verbose', 'Verbose output') { $verbose=true }
20
+ global_option('--dry-run', 'Dry-run; don\'t run commands, just pretend to') { $dry=true }
21
+ global_option('--type STRING', 'Package type (deb, rpm, tgz). Currently only deb')
22
+ global_option('--env STRING', 'Package environment to be built for')
23
+
24
+ def load_defaults
25
+ %w(./devinstall.yml ./.devinstall.yml ~/.devinstall).each do |f|
26
+ Devinstall::Settings.instance.load! f and return true
47
27
  end
28
+ puts "Couldn't find default config file and no --config option given at command line"
29
+ exit!
30
+ end
31
+
32
+ command :build do |c|
33
+ c.action do |args, options|
34
+ config=Devinstall::Settings.instance
35
+ load_defaults unless options.config
36
+ type = options.type ? options.type.to_sym : config.defaults(:type)
37
+ env = options.env ? options.env.to_sym : config.defaults(:env)
48
38
 
49
- def build
50
- @packages.each do |package|
51
- pk=Devinstall::Pkg.new(package)
39
+ args.each do |p|
40
+ pk=Devinstall::Pkg.new(p, type, env)
52
41
  pk.build
53
42
  end
54
43
  end
44
+ end
45
+
46
+ command :install do |c|
47
+ c.action do |args, options|
48
+ config=Devinstall::Settings.instance
49
+ load_defaults unless options.config
50
+ type = options.type ? options.type.to_sym : config.defaults(:type)
51
+ env = options.env ? options.env.to_sym : config.defaults(:env)
55
52
 
56
- def install
57
- @packages.each do |package|
58
- pk=Devinstall::Pkg.new(package)
53
+ args.each do |p|
54
+ pk=Devinstall::Pkg.new(p, type, env)
59
55
  pk.build
60
56
  pk.install
61
57
  end
62
58
  end
59
+ end
63
60
 
64
- def upload
65
- @packages.each do |package|
66
- pk=Devinstall::Pkg.new(package)
67
- pk.build
68
- pk.run_tests
69
- pk.upload
70
- end
71
- end
61
+ command :test do |c|
62
+ c.action do |args, options|
63
+ config=Devinstall::Settings.instance
64
+ load_defaults unless options.config
65
+ type = options.type ? options.type.to_sym : config.defaults(:type)
66
+ env = options.env ? options.env.to_sym : config.defaults(:env)
72
67
 
73
- def test
74
- @packages.each do |package|
75
- pk=Devinstall::Pkg.new(package)
68
+ args.each do |p|
69
+ pk=Devinstall::Pkg.new(p, type, env)
76
70
  pk.run_tests
77
71
  end
78
72
  end
73
+ end
79
74
 
80
- def help
81
- puts 'Usage:'
82
- puts 'pkg-tool command [package_name ... ] --config|-c <file> --type|-t <package_type> --env|-e <environment>'
83
- puts 'where command is one of the: build, install, upload, help, version'
84
- exit! ''
85
- end
75
+ command :upload do |c|
76
+ c.action do |args, options|
77
+ config=Devinstall::Settings.instance
78
+ load_defaults unless options.config
79
+ type = options.type ? options.type.to_sym : config.defaults(:type)
80
+ env = options.env ? options.env.to_sym : config.defaults(:env)
86
81
 
87
- def version
88
- puts "devinstall version #{Devinstall::VERSION}"
89
- puts "pkg-tool version #{Devinstall::VERSION}"
90
- exit! ''
82
+ args.each do |p|
83
+ pk=Devinstall::Pkg.new(p, type, env)
84
+ pk.build
85
+ pk.run_tests
86
+ pk.upload
87
+ end
91
88
  end
92
-
93
89
  end
90
+
94
91
  end
95
92
 
93
+ __END__
94
+
@@ -0,0 +1,178 @@
1
+ require 'devinstall/version'
2
+ require 'devinstall/deep_symbolize'
3
+ require 'devinstall/utils'
4
+ require 'devinstall/settings'
5
+ require 'pp'
6
+
7
+ module Devinstall
8
+ class UndeffError < RuntimeError; end
9
+
10
+ class Pkg
11
+ include Utils
12
+
13
+ def get_version(pkg, type, env)
14
+ config=Settings.instance
15
+ folder=config.local(:folder, pkg:pkg, type:type, env:env)
16
+ case type
17
+ when :deb
18
+ begin
19
+ deb_changelog = File.expand_path "#{folder}/#{pkg}/debian/changelog"
20
+ unless File.exists? deb_changelog
21
+ exit! <<-eos
22
+ No 'debian/changelog' found in specified :local:folder (#{folder})
23
+ Please check your config file
24
+ eos
25
+ end
26
+ @_package_version[:deb] = File.open(deb_changelog, 'r') { |f| f.gets.chomp.sub(/^.*\((.*)\).*$/, '\1') }
27
+ rescue IOError => e
28
+ exit! <<-eos
29
+ IO Error while opening #{deb_changelog}
30
+ Aborting \n #{e}
31
+ eos
32
+ end
33
+ else
34
+ raise UndeffError, "TODO package type #{type}"
35
+ end
36
+ end
37
+
38
+ # @param [String] package
39
+ def initialize(package, type, env)
40
+ config=Settings.instance #class variable,first thing!
41
+ @type=type
42
+ @env=env
43
+ @package = package
44
+ @_package_version = {} # versions for types:
45
+ @package_files = {}
46
+ arch = config.build(pkg:package, type:type, env:env)[:arch]
47
+ p_name = "#{@package}_#{get_version(package, type, env)}"
48
+ @package_files[:deb] = {deb: "#{p_name}_#{arch}.deb",
49
+ tgz: "#{p_name}.tar.gz",
50
+ dsc: "#{p_name}.dsc",
51
+ chg: "#{p_name}_amd64.changes"}
52
+ end
53
+
54
+ def upload(pkg=@package, type=@type, env=@env)
55
+ config = Settings.instance
56
+ scp = config.base(:scp)
57
+ repo = config.repos(pkg:pkg, type:type, env:env)
58
+ local = config.local(pkg:pkg, type:type, env:env)
59
+
60
+ @package_files[type].each do |p, f|
61
+ puts "Uploading #{f}\t\t[#{p}] to #{repo[:host]}"
62
+ command("#{scp} #{local[:temp]}/#{f} #{repo[:user]}@#{repo[:host]}:#{repo[:folder]}")
63
+ end
64
+ rescue CommandError => e
65
+ puts e.verbose_message
66
+ exit! ''
67
+ rescue KeyNotDefinedError => e
68
+ puts e.message
69
+ exit! ''
70
+ end
71
+
72
+ def build(pkg=@package, type=@type, env=@env)
73
+ config = Settings.instance
74
+ puts "Building package #{pkg} type #{type}"
75
+ build = config.build(pkg:pkg, type:type, env:env)
76
+ local = config.local(pkg:pkg, type:type, env:env)
77
+ raise 'Invaild build configuration' unless build.valid?
78
+
79
+ ssh = config.base(:ssh)
80
+ rsync = config.base(:rsync)
81
+ local_folder = File.expand_path local[:folder]
82
+ local_temp = File.expand_path local[:temp]
83
+
84
+ build_command = build[:command].gsub('%f', build[:folder]).
85
+ gsub('%t', build[:target]).
86
+ gsub('%p', pkg.to_s).
87
+ gsub('%T', type.to_s)
88
+
89
+ upload_sources("#{local_folder}/", "#{build[:user]}@#{build[:host]}:#{build[:folder]}")
90
+ command("#{ssh} #{build[:user]}@#{build[:host]} \"#{build_command}\"")
91
+ @package_files[type].each do |p, t|
92
+ puts "Receiving target #{p.to_s} for #{t.to_s}"
93
+ command("#{rsync} -az #{build[:user]}@#{build[:host]}:#{build[:target]}/#{t} #{local_temp}")
94
+ end
95
+ rescue CommandError => e
96
+ puts e.verbose_message
97
+ exit! ''
98
+ rescue KeyNotDefinedError => e
99
+ puts e.message
100
+ exit! ''
101
+ end
102
+
103
+ def install(pkg=@package, type=@type, env=@env)
104
+ config=Settings.instance
105
+ puts "Installing #{pkg} in #{env} environment."
106
+ install=config.install(pkg:pkg, type:type, env:env)
107
+ temp =config.local(pkg:pkg, type:type, env:env)[:temp]
108
+
109
+ sudo = config.base(:sudo)
110
+ scp = config.base(:scp)
111
+
112
+ install[:host] = [install[:host]] unless Array === install[:host]
113
+ case type
114
+ when :deb
115
+ install[:host].each do |host|
116
+ command("#{scp} #{temp}/#{@package_files[type][:deb]} #{install[:user]}@#{host}:#{install[:folder]}")
117
+ command("#{sudo} #{install[:user]}@#{host} /usr/bin/dpkg -i #{install[:folder]}/#{@package_files[type][:deb]}")
118
+ end
119
+ else
120
+ exit! "unknown package type '#{type.to_s}'"
121
+ end
122
+ rescue CommandError => e
123
+ puts e.verbose_message
124
+ exit! ''
125
+ rescue KeyNotDefinedError => e
126
+ puts e.message
127
+ exit! ''
128
+ end
129
+
130
+ def run_tests(pkg=@package, type=@type, env=@env)
131
+ config=Settings.instance
132
+ # check if we have the test section in the configuration file
133
+ unless config.respond_to? :tests
134
+ puts 'No test section in the config file.'
135
+ puts 'Skipping tests'
136
+ return
137
+ end
138
+ # for tests we will use almost the same setup as for build
139
+ test = config.tests(pkg:pkg, type:type, env:env)
140
+ local = config.local(pkg:pkg, type:type, env:env)
141
+ build = config.build(pkg:pkg, type:type, env:env)
142
+
143
+ ssh = config.base(:ssh)
144
+ # replace "variables" in commands
145
+ command = test[:command].
146
+ gsub('%f', test[:folder]).# %f is the folder where the sources are rsync-ed
147
+ gsub('%t', build[:target]).# %t is the folder where the build places the result
148
+ gsub('%p', pkg.to_s) # %p is the package name
149
+ # take the sources from the local folder
150
+ local_folder = File.expand_path local[:folder]
151
+ # upload them to the test machine
152
+ upload_sources("#{local_folder}/", "#{test[:user]}@#{test[:machine]}:#{test[:folder]}")
153
+ puts 'Running all tests'
154
+ puts 'This will take some time and you have no output'
155
+ command("#{ssh} #{test[:user]}@#{test[:machine]} \"#{command}\"")
156
+ rescue CommandError => e
157
+ puts e.verbose_message
158
+ exit! ''
159
+ rescue KeyNotDefinedError => e
160
+ puts e.message
161
+ exit! ''
162
+ end
163
+
164
+ def upload_sources (source, dest)
165
+ config=Settings.instance
166
+ rsync = config.base(:rsync)
167
+ command("#{rsync} -az #{source} #{dest}")
168
+ end
169
+ rescue CommandError => e
170
+ puts e.verbose_message
171
+ exit! ''
172
+ rescue KeyNotDefinedError => e
173
+ puts e.message
174
+ exit! ''
175
+ end
176
+
177
+ end
178
+
@@ -7,142 +7,127 @@ class Hash
7
7
  include DeepSymbolizable
8
8
  end
9
9
 
10
- module Devinstall
11
10
 
12
- class KeyNotDefinedError < RuntimeError;
13
- end
14
11
 
15
- class UnknownKeyError < RuntimeError;
16
- end
12
+ module Devinstall
13
+
14
+ class KeyNotDefinedError < RuntimeError;end
15
+ class UnknownKeyError < RuntimeError;end
17
16
 
18
17
  class Settings
19
18
  include Singleton
20
19
 
21
- attr_accessor :env, :type
22
20
  FILES = []
23
21
  SETTINGS = {}
24
-
25
- def pkg=(pkg)
26
- if Array === pkg and pkg.length == 1
27
- @pkg = pkg[0]
28
- elsif pkg.class.method_defined? :to_sym
29
- @pkg = pkg.to_sym
30
- else
31
- @pkg = pkg
22
+ MDEFS={
23
+ local: [:folder, :temp],
24
+ build: [:user, :host, :folder, :target, :arch, :command, :provider],
25
+ install: [:user, :host, :folder, :type, :arch, :provider],
26
+ tests: [:machine, :folder, :user, :command, :provider],
27
+ repos: [:user, :host, :folder, :type, :arch]
28
+ }
29
+
30
+ class Action
31
+ include Enumerable
32
+
33
+ def initialize(set, sect, pkg, type, env)
34
+ @set=set
35
+ @sect=sect
36
+ @pkg=pkg
37
+ @type=type
38
+ @env=env
32
39
  end
33
- end
34
40
 
35
- def pkg
36
- @pkg
37
- end
38
-
39
- def validate
40
- raise KeyNotDefinedError, 'Missing package' unless self.pkg
41
- raise KeyNotDefinedError, 'Missing environment' unless self.env
42
- raise KeyNotDefinedError, 'Missing package type' unless self.type
43
- if Array === self.pkg
44
- self.pkg.each do |p|
45
- raise KeyNotDefinedError, "Package '#{p}' not defined" unless SETTINGS[:packages].has_key? p.to_sym
46
- raise KeyNotDefinedError, "Package #{p} type '#{type}' not defined " unless SETTINGS[:packages][p.to_sym].has_key? self.type
41
+ def valid?
42
+ config = Settings.instance
43
+ return false unless Settings::MDEFS.has_key? @sect
44
+ Settings::MDEFS[@sect].inject (true) do |res, k|
45
+ res and config.respond_to? @sect and config.send(@sect, k, pkg: @pkg, type: @type, env: @env)
47
46
  end
48
- else
49
- raise KeyNotDefinedError, "Package '#{pkg}' not defined" unless SETTINGS[:packages].has_key? self.pkg.to_sym
50
- raise KeyNotDefinedError, "Package #{pkg} type '#{type}' not defined " unless SETTINGS[:packages][self.pkg.to_sym].has_key? self.type
47
+ rescue KeyNotDefinedError => e
48
+ puts e.message
49
+ puts e.backtrace if $verbose
50
+ return false
51
51
  end
52
- rescue KeyNotDefinedError => e
53
- raise e
54
- rescue UnknownKeyError => e
55
- puts "Program error: #{e.message} at:"
56
- puts e.backtrace
57
- exit!
58
- end
59
52
 
60
- def load! (filename) # Multiple load -> merge settings
61
- unless File.exist?(File.expand_path(filename))
62
- puts "Unable to find config file \"#{File.expand_path(filename)}\""
63
- exit!
53
+ def [](key)
54
+ Settings.instance.send(@sect, key, pkg: @pkg, type: @type, env: @env)
64
55
  end
65
- unless FILES.include? filename
66
- FILES << filename
67
- newsets = YAML::load_file(filename).deep_symbolize
68
- deep_merge!(SETTINGS, newsets)
69
- end
70
- ### initialize type, env from defaults unless already defined
71
- self.env ||= defaults(:env).to_sym
72
- self.type ||= defaults(:type).to_sym
73
- end
74
56
 
75
- def deep_merge!(target, data)
76
- merger = proc do |_, v1, v2|
77
- Hash === v1 && Hash === v2 ? v1.merge(v2, &merger) : v2
57
+ def each
58
+ config=Settings.instance
59
+ Settings::MDEFS[@sect].each do |key|
60
+ yield(key, config.send(@sect, key, pkg: @pkg, type: @type, env: @env)) if block_given?
61
+ end
62
+ end
63
+ end ## Class Action
64
+
65
+ def load! (filename)
66
+ if File.exist?(File.expand_path(filename))
67
+ unless FILES.include? filename
68
+ FILES << filename
69
+ data = YAML::load_file(filename).deep_symbolize
70
+ merger = proc do |_, v1, v2|
71
+ Hash === v1 && Hash === v2 ? v1.merge(v2, &merger) : v2
72
+ end
73
+ SETTINGS.merge! data, &merger
74
+ end
78
75
  end
79
- target.merge! data, &merger
80
- end
81
-
82
- def self.defaults(key=nil)
83
- return SETTINGS.has_key? :defaults if key.nil?
84
- raise UnknownKeyError, "Don't know what are you asking about: '#{key}'" unless [:package, :type, :env, :providers].include? key
85
- SETTINGS[:defaults][key] or raise KeyNotDefinedError, "Undefined key :default:#{key.to_s}"
86
76
  end
87
77
 
88
78
  def defaults(key=nil)
89
- self.class.defaults key
79
+ return SETTINGS.has_key? :defaults if key.nil?
80
+ raise UnknownKeyError, "Unknowwn key: '#{key}'" unless [:package, :type, :env, :providers].include? key
81
+ return nil unless key_chain(:defaults, key)
82
+ SETTINGS[:defaults][key].to_sym or raise KeyNotDefinedError, "Undefined key :default:#{key.to_s}"
90
83
  end
91
84
 
92
- def self.base(key=nil)
85
+ def base(key=nil)
93
86
  return SETTINGS.has_key? :base if key.nil?
94
- raise UnknownKeyError, "Don't know what are you asking about: '#{key}'" unless [:rsync, :ssh, :sudo, :scp].include? key
87
+ raise UnknownKeyError, "Unknown key: '#{key}'" unless [:rsync, :ssh, :sudo, :scp].include? key
88
+ return nil unless key_chain(:base, key)
95
89
  SETTINGS[:base][key] or raise KeyNotDefinedError, "Undefined key :base:#{key.to_s}"
96
90
  end
97
91
 
98
- def base(key=nil)
99
- self.class.base key
100
- end
101
-
102
- def global_or_local(section, key)
103
- ret = nil
104
- if SETTINGS[:packages][self.pkg][self.type].has_key? section
105
- ret ||= SETTINGS[:packages][self.pkg][self.type][section][self.env][key] if SETTINGS[:packages][self.pkg][self.type][section].has_key? self.env
106
- ret ||= SETTINGS[:packages][self.pkg][self.type][section][key] # or nil
92
+ def method_missing (m, *args)
93
+ raise UnknownKeyError, "Undefined section '#{m}'" unless MDEFS.has_key? m
94
+ key=(args.shift or {})
95
+ if Hash === key
96
+ pkg = key[:pkg] or raise 'package must be defined'
97
+ type = (key[:type] or defaults(:type))
98
+ env = (key[:env] or defaults(:env))
99
+ return Action.new(SETTINGS, m, pkg, type, env)
107
100
  end
108
- ret ||= SETTINGS[section][self.env][key] if SETTINGS[section].has_key? self.env
109
- ret ||= SETTINGS[section][key] # or nil
110
- ret
111
- end
112
-
113
- def local(key=nil)
114
- return SETTINGS.has_key? :local if key.nil?
115
- raise UnknownKeyError, "Don't know what are you asking about: '#{key}'" unless [:folder, :temp].include? key
116
- global_or_local(:local, key) or raise KeyNotDefinedError, "Undefined key :local:#{key} or :#{self.pkg}:local:#{key}"
101
+ rest=(args.shift or {})
102
+ (pkg = rest[:pkg]) or raise 'package must be defined'
103
+ type = (rest[:type] or defaults(:type))
104
+ env = (rest[:env] or defaults(:env))
105
+ pkg=pkg.to_sym
106
+ raise UnknownKeyError, "Unknown key #{key}" unless MDEFS[m].include? key
107
+ global_or_local(m, key, pkg, type, env) or raise KeyNotDefinedError, "Undefined key '#{m}:#{key}' or alternate for ['#{pkg}' '#{type}' '#{env}']"
117
108
  end
118
109
 
119
- def build(key=nil)
120
- return (SETTINGS.has_key? :build or SETTINGS[:packages][self.pkg][self.type].has_key? :build) if key.nil?
121
- raise UnknownKeyError, "Don't know what are you asking about: '#{key}'" unless [:user, :host, :folder, :target, :arch, :command, :provider].include? key
122
- global_or_local(:build, key) or raise KeyNotDefinedError, "Undefined key :build:#{key} or :#{self.pkg}:#{self.type}:build:#{key}"
110
+ def respond_to_missing?(method, _)
111
+ MDEFS.has_key? method and SETTINGS.has_key? method
123
112
  end
124
113
 
125
- def install(key=nil)
126
- return SETTINGS.has_key? :install if key.nil?
127
- raise UnknownKeyError, "Don't know what are you asking about: '#{key}'" unless [:user, :host, :folder, :type, :arch, :provider].include? key
128
- global_or_local(:install, key) or raise KeyNotDefinedError, "Undefined key :install:#{self.env.to_s}:#{key} or :#{self.pkg}:install:#{self.env.to_s}:#{key}"
129
- end
114
+ private
130
115
 
131
- def tests(key=nil) # tests don't have 'env'
132
- return SETTINGS.has_key?(:tests) if key.nil?
133
- raise UnknownKeyError, "Don't know what are you asking about: '#{key}'" unless [:machine, :folder, :user, :command, :provider].include? key
134
- global_or_local(:tests, key) or raise KeyNotDefinedError, "Undefined key :tests:#{self.env.to_s}:#{key} or :#{self.pkg}:tests:#{self.env.to_s}:#{key}"
135
- end
136
-
137
- def repos(key=nil)
138
- return SETTINGS.has_key?(:repos) if key.nil?
139
- raise UnknownKeyError, "Don't know what are you asking about: '#{key}'" unless [:user, :host, :folder, :type, :arch].include? key
140
- global_or_local(:repos, key) or raise KeyNotDefinedError, "Undefined key :repos:environments:#{self.env.to_s}:#{key} or :#{self.pkg}:repos:#{self.env.to_s}:#{key}"
116
+ def key_chain(*keys)
117
+ res=SETTINGS
118
+ keys.each do |key|
119
+ next if key.nil?
120
+ return nil unless res.has_key? key
121
+ res=res[key]
122
+ end
123
+ res
141
124
  end
142
125
 
143
- def packages(key=nil)
144
- return SETTINGS.has_key?(:packages) if key.nil?
145
- SETTINGS[:packages][key] ## no checks here!
126
+ def global_or_local(section, key, pkg, type, env)
127
+ key_chain(:packages, pkg, type, section, env, key) ||
128
+ key_chain(:packages, pkg, type, section, key) ||
129
+ key_chain(section, env, key) ||
130
+ key_chain(section, key)
146
131
  end
147
132
 
148
133
  end
@@ -28,8 +28,8 @@ module Utils
28
28
  ret
29
29
  end
30
30
 
31
- def exit!(msg=nil)
32
- puts msg || 'Aborting!'
31
+ def exit!(msg='Aborting')
32
+ puts msg
33
33
  Kernel.exit 1
34
34
  end
35
35
 
@@ -1,3 +1,3 @@
1
1
  module Devinstall
2
- VERSION = '1.0.1' # Working!
2
+ VERSION = '1.1.0' # Working!
3
3
  end
data/lib/devinstall.rb CHANGED
@@ -2,168 +2,6 @@ require 'devinstall/version'
2
2
  require 'devinstall/deep_symbolize'
3
3
  require 'devinstall/utils'
4
4
  require 'devinstall/settings'
5
- require 'pp'
6
-
7
- module Devinstall
8
-
9
- class Pkg
10
-
11
- include Utils
12
-
13
- def get_version
14
- case @config.type
15
- when :deb
16
- begin
17
- deb_changelog = File.expand_path "#{@config.local(:folder)}/#{@package}/debian/changelog" # This is the folder that should be checked
18
- unless File.exists? deb_changelog
19
- exit! <<-eos
20
- No 'debian/changelog' found in specified :local:folder (#{@config.local(:folder)})
21
- Please check your config file
22
- eos
23
- end
24
- @_package_version[:deb] = File.open(deb_changelog, 'r') { |f| f.gets.chomp.sub(/^.*\((.*)\).*$/, '\1') }
25
- rescue IOError => e
26
- exit! <<-eos
27
- IO Error while opening #{deb_changelog}
28
- Aborting \n #{e}
29
- eos
30
- end
31
- end
32
- end
33
-
34
- # @param [String] package
35
- def initialize(package)
36
- @config=Settings.instance #class variable,first thing!
37
- @config.pkg=package # very important!
38
- @package = package # currently implemented only for .deb packages (for .rpm later :D)
39
- @_package_version = {} # versions for types:
40
- @package_files = {}
41
- arch = @config.build(:arch)
42
- p_name = "#{@package}_#{get_version}"
43
- @package_files[:deb] = {deb: "#{p_name}_#{arch}.deb",
44
- tgz: "#{p_name}.tar.gz",
45
- dsc: "#{p_name}.dsc",
46
- chg: "#{p_name}_amd64.changes"}
47
- end
48
-
49
- def upload
50
- scp = @config.base(:scp)
51
- repo = {}
52
- [:user, :host, :folder, :type].each do |k|
53
- repo[k] = @config.repos(k) # looks stupid
54
- end
55
- @package_files[type].each do |p, f|
56
- puts "Uploading #{f}\t\t[#{p}] to $#{repo[:host]}"
57
- command("#{scp} #{@config.local(:temp)}/#{f} #{repo[:user]}@#{repo[:host]}:#{repo[:folder]}")
58
- end
59
- rescue CommandError => e
60
- puts e.verbose_message
61
- exit! ''
62
- rescue KeyNotdefinederror => e
63
- puts e.message
64
- exit! ''
65
- end
66
-
67
- def build
68
- type = @config.type
69
- puts "Building package #{@package} type #{type}"
70
- build = {}
71
- [:user, :host, :folder, :target].each do |k|
72
- build[k] = @config.build(k)
73
- end
74
-
75
- ssh = @config.base(:ssh)
76
- build_command = @config.build(:command)
77
- rsync = @config.base(:rsync)
78
- local_folder = File.expand_path @config.local(:folder)
79
- local_temp = File.expand_path @config.local(:temp)
80
-
81
- build_command = build_command.gsub('%f', build[:folder]).
82
- gsub('%t', @config.build(:target)).
83
- gsub('%p', @package.to_s).
84
- gsub('%T', type.to_s)
85
-
86
- upload_sources("#{local_folder}/", "#{build[:user]}@#{build[:host]}:#{build[:folder]}")
87
- command("#{ssh} #{build[:user]}@#{build[:host]} \"#{build_command}\"")
88
- @package_files[type].each do |p, t|
89
- puts "Receiving target #{p.to_s} for #{t.to_s}"
90
- command("#{rsync} -az #{build[:user]}@#{build[:host]}:#{build[:target]}/#{t} #{local_temp}")
91
- end
92
- rescue CommandError => e
93
- puts e.verbose_message
94
- exit! ''
95
- rescue KeyNotdefinederror => e
96
- puts e.message
97
- exit! ''
98
- end
99
-
100
- def install
101
- env = @config.env
102
- puts "Installing #{@package} in #{env} environment."
103
- local_temp = @config.local(:temp)
104
- sudo = @config.base(:sudo)
105
- scp = @config.base(:scp)
106
- type = @config.type
107
- install = {}
108
- [:user, :host, :folder].each do |k|
109
- install[k] = @config.install(k)
110
- end
111
- install[:host] = [install[:host]] unless Array === install[:host]
112
- case type
113
- when :deb
114
- install[:host].each do |host|
115
- command("#{scp} #{local_temp}/#{@package_files[type][:deb]} #{install[:user]}@#{host}:#{install[:folder]}")
116
- command("#{sudo} #{install[:user]}@#{host} /usr/bin/dpkg -i #{install[:folder]}/#{@package_files[type][:deb]}")
117
- end
118
- else
119
- exit! "unknown package type '#{type.to_s}'"
120
- end
121
- rescue CommandError => e
122
- puts e.verbose_message
123
- exit! ''
124
- rescue KeyNotdefinederror => e
125
- puts e.message
126
- exit! ''
127
- end
128
-
129
- def run_tests
130
- # check if we have the test section in the configuration file
131
- unless @config.tests
132
- puts 'No test section in the config file.'
133
- puts 'Skipping tests'
134
- return
135
- end
136
- # for tests we will use almost the same setup as for build
137
- test = {}
138
- [:user, :machine, :command, :folder].each do |k|
139
- test[k] = @config.tests(k)
140
- end
141
- ssh = @config.base(:ssh)
142
- # replace "variables" in commands
143
- test[:command] = test[:command].
144
- gsub('%f', test[:folder]).# %f is the folder where the sources are rsync-ed
145
- gsub('%t', @config.build(:target)).# %t is the folder where the build places the result
146
- gsub('%p', @package.to_s) # %p is the package name
147
- # take the sources from the local folder
148
- local_folder = File.expand_path @config.local(:folder)
149
- # upload them to the test machine
150
- upload_sources("#{local_folder}/", "#{test[:user]}@#{test[:machine]}:#{test[:folder]}")
151
- puts 'Running all tests'
152
- puts 'This will take some time and you have no output'
153
- command("#{ssh} #{test[:user]}@#{test[:machine]} \"#{test[:command]}\"")
154
- end
155
-
156
- def upload_sources (source, dest)
157
- rsync = @config.base(:rsync)
158
- command("#{rsync} -az #{source} #{dest}")
159
- end
160
- rescue CommandError => e
161
- puts e.verbose_message
162
- exit! ''
163
- rescue KeyNotdefinederror => e
164
- puts e.message
165
- exit! ''
166
- end
167
-
168
- end
5
+ require 'devinstall/pkg'
6
+ require 'devinstall/cli'
169
7
 
@@ -4,12 +4,24 @@ require 'devinstall/settings'
4
4
 
5
5
  describe 'Settings' do
6
6
  config=Devinstall::Settings.instance
7
- config.load! "./doc/example.yml"
7
+ config.load! './doc/example.yml' ## use defaults for type and env
8
+
9
+ package=:devinstall
10
+ type=:deb
11
+ env=nil
12
+
13
+ it 'should load an existig file' do
14
+ expect(config.load!('doc/example.yml')).to be_true
15
+ end
16
+
17
+ it 'should not load an unexisting file' do
18
+ expect(config.load!('doc/unexisting.yml')).to be_false
19
+ end
8
20
 
9
21
  it 'should load at init' do
10
22
  expect(config).to be_an_instance_of(Devinstall::Settings)
11
- [:defaults, :base, :local, :build, :install, :tests, :packages, :repos].each do |p|
12
- expect(config.send(p)).to be_true
23
+ [:defaults, :base, :local, :build, :install, :tests, :repos].each do |p|
24
+ expect(config.respond_to? p).to be_true
13
25
  end # all sections loaded!
14
26
  end
15
27
 
@@ -17,8 +29,22 @@ describe 'Settings' do
17
29
  expect(config.defaults).to be_true
18
30
  end
19
31
 
20
- it 'should have a static default' do
21
- expect(Devinstall::Settings.defaults(:package)).to be(config.defaults(:package))
32
+ it 'should produce validators when hashes are given' do
33
+ expect(config.build(type:'deb', env:'dev', pkg:package)).to be_an_instance_of(Devinstall::Settings::Action)
34
+ end
35
+
36
+ it 'should produce validators when partial hashes are given' do
37
+ expect(config.build(pkg:package)).to be_an_instance_of(Devinstall::Settings::Action)
38
+ end
39
+
40
+ it 'should validate correct data' do
41
+ expect(rr=config.build(pkg:package, type:type, env:env)).to be_an_instance_of(Devinstall::Settings::Action)
42
+ expect(rr.valid?).to be_true
43
+ end
44
+
45
+ it 'should not validate incorrect data' do
46
+ expect(rr=config.build(pkg:package, type: :rpm, env:env)).to be_an_instance_of(Devinstall::Settings::Action)
47
+ expect(rr.valid?).to be_false
22
48
  end
23
49
 
24
50
  it 'should raise errors for unknown keys' do
@@ -26,6 +52,24 @@ describe 'Settings' do
26
52
  end
27
53
 
28
54
  it 'should raise errors for undefined keys' do
29
- expect{config.tests(:provider)}.to raise_error(Devinstall::KeyNotDefinedError)
55
+ expect{config.tests(:provider, pkg:package)}.to raise_error(Devinstall::KeyNotDefinedError)
30
56
  end
57
+
58
+ it 'should produce a value if aok' do
59
+ expect(config.build(:user, pkg:package)).to eq('dboca')
60
+ end
61
+
62
+ it 'validator should have a [] method' do
63
+ rr=config.build(pkg:package, type:type, env:env)
64
+ expect(rr[:user]).to eq('dboca')
65
+ end
66
+
67
+ it 'should enumerate all defined values' do
68
+ ar=[]
69
+ config.build(pkg:package, type:type, env:env).each do |k,v|
70
+ ar << k
71
+ end
72
+ expect(ar).to eql([:user, :host, :folder, :target, :arch, :command, :provider])
73
+ end
74
+
31
75
  end
metadata CHANGED
@@ -1,69 +1,94 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: devinstall
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.1
4
+ version: 1.1.0
5
+ prerelease:
5
6
  platform: ruby
6
7
  authors:
7
8
  - Dragos Boca
8
9
  autorequire:
9
10
  bindir: bin
10
11
  cert_chain: []
11
- date: 2013-05-02 00:00:00.000000000 Z
12
+ date: 2013-05-03 00:00:00.000000000 Z
12
13
  dependencies:
13
14
  - !ruby/object:Gem::Dependency
14
15
  name: bundler
15
16
  requirement: !ruby/object:Gem::Requirement
17
+ none: false
16
18
  requirements:
17
- - - '>='
19
+ - - ! '>='
18
20
  - !ruby/object:Gem::Version
19
21
  version: '0'
20
22
  type: :development
21
23
  prerelease: false
22
24
  version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
23
26
  requirements:
24
- - - '>='
27
+ - - ! '>='
25
28
  - !ruby/object:Gem::Version
26
29
  version: '0'
27
30
  - !ruby/object:Gem::Dependency
28
31
  name: rake
29
32
  requirement: !ruby/object:Gem::Requirement
33
+ none: false
30
34
  requirements:
31
- - - '>='
35
+ - - ! '>='
32
36
  - !ruby/object:Gem::Version
33
37
  version: '0'
34
38
  type: :development
35
39
  prerelease: false
36
40
  version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
37
42
  requirements:
38
- - - '>='
43
+ - - ! '>='
39
44
  - !ruby/object:Gem::Version
40
45
  version: '0'
41
46
  - !ruby/object:Gem::Dependency
42
47
  name: getopt
43
48
  requirement: !ruby/object:Gem::Requirement
49
+ none: false
44
50
  requirements:
45
- - - '>='
51
+ - - ! '>='
46
52
  - !ruby/object:Gem::Version
47
53
  version: '0'
48
54
  type: :development
49
55
  prerelease: false
50
56
  version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
51
58
  requirements:
52
- - - '>='
59
+ - - ! '>='
53
60
  - !ruby/object:Gem::Version
54
61
  version: '0'
55
62
  - !ruby/object:Gem::Dependency
56
63
  name: rspec
57
64
  requirement: !ruby/object:Gem::Requirement
65
+ none: false
58
66
  requirements:
59
- - - '>='
67
+ - - ! '>='
60
68
  - !ruby/object:Gem::Version
61
69
  version: '0'
62
70
  type: :development
63
71
  prerelease: false
64
72
  version_requirements: !ruby/object:Gem::Requirement
73
+ none: false
65
74
  requirements:
66
- - - '>='
75
+ - - ! '>='
76
+ - !ruby/object:Gem::Version
77
+ version: '0'
78
+ - !ruby/object:Gem::Dependency
79
+ name: commander
80
+ requirement: !ruby/object:Gem::Requirement
81
+ none: false
82
+ requirements:
83
+ - - ! '>='
84
+ - !ruby/object:Gem::Version
85
+ version: '0'
86
+ type: :development
87
+ prerelease: false
88
+ version_requirements: !ruby/object:Gem::Requirement
89
+ none: false
90
+ requirements:
91
+ - - ! '>='
67
92
  - !ruby/object:Gem::Version
68
93
  version: '0'
69
94
  description: remote builder and installer
@@ -86,6 +111,7 @@ files:
86
111
  - lib/devinstall.rb
87
112
  - lib/devinstall/cli.rb
88
113
  - lib/devinstall/deep_symbolize.rb
114
+ - lib/devinstall/pkg.rb
89
115
  - lib/devinstall/settings.rb
90
116
  - lib/devinstall/utils.rb
91
117
  - lib/devinstall/version.rb
@@ -93,26 +119,27 @@ files:
93
119
  homepage: http://github.com/dboca/devinstall
94
120
  licenses:
95
121
  - MIT
96
- metadata: {}
97
122
  post_install_message:
98
123
  rdoc_options: []
99
124
  require_paths:
100
125
  - lib
101
126
  required_ruby_version: !ruby/object:Gem::Requirement
127
+ none: false
102
128
  requirements:
103
- - - '>='
129
+ - - ! '>='
104
130
  - !ruby/object:Gem::Version
105
131
  version: '0'
106
132
  required_rubygems_version: !ruby/object:Gem::Requirement
133
+ none: false
107
134
  requirements:
108
- - - '>='
135
+ - - ! '>='
109
136
  - !ruby/object:Gem::Version
110
137
  version: '0'
111
138
  requirements: []
112
139
  rubyforge_project:
113
- rubygems_version: 2.0.3
140
+ rubygems_version: 1.8.25
114
141
  signing_key:
115
- specification_version: 4
142
+ specification_version: 3
116
143
  summary: Copy the source files to a build host, build the packages and install builded
117
144
  packages
118
145
  test_files:
checksums.yaml DELETED
@@ -1,7 +0,0 @@
1
- ---
2
- SHA1:
3
- metadata.gz: 020bb3bf72c1b2c8c0028b4f3325535ac560bd89
4
- data.tar.gz: dee754076fd8134e9f29ddd04e985495c62ed0ce
5
- SHA512:
6
- metadata.gz: bc609fc9b54577ebc424b47b106af5892c8af416d27634936302162546e084eb4ac273c3518a88a71f60c579d0c70f3763f158bafdf73aa31fc3442e0dd373ed
7
- data.tar.gz: df8ca74a6cddefa371bb4c7cc78a619ee0608396b022cd834a43fd55b78de47bc017688c1fb35dab9e269872de683642e9039363a4b1626439492caca7c1d789