vagabund 0.0.20

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,48 @@
1
+ module Vagabund
2
+ module Settler
3
+ module Errors
4
+ class SettlerError < Vagrant::Errors::VagrantError
5
+ attr_reader :original_error
6
+
7
+ error_namespace "vagabund.settler.errors"
8
+
9
+ def message(orig=true)
10
+ return super() if !orig || original_error.nil?
11
+ "#{original_error.class.name}: #{original_error.message}"
12
+ end
13
+
14
+ def backtrace(orig=true)
15
+ !orig || original_error.nil? ? super() : original_error.backtrace
16
+ end
17
+
18
+ def initialize(*args)
19
+ @original_error = args.shift if args.first.is_a?(Exception)
20
+ super(*args)
21
+ end
22
+ end
23
+
24
+ class PackageError < SettlerError; end
25
+ class ProjectError < SettlerError; end
26
+
27
+ class PackageBuildError < PackageError
28
+ error_key :package_build_error
29
+ end
30
+
31
+ class PackageCleanError < PackageError
32
+ error_key :package_clean_error
33
+ end
34
+
35
+ class PackageExtractionError < PackageError
36
+ error_key :package_extraction_error
37
+ end
38
+
39
+ class PackageInstallError < PackageError
40
+ error_key :package_install_error
41
+ end
42
+
43
+ class PackagePullError < PackageError
44
+ error_key :package_pull_error
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,215 @@
1
+ require_relative 'package_config'
2
+
3
+ module Vagabund
4
+ module Settler
5
+ module Packages
6
+ class Base
7
+ attr_reader :config
8
+
9
+ def provision(machine)
10
+ exec_before :package, machine
11
+
12
+ if skip?
13
+ machine.ui.warn "Skipping package #{name}-#{version} because skip flag was set."
14
+ return
15
+ end
16
+
17
+ pull machine
18
+ extract machine
19
+ build machine
20
+ install machine
21
+ clean machine
22
+
23
+ exec_after :package, machine
24
+ end
25
+
26
+ def build(machine)
27
+ exec_before :build, machine
28
+ machine.ui.detail "Building #{name}-#{version}..."
29
+ action_exec config.builder, machine
30
+ exec_after :build, machine
31
+ rescue StandardError => e
32
+ raise Settler::Errors::PackageBuildError, e
33
+ end
34
+
35
+ def clean(machine)
36
+ exec_before :clean, machine
37
+ machine.ui.detail "Cleaning up after #{name}-#{version}..."
38
+ action_exec config.cleaner, machine
39
+ exec_after :clean, machine
40
+ rescue StandardError => e
41
+ raise Settler::Errors::PackageCleanError, e
42
+ end
43
+
44
+ def extract(machine)
45
+ exec_before :extract, machine
46
+ machine.ui.detail "Unpacking #{name}-#{version}..."
47
+ action_exec config.extractor, machine
48
+ exec_after :extract, machine
49
+ rescue StandardError => e
50
+ raise Settler::Errors::PackageExtractionError, e
51
+ end
52
+
53
+ def install(machine)
54
+ exec_before :install, machine
55
+ machine.ui.detail "Installing #{name}-#{version}..."
56
+ action_exec config.installer, machine
57
+ exec_after :install, machine
58
+ rescue StandardError => e
59
+ raise Settler::Errors::PackageInstallError, e
60
+ end
61
+
62
+ def pull(machine)
63
+ exec_before :pull, machine
64
+ machine.ui.detail "Retrieving sources for #{name}-#{version}..."
65
+ action_exec config.puller, machine
66
+ exec_after :pull, machine
67
+ rescue StandardError => e
68
+ raise Settler::Errors::PackagePullError, e
69
+ end
70
+
71
+ def exec_before(action, machine)
72
+ hook_exec :before, action, machine
73
+ end
74
+
75
+ def exec_after(action, machine)
76
+ hook_exec :after, action, machine
77
+ end
78
+
79
+ def hook_exec(hook, action, machine)
80
+ hook_action = "#{hook.to_s}_#{action.to_s.gsub(/[eo]r$/, '')}"
81
+ return if config.send(hook_action).nil? || config.send(hook_action).empty?
82
+
83
+ machine.ui.detail "Executing custom :#{hook_action} hooks for package #{name}-#{version}..."
84
+ config.send(hook_action).each do |hact|
85
+ action_exec hact, machine
86
+ end
87
+ rescue StandardError => e
88
+ raise Settler::Errors::PackageError, e
89
+ end
90
+
91
+ def action_exec(command, machine)
92
+ self.class.instance_eval do
93
+ [:ask, :detail, :error, :info, :output, :warn].each do |cmd|
94
+ define_method cmd do |*args, &block|
95
+ machine.ui.send cmd, *args, &block
96
+ end
97
+ end
98
+
99
+ [:execute, :sudo, :test].each do |cmd|
100
+ define_method cmd do |*args, &block|
101
+ opts = {verbose: false}.merge(args.extract_options!)
102
+ if opts[:verbose] == true
103
+ machine.communicate.send cmd, *args, opts do |type,data|
104
+ color = type == :stderr ? :red : :green
105
+ options = {
106
+ color: color,
107
+ new_line: false,
108
+ prefix: false
109
+ }
110
+
111
+ detail(data, options)
112
+ block.call(type, data) unless block.nil?
113
+ end
114
+ else
115
+ machine.communicate.send cmd, *args, opts, &block
116
+ end
117
+ end
118
+ end
119
+
120
+ define_method :capture do |*args, &block|
121
+ output = ''
122
+ machine.communicate.execute *args do |type,data|
123
+ output += data if type == :stdout
124
+ block.call(type, data) unless block.nil?
125
+ end
126
+ output
127
+ end
128
+ end
129
+
130
+ instance_exec self, machine, machine.communicate, &command if command.is_a?(Proc)
131
+
132
+ self.class.instance_eval do
133
+ [:ask, :detail, :error, :info, :output, :warn, :capture, :execute, :sudo, :test].each do |cmd|
134
+ undef_method cmd
135
+ end
136
+ end
137
+ end
138
+
139
+ def configure(&block)
140
+ config.configure &block
141
+ end
142
+
143
+ def local_package
144
+ config.local_package
145
+ end
146
+ alias_method :local_file, :local_package
147
+
148
+ def build_path
149
+ config.build_path
150
+ end
151
+
152
+ def build_root
153
+ config.build_root
154
+ end
155
+
156
+ def name
157
+ config.name
158
+ end
159
+
160
+ def version
161
+ config.version
162
+ end
163
+
164
+ def source
165
+ config.source
166
+ end
167
+
168
+ def skip(s)
169
+ @skip = s unless s.nil?
170
+ @skip
171
+ end
172
+ alias_method :skip=, :skip
173
+
174
+ def skip?
175
+ @skip
176
+ end
177
+
178
+ protected
179
+
180
+ #
181
+ # Base.new 'poppler', '0.24.5', {url: 'http://poppler.freedesktop.org/poppler-0.24.5.tar.xz'}
182
+ #
183
+ # Supported source types:
184
+ # git: 'git url'
185
+ # local: '/path/to/local/file'
186
+ # url: 'http://example.com/path/to/file'
187
+ # url: 'ftp://user:pass@example.com/path/to/file'
188
+ # scp: '[user@]example.com:/path/to/file' # this might require ssh forwarding
189
+ def initialize(*args, &block)
190
+ opts = args.extract_options!
191
+ opts = {name: args.shift, version: args.shift}.merge(opts)
192
+ @config = PackageConfig.new(opts, &block)
193
+ end
194
+
195
+ def build_path_exists?(machine)
196
+ return machine.communicate.test("[ -d #{build_path} ]") ? true : false
197
+ end
198
+
199
+ def package_exists?(machine)
200
+ return machine.communicate.test("[ -f #{existing_package_file(machine)} ]") ? true : false
201
+ end
202
+
203
+ def existing_package_file(machine)
204
+ pkg_file = local_file
205
+
206
+ while !machine.communicate.test("[ -f #{pkg_file} ]") && !File.extname(pkg_file).empty? do
207
+ pkg_file = File.join(build_root, File.basename(pkg_file, File.extname(pkg_file)))
208
+ end
209
+ pkg_file
210
+ end
211
+
212
+ end
213
+ end
214
+ end
215
+ end
@@ -0,0 +1,39 @@
1
+ module Vagabund
2
+ module Settler
3
+ module Packages
4
+ class Config
5
+
6
+ def packages
7
+ @packages ||= []
8
+ end
9
+
10
+ def add_package(*args, &block)
11
+ if args.first.is_a?(Packages::Base)
12
+ pkg = args.shift
13
+ pkg.configure &block if block_given?
14
+ packages << pkg
15
+ else
16
+ add_package Package.new(*args, &block)
17
+ end
18
+ end
19
+ alias_method :package, :add_package
20
+ alias_method :package=, :add_package
21
+
22
+ def method_missing(meth, *args, &block)
23
+ packages.send meth, *args, &block
24
+ end
25
+
26
+ def respond_to_missing?(meth, include_private=false)
27
+ packages.respond_to? meth, include_private
28
+ end
29
+
30
+ protected
31
+
32
+ def initialize(*args)
33
+ @settler_config = args.shift if args.first.is_a?(Settler::Config)
34
+ @packages = args.shift if args.first.is_a?(Array)
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,118 @@
1
+ module Vagabund
2
+ module Settler
3
+ module Packages
4
+ class PackageConfig
5
+ attr_reader :config, :source
6
+
7
+ # Bit of metaprogramming to define methods like builder, installer,
8
+ # before_build, after_install, etc.
9
+ %w(package builder cleaner extractor installer puller).each do |action|
10
+ %w(before after).each do |hook|
11
+ hook_action = "#{hook}_#{action.gsub(/[eo]r$/, '')}"
12
+
13
+ # Defines before/after 'hook' methods for each action: before_build,
14
+ # before_pull, after_install, etc.
15
+ define_method hook_action.to_sym do |*args, &block|
16
+ if args.first.is_a?(String)
17
+ command = args.shift
18
+ opts = args.extract_options!
19
+
20
+ cmd_proc = Proc.new do |package, machine, channel|
21
+ cmd = "cd #{package.build_path}; #{command}"
22
+ execute cmd, {verbose: true}.merge(opts)
23
+ end
24
+
25
+ config.send "#{hook_action}=".to_sym, [] if config.send(hook_action.to_sym).nil?
26
+ config.send(hook_action.to_sym) << cmd_proc
27
+ end
28
+
29
+ if !args.empty? && (args.first.nil? || args.first.is_a?(Proc))
30
+ config.send "#{hook_action}=".to_sym, [] if config.send(hook_action.to_sym).nil?
31
+ config.send(hook_action.to_sym) << args.shift
32
+ end
33
+
34
+ if !block.nil? # block_given? doesn't work here
35
+ config.send "#{hook_action}=".to_sym, [] if config.send(hook_action.to_sym).nil?
36
+ config.send(hook_action.to_sym) << block
37
+ end
38
+
39
+ config.send "#{hook_action}".to_sym
40
+ end
41
+ end
42
+
43
+ if action == 'package'
44
+ alias_method :before, :before_package
45
+ alias_method :after, :after_package
46
+ next
47
+ end
48
+
49
+ # Defines custom action methods to override the built-in puller,
50
+ # extractor, builder, installer and cleaner.
51
+ define_method action.to_sym do |*args, &block|
52
+ if args.first.is_a?(String)
53
+ command = args.shift
54
+ opts = args.extract_options!
55
+
56
+ cmd_proc = Proc.new do |package, machine, channel|
57
+ cmd = "cd #{package.build_path}; #{command}"
58
+ execute cmd, {verbose: true}.merge(opts)
59
+ end
60
+
61
+ config.send "#{action}=".to_sym, cmd_proc
62
+ end
63
+
64
+ config.send "#{action}=".to_sym, args.shift if !args.empty? && (args.first.nil? || args.first.is_a?(Proc))
65
+ config.send "#{action}=".to_sym, block if !block.nil? # block_given? doesn't work here
66
+
67
+ config.send action.to_sym
68
+ end
69
+ alias_method "#{action}=".to_sym, action.to_sym
70
+ alias_method "#{action.gsub(/[eo]r$/, '')}_with".to_sym, action.to_sym
71
+ end
72
+
73
+ def build_root
74
+ config.build_root ||= "/tmp/#{name}-#{version}"
75
+ end
76
+
77
+ def build_path
78
+ config.build_path ||= File.join(build_root, "#{name}-#{version}")
79
+ end
80
+
81
+ def local_package
82
+ config.local_package ||= File.join(build_root, (File.basename(source.origin) rescue "#{name}-#{version}"))
83
+ end
84
+ alias_method :local_file, :local_package
85
+
86
+ def configure(&block)
87
+ instance_eval &block if block_given?
88
+ end
89
+
90
+ def method_missing(meth, *args, &block)
91
+ config.send meth, *args, &block
92
+ end
93
+
94
+ def respond_to_missing?(meth, include_private=false)
95
+ config.respond_to? meth, include_private
96
+ end
97
+
98
+ protected
99
+
100
+ def initialize(*args, &block)
101
+ @config = OpenStruct.new({builder: Package::BUILDER, cleaner: Package::CLEANER, extractor: Package::EXTRACTOR, installer: Package::INSTALLER, puller: Package::PULLER}.merge(args.extract_options!))
102
+
103
+ if config.respond_to?(:git)
104
+ @source = Sources::Git.new(config.git)
105
+ elsif config.respond_to?(:url)
106
+ @source = Sources::Url.new(config.url)
107
+ elsif config.respond_to?(:local)
108
+ @source = Sources::Local.new(config.local)
109
+ #elsif config.respond_to?(:scp)
110
+ # remote scp
111
+ end
112
+
113
+ configure &block if block_given?
114
+ end
115
+ end
116
+ end
117
+ end
118
+ end
@@ -0,0 +1,101 @@
1
+ require_relative 'errors'
2
+ require_relative 'packages/base'
3
+
4
+ module Vagabund
5
+ module Settler
6
+ module Packages
7
+ end
8
+
9
+ class Package < Packages::Base
10
+ EXTENSIONS = ['.gz', '.bz', '.bz2', '.xz', '.zip', '.tar', '.tgz', '.tbz', '.tbz2', '.txz']
11
+
12
+ BUILDER = Proc.new do |package, machine, channel|
13
+ execute "cd #{build_path}; ./configure && make", verbose: true
14
+ end
15
+
16
+ CLEANER = Proc.new do |package, machine, channel|
17
+ sudo "rm -rf #{build_root}"
18
+ end
19
+
20
+ EXTRACTOR = Proc.new do |package, machine, channel|
21
+ if build_path_exists?(machine)
22
+ machine.ui.warn "Build path #{build_path} already exists, using it for the build. If you would like to use a clean source tree, you should manually remove it and run `vagrant provision` again."
23
+ elsif File.directory?(local_package)
24
+ execute "cp -r #{local_package} #{build_path}" if local_package != build_path
25
+ else
26
+ execute "mkdir -p #{build_path}"
27
+ local_ext = File.extname(local_package)
28
+
29
+ case local_ext
30
+ when '.gz'
31
+ execute "cd #{build_root}; gzip -dc #{local_package} > #{build_path}/#{File.basename(local_package, local_ext)}"
32
+ when '.tgz'
33
+ execute "cd #{build_root}; gzip -dc #{local_package} > #{build_path}/#{File.basename(local_package, local_ext)}.tar"
34
+ when '.bz', '.bz2'
35
+ execute "cd #{build_root}; bzip2 -dc #{local_package} > #{build_path}/#{File.basename(local_package, local_ext)}"
36
+ when '.tbz', '.tbz2'
37
+ execute "cd #{build_root}; bzip2 -dc #{local_package} > #{build_path}/#{File.basename(local_package, local_ext)}.tar"
38
+ when '.xz'
39
+ execute "cd #{build_root}; xz -dc #{local_package} > #{build_path}/#{File.basename(local_package, local_ext)}"
40
+ when '.txz'
41
+ execute "cd #{build_root}; xz -dc #{local_package} > #{build_path}/#{File.basename(local_package, local_ext)}.tar"
42
+ when '.zip'
43
+ execute "cd #{build_root}; unzip #{local_package} -d #{build_path}"
44
+ execute("cd #{build_path}; mv #{File.basename(local_package, local_ext)}/* ./") rescue nil
45
+ execute("cd #{build_path}; mv #{File.basename(local_package, local_ext)}/.* ./") rescue nil
46
+ execute("cd #{build_path}; mv #{name}-#{version}/* ./") rescue nil
47
+ execute("cd #{build_path}; mv #{name}-#{version}/.* ./") rescue nil
48
+ execute("cd #{build_path}; rm -rf #{File.basename(local_package, local_ext)}") rescue nil
49
+ when '.tar'
50
+ begin
51
+ execute "cd #{build_root}; tar xf #{local_package} #{File.basename(local_package, local_ext)} -C #{build_path}"
52
+ rescue
53
+ begin
54
+ execute "cd #{build_root}; tar xf #{local_package} #{name}-#{version} -C #{build_path}"
55
+ rescue
56
+ execute "cd #{build_root}; tar xf #{local_package} -C #{build_path}"
57
+ end
58
+ end
59
+ end
60
+
61
+ build_files = ""
62
+ execute "cd #{build_path}; ls" do |type, data|
63
+ build_files = data
64
+ end
65
+
66
+ if build_files.split($/).length == 1
67
+ new_package_file = File.basename(build_files.chomp)
68
+ if Package::EXTENSIONS.include?(File.extname(new_package_file))
69
+ execute "mv #{File.join(build_path, new_package_file)} #{build_root}"
70
+ sudo "rm -rf #{local_package} #{build_path}"
71
+ config.local_package = File.join(build_root, new_package_file)
72
+
73
+ # Re-execute this proc directly instead of going back through extract() or action_exec()
74
+ detail "Unpacking #{local_package}..."
75
+ instance_exec self, machine, machine.communicate, &EXTRACTOR
76
+ end
77
+ end
78
+
79
+ end
80
+ end
81
+
82
+ INSTALLER = Proc.new do |package, machine, channel|
83
+ sudo "cd #{build_path}; make install", verbose: true
84
+ end
85
+
86
+ PULLER = Proc.new do |package, machine, channel|
87
+ if package_exists?(machine)
88
+ config.local_package = existing_package_file(machine)
89
+ machine.ui.warn "Package #{local_package} already exists, using it for the build. If you would like to re-download the package, you should manually remove it then run `vagrant provision` again."
90
+ else
91
+ source.pull machine, local_package
92
+ end
93
+ end
94
+
95
+ def self.new(*args, &block)
96
+ Packages::Base.new(*args, &block)
97
+ end
98
+ end
99
+ end
100
+ end
101
+
@@ -0,0 +1,120 @@
1
+ require_relative 'project_config'
2
+
3
+ module Vagabund
4
+ module Settler
5
+ module Projects
6
+ class Base
7
+ attr_reader :config
8
+
9
+ def provision(machine)
10
+ exec_before :project, machine
11
+ pull machine
12
+ exec_after :project, machine
13
+ end
14
+
15
+ def pull(machine)
16
+ exec_before :pull, machine
17
+ if config.puller.nil?
18
+ config.source.pull machine, project_path
19
+ else
20
+ action_exec config.puller, machine
21
+ end
22
+ exec_after :pull, machine
23
+ rescue StandardError => e
24
+ raise Settler::Errors::ProjectError, e
25
+ end
26
+
27
+ def exec_before(action, machine)
28
+ hook_exec :before, action, machine
29
+ end
30
+
31
+ def exec_after(action, machine)
32
+ hook_exec :after, action, machine
33
+ end
34
+
35
+ def hook_exec(hook, action, machine)
36
+ hook_action = "#{hook.to_s}_#{action.to_s.gsub(/[eo]r$/, '')}"
37
+ return if config.send(hook_action).nil? || config.send(hook_action).empty?
38
+
39
+ machine.ui.detail "Executing custom :#{hook_action} hooks for project #{name}..."
40
+ config.send(hook_action).each do |hact|
41
+ action_exec hact, machine
42
+ end
43
+ rescue StandardError => e
44
+ raise Settler::Errors::ProjectError, e
45
+ end
46
+
47
+ def action_exec(command, machine)
48
+ self.class.instance_eval do
49
+ [:ask, :detail, :error, :info, :output, :warn].each do |cmd|
50
+ define_method cmd do |*args, &block|
51
+ machine.ui.send cmd, *args, &block
52
+ end
53
+ end
54
+ [:execute, :sudo, :test].each do |cmd|
55
+ define_method cmd do |*args, &block|
56
+ opts = {verbose: false}.merge(args.extract_options!)
57
+ if opts[:verbose] == true
58
+ machine.communicate.send cmd, *args, opts do |type,data|
59
+ color = type == :stderr ? :red : :green
60
+ options = {
61
+ color: color,
62
+ new_line: false,
63
+ prefix: false
64
+ }
65
+
66
+ detail(data, options)
67
+ block.call(type, data) unless block.nil?
68
+ end
69
+ else
70
+ machine.communicate.send cmd, *args, opts, &block
71
+ end
72
+ end
73
+ end
74
+
75
+ define_method :capture do |*args, &block|
76
+ output = ''
77
+ machine.communicate.execute *args do |type,data|
78
+ output += data if type == :stdout
79
+ block.call(type, data) unless block.nil?
80
+ end
81
+ output
82
+ end
83
+ end
84
+
85
+ instance_exec self, machine, machine.communicate, &command if command.is_a?(Proc)
86
+
87
+ self.class.instance_eval do
88
+ [:ask, :detail, :error, :info, :output, :warn, :capture, :execute, :sudo, :test].each do |cmd|
89
+ undef_method cmd
90
+ end
91
+ end
92
+ end
93
+
94
+ def configure(&block)
95
+ config.configure &block
96
+ end
97
+
98
+ def name
99
+ config.name
100
+ end
101
+
102
+ def project_path
103
+ config.project_path
104
+ end
105
+
106
+ protected
107
+
108
+ #
109
+ # Base.new 'my_project', {git: 'git@github.com:/user/repo.git'}
110
+ #
111
+ def initialize(*args, &block)
112
+ opts = args.extract_options!
113
+ opts = {name: args.shift}.merge(opts)
114
+ @config = ProjectConfig.new(opts, &block)
115
+ end
116
+
117
+ end
118
+ end
119
+ end
120
+ end
@@ -0,0 +1,51 @@
1
+ module Vagabund
2
+ module Settler
3
+ module Projects
4
+ class Config
5
+
6
+ def projects_path
7
+ @projects_path ||= '/vagrant'
8
+ end
9
+ alias_method :path, :projects_path
10
+
11
+ def projects_path=(path)
12
+ @projects_path = path
13
+ end
14
+ alias_method :path=, :projects_path=
15
+
16
+ def projects
17
+ @projects ||= []
18
+ end
19
+
20
+ def add_project(*args, &block)
21
+ if args.first.is_a?(Projects::Base)
22
+ prj = args.shift
23
+ prj.config.projects_path ||= projects_path
24
+ prj.configure &block if block_given?
25
+ projects << prj
26
+ else
27
+ args.push({projects_path: projects_path}.merge(args.extract_options!))
28
+ add_project Project.new(*args, &block)
29
+ end
30
+ end
31
+ alias_method :project, :add_project
32
+ alias_method :project=, :add_project
33
+
34
+ def method_missing(meth, *args, &block)
35
+ projects.send meth, *args, &block
36
+ end
37
+
38
+ def respond_to_missing?(meth, include_private=false)
39
+ projects.respond_to? meth, include_private
40
+ end
41
+
42
+ protected
43
+
44
+ def initialize(*args)
45
+ @settler_config = args.shift if args.first.is_a?(Settler::Config)
46
+ @projects = args.shift if args.first.is_a?(Array)
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end