devinstall 1.0.1 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/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
|