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 +2 -31
- data/devinstall.gemspec +1 -0
- data/doc/example.yml +1 -1
- data/lib/devinstall/cli.rb +66 -67
- data/lib/devinstall/pkg.rb +178 -0
- data/lib/devinstall/settings.rb +88 -103
- data/lib/devinstall/utils.rb +2 -2
- data/lib/devinstall/version.rb +1 -1
- data/lib/devinstall.rb +2 -164
- data/spec/settings_spec.rb +50 -6
- metadata +42 -15
- checksums.yaml +0 -7
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
|
4
|
+
require 'devinstall'
|
5
5
|
|
6
|
-
|
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
data/doc/example.yml
CHANGED
data/lib/devinstall/cli.rb
CHANGED
@@ -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
|
6
|
-
class Cli
|
6
|
+
module Cli
|
7
7
|
|
8
|
-
|
8
|
+
program :name, 'DevInstall'
|
9
|
+
program :version, Devinstall::VERSION
|
10
|
+
program :description, 'Poor man builder/installer'
|
9
11
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
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
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
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
|
-
|
50
|
-
|
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
|
-
|
57
|
-
|
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
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
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
|
-
|
74
|
-
|
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
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
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
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
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
|
+
|
data/lib/devinstall/settings.rb
CHANGED
@@ -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
|
-
|
16
|
-
|
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
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
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
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
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
|
-
|
49
|
-
|
50
|
-
|
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
|
-
|
61
|
-
|
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
|
-
|
76
|
-
|
77
|
-
|
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
|
-
|
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
|
85
|
+
def base(key=nil)
|
93
86
|
return SETTINGS.has_key? :base if key.nil?
|
94
|
-
raise UnknownKeyError, "
|
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
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
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
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
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
|
120
|
-
|
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
|
-
|
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
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
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
|
144
|
-
|
145
|
-
|
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
|
data/lib/devinstall/utils.rb
CHANGED
data/lib/devinstall/version.rb
CHANGED
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 '
|
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
|
|
data/spec/settings_spec.rb
CHANGED
@@ -4,12 +4,24 @@ require 'devinstall/settings'
|
|
4
4
|
|
5
5
|
describe 'Settings' do
|
6
6
|
config=Devinstall::Settings.instance
|
7
|
-
config.load!
|
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, :
|
12
|
-
expect(config.
|
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
|
21
|
-
expect(
|
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
|
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-
|
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:
|
140
|
+
rubygems_version: 1.8.25
|
114
141
|
signing_key:
|
115
|
-
specification_version:
|
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
|