boxes 2.0.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.
- checksums.yaml +7 -0
- data/.gitignore +13 -0
- data/.ruby-version +1 -0
- data/CHANGELOG.md +9 -0
- data/Gemfile +3 -0
- data/LICENSE +22 -0
- data/README.md +51 -0
- data/Rakefile +34 -0
- data/bin/boxes +6 -0
- data/boxes.gemspec +39 -0
- data/features/boxes.feature +8 -0
- data/features/build.feature +16 -0
- data/features/env.feature +18 -0
- data/features/support/env.rb +1 -0
- data/lib/boxes.rb +28 -0
- data/lib/boxes/builder.rb +77 -0
- data/lib/boxes/command.rb +12 -0
- data/lib/boxes/command/build.rb +45 -0
- data/lib/boxes/command/env.rb +50 -0
- data/lib/boxes/config.rb +73 -0
- data/lib/boxes/environment.rb +74 -0
- data/lib/boxes/errors.rb +19 -0
- data/lib/boxes/subprocess.rb +39 -0
- data/lib/boxes/template.rb +50 -0
- data/lib/boxes/version.rb +4 -0
- data/scripts/ansible.sh +13 -0
- data/scripts/chef.sh +28 -0
- data/scripts/postinstall.sh +42 -0
- data/scripts/puppet.sh +14 -0
- data/scripts/purge.sh +60 -0
- data/scripts/ruby.sh +41 -0
- data/scripts/vmtools.sh +32 -0
- data/spec/boxes/builder_spec.rb +52 -0
- data/spec/boxes/config_spec.rb +142 -0
- data/spec/boxes/environment_spec.rb +73 -0
- data/spec/boxes/subprocess_spec.rb +35 -0
- data/spec/boxes/template_spec.rb +53 -0
- data/spec/spec_helper.rb +5 -0
- data/spec/support/subprocess_command.rb +7 -0
- data/templates/debian/preseed.cfg +69 -0
- data/templates/debian/wheezy64.erb +59 -0
- data/templates/ubuntu/precise64.erb +59 -0
- data/templates/ubuntu/preseed.cfg +61 -0
- data/templates/ubuntu/trusty64.erb +59 -0
- metadata +230 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 61968a830b3bc14160ec9f1da648d4d25692e4de
|
4
|
+
data.tar.gz: 9488c5e6f4b90c8f8cbdc163b919cfecfca86a05
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 9055590e48fa44358ecf33105e2329b29383c6ea1dbf2612d1eb8630abcb2c320578d53af38ca32c6cbdf97a3924389fe50bc4be43a08aaeea2f7e9320d44e0a
|
7
|
+
data.tar.gz: a29840bdc11b837c7d53e50c072b8ab28d0a855a54e407c827044a394df078d84f89cbe9774fc6b439e9d5cc37fff129104d3aca028e4cb994fa4e671899129d
|
data/.gitignore
ADDED
data/.ruby-version
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
ruby-2.2.2
|
data/CHANGELOG.md
ADDED
@@ -0,0 +1,9 @@
|
|
1
|
+
# CHANGELOG
|
2
|
+
|
3
|
+
## 2.0.0 (10/10/2015)
|
4
|
+
|
5
|
+
* Conversion to being a command line tool distributed through Ruby Gems.
|
6
|
+
* Basic test coverage using Specs and Feature tests.
|
7
|
+
* Maintains an environment for running builds.
|
8
|
+
* Parses, validates and combines arguments.
|
9
|
+
* Allows the building of all of the previous styles of boxes.
|
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2013 Nick Charlton
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
# boxes
|
2
|
+
|
3
|
+
[boxes][] takes the complexity out of building custom [Vagrant][] boxes.
|
4
|
+
|
5
|
+
It's a command line tool which provides a set of templates and scripts to
|
6
|
+
combine as you need. There are also a set of pre-build boxes which are
|
7
|
+
regenerated regularly.
|
8
|
+
|
9
|
+
## Installation & Requirements
|
10
|
+
|
11
|
+
```shell
|
12
|
+
[sudo] gem install boxes
|
13
|
+
```
|
14
|
+
|
15
|
+
boxes leans on [Packer][] and [VirtualBox][], [VMware Fusion][fusion] or
|
16
|
+
[VMware Workstation][workstation] for building boxes and these will need to
|
17
|
+
available in your `$PATH`.
|
18
|
+
|
19
|
+
## Usage
|
20
|
+
|
21
|
+
boxes is driven by the `boxes` command line tool, and works with artifacts
|
22
|
+
inside it's own working directory. You need to specify a name for the build,
|
23
|
+
a template to work with and the output provider. Something like so:
|
24
|
+
|
25
|
+
```shell
|
26
|
+
boxes build --name=trusty64-empty --template=ubuntu/trusty64 --provider=vmware
|
27
|
+
```
|
28
|
+
|
29
|
+
This will build a file called `trusty64-empty.box` in the current directory.
|
30
|
+
|
31
|
+
There's lots more to `boxes` than building simple empty Vagrant boxes like
|
32
|
+
this, which can be see in the inline help.
|
33
|
+
|
34
|
+
## Contributing
|
35
|
+
|
36
|
+
1. Fork it ( https://github.com/nickcharlton/boxes/fork )
|
37
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
38
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
39
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
40
|
+
5. Create a new Pull Request
|
41
|
+
|
42
|
+
## Author
|
43
|
+
|
44
|
+
Copyright (c) 2013 Nick Charlton <nick@nickcharlton.net>
|
45
|
+
|
46
|
+
[boxes]: http://boxes.io
|
47
|
+
[Vagrant]: http://vagrantup.com
|
48
|
+
[Packer]: https://packer.io
|
49
|
+
[VirtualBox]: https://www.virtualbox.org
|
50
|
+
[fusion]: https://www.vmware.com/products/fusion/features.html
|
51
|
+
[workstation]: https://www.vmware.com/products/workstation/features.html
|
data/Rakefile
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
#!/usr/bin/env rake
|
2
|
+
|
3
|
+
begin
|
4
|
+
require 'bundler/setup'
|
5
|
+
rescue LoadError
|
6
|
+
puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
|
7
|
+
end
|
8
|
+
|
9
|
+
require 'bundler/gem_tasks'
|
10
|
+
|
11
|
+
##
|
12
|
+
# Configure the test suite.
|
13
|
+
##
|
14
|
+
require 'rspec/core'
|
15
|
+
require 'rspec/core/rake_task'
|
16
|
+
|
17
|
+
RSpec::Core::RakeTask.new
|
18
|
+
|
19
|
+
##
|
20
|
+
# Cucumber for feature testing.
|
21
|
+
##
|
22
|
+
require 'rake/clean'
|
23
|
+
require 'cucumber'
|
24
|
+
require 'cucumber/rake/task'
|
25
|
+
|
26
|
+
Cucumber::Rake::Task.new(:features) do |t|
|
27
|
+
t.cucumber_opts = 'features --format pretty -x'
|
28
|
+
t.fork = false
|
29
|
+
end
|
30
|
+
|
31
|
+
##
|
32
|
+
# By default, just run the tests.
|
33
|
+
##
|
34
|
+
task default: :spec
|
data/bin/boxes
ADDED
data/boxes.gemspec
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'boxes/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = 'boxes'
|
8
|
+
spec.version = Boxes::VERSION
|
9
|
+
spec.authors = ['Nick Charlton']
|
10
|
+
spec.email = ['nick@nickcharlton.net']
|
11
|
+
|
12
|
+
spec.summary = 'A command line tool to take the complexity out of '\
|
13
|
+
'building Vagrant boxes.'
|
14
|
+
spec.description = <<-EOF
|
15
|
+
boxes takes the complexity out of building custom Vagrant boxes.
|
16
|
+
|
17
|
+
It's a command line tool which provides a set of templates and scripts to
|
18
|
+
combine as you need. There are also a set of pre-build boxes which are
|
19
|
+
regenerated regularly.'
|
20
|
+
EOF
|
21
|
+
spec.homepage = 'https://github.com/nickcharlton/boxes'
|
22
|
+
spec.license = 'MIT'
|
23
|
+
|
24
|
+
spec.files = `git ls-files`.split($RS)
|
25
|
+
spec.executables = spec.files.grep(/^bin/) { |f| File.basename(f) }
|
26
|
+
spec.test_files = spec.files.grep(/^(test|spec|features)/)
|
27
|
+
spec.require_paths = ['lib']
|
28
|
+
|
29
|
+
spec.add_dependency 'claide', '~> 0.9'
|
30
|
+
spec.add_dependency 'colored', '~> 1.2'
|
31
|
+
|
32
|
+
spec.add_development_dependency 'bundler', '~> 1.9'
|
33
|
+
spec.add_development_dependency 'rake', '~> 10.4'
|
34
|
+
spec.add_development_dependency 'rspec', '~> 3.3'
|
35
|
+
spec.add_development_dependency 'cucumber', '~> 1.3'
|
36
|
+
spec.add_development_dependency 'aruba', '~> 0.8'
|
37
|
+
spec.add_development_dependency 'fakefs', '~> 0.6'
|
38
|
+
spec.add_development_dependency 'pry'
|
39
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
Feature: We can build boxes
|
2
|
+
|
3
|
+
Scenario: It will error without a name
|
4
|
+
When I run `boxes build --template=ubuntu/trusty64 --provider=vmware`
|
5
|
+
Then the output should contain "[!] A name is required!"
|
6
|
+
And the exit status should be 1
|
7
|
+
|
8
|
+
Scenario: It will error without a provider
|
9
|
+
When I run `boxes build --name=trusty64-standard --template=ubuntu/trusty64`
|
10
|
+
Then the output should contain "[!] A provider is required!"
|
11
|
+
And the exit status should be 1
|
12
|
+
|
13
|
+
Scenario: It will error without a template
|
14
|
+
When I run `boxes build --name=trusty64-standard --provider=vmware`
|
15
|
+
Then the output should contain "[!] A template is required!"
|
16
|
+
And the exit status should be 1
|
@@ -0,0 +1,18 @@
|
|
1
|
+
Feature: We can manage the boxes environment
|
2
|
+
|
3
|
+
Scenario: It shows the environment by default
|
4
|
+
When I run `boxes env`
|
5
|
+
Then the output should contain "Configuration:"
|
6
|
+
Then the output should contain "Environment Variables:"
|
7
|
+
And the exit status should be 0
|
8
|
+
|
9
|
+
Scenario: It has a show command
|
10
|
+
When I run `boxes env show`
|
11
|
+
Then the output should contain "Configuration:"
|
12
|
+
Then the output should contain "Environment Variables:"
|
13
|
+
And the exit status should be 0
|
14
|
+
|
15
|
+
Scenario: It can clean the environment
|
16
|
+
When I run `boxes env clean`
|
17
|
+
Then the directory named "~/.boxes/env" does not exist
|
18
|
+
And the exit status should be 0
|
@@ -0,0 +1 @@
|
|
1
|
+
require 'aruba/cucumber'
|
data/lib/boxes.rb
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'fileutils'
|
2
|
+
require 'pathname'
|
3
|
+
require 'yaml'
|
4
|
+
require 'open3'
|
5
|
+
require 'erb'
|
6
|
+
|
7
|
+
require 'claide'
|
8
|
+
require 'colored'
|
9
|
+
|
10
|
+
require 'boxes/version'
|
11
|
+
require 'boxes/errors'
|
12
|
+
require 'boxes/config'
|
13
|
+
require 'boxes/subprocess'
|
14
|
+
require 'boxes/environment'
|
15
|
+
require 'boxes/template'
|
16
|
+
require 'boxes/builder'
|
17
|
+
require 'boxes/command'
|
18
|
+
|
19
|
+
# Toolkit for building Vagrantboxes, VM and cloud images.
|
20
|
+
module Boxes
|
21
|
+
class << self
|
22
|
+
attr_reader :config
|
23
|
+
|
24
|
+
def config
|
25
|
+
@config ||= Config.new
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,77 @@
|
|
1
|
+
module Boxes
|
2
|
+
# Class which drives the build process.
|
3
|
+
class Builder
|
4
|
+
include Boxes::Errors
|
5
|
+
|
6
|
+
attr_accessor :name, :template, :scripts, :provider
|
7
|
+
|
8
|
+
# Initialise a new build.
|
9
|
+
#
|
10
|
+
# @param env [Boxes::Environment] environment to operate in.
|
11
|
+
# @param args [Hash]
|
12
|
+
# @param template [String] the name of the template.
|
13
|
+
# @param scripts [Array] scripts to include in the build.
|
14
|
+
def initialize(env, args) # rubocop:disable Metrics/MethodLength
|
15
|
+
@name = args[:name] || fail(MissingArgumentError,
|
16
|
+
'The name must be specified.')
|
17
|
+
@provider = args[:provider] || fail(MissingArgumentError,
|
18
|
+
'The provider must be specified.')
|
19
|
+
template = args[:template] || fail(MissingArgumentError,
|
20
|
+
'The template must be specified.')
|
21
|
+
scripts = args.fetch(:scripts, [])
|
22
|
+
|
23
|
+
@template = Template.new(env, template)
|
24
|
+
@scripts = scripts.collect do |c|
|
25
|
+
env.available_scripts.include?(c) ? c : fail(ScriptNotFoundError)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
# Run the build.
|
30
|
+
def run # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
|
31
|
+
original_directory = FileUtils.pwd
|
32
|
+
box_name = ''
|
33
|
+
|
34
|
+
# render the template
|
35
|
+
rendered_template = template.render(name: name,
|
36
|
+
provider: provider,
|
37
|
+
scripts: scripts)
|
38
|
+
|
39
|
+
# write the template to a file
|
40
|
+
File.open(Boxes.config.working_dir + "#{build_name}.json", 'w') do |f|
|
41
|
+
f.puts rendered_template
|
42
|
+
end
|
43
|
+
|
44
|
+
# execute the packer command
|
45
|
+
FileUtils.chdir(Boxes.config.working_dir)
|
46
|
+
cmd = "packer build #{build_name}.json"
|
47
|
+
status = Subprocess.run(cmd) do |stdout, stderr, _thread|
|
48
|
+
puts stdout unless stdout.nil?
|
49
|
+
puts stderr unless stderr.nil?
|
50
|
+
|
51
|
+
# catch the name of the artifact
|
52
|
+
if stdout =~ /\.box/
|
53
|
+
box_name = stdout.gsub(/[a-zA-Z0-9:\-_]*?\.box/).first
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
if status.exitstatus == 0
|
58
|
+
FileUtils.mv(Boxes.config.working_dir + box_name,
|
59
|
+
"#{original_directory}/#{name}.box")
|
60
|
+
else
|
61
|
+
fail BuildRunError,
|
62
|
+
'The build didn\'t complete successfully. Check the logs.'
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
# Clean any temporary files used during building.
|
67
|
+
def clean
|
68
|
+
FileUtils.rm("#{build_name}.json")
|
69
|
+
end
|
70
|
+
|
71
|
+
private
|
72
|
+
|
73
|
+
def build_name
|
74
|
+
@build_name ||= "#{@name}-#{Time.now.strftime('%Y%m%d%H%M%S')}"
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
module Boxes
|
2
|
+
# Class which encapsulates the command line handling.
|
3
|
+
class Command < CLAide::Command
|
4
|
+
require 'boxes/command/build'
|
5
|
+
require 'boxes/command/env'
|
6
|
+
|
7
|
+
self.abstract_command = true
|
8
|
+
self.command = 'boxes'
|
9
|
+
self.version = VERSION
|
10
|
+
self.description = 'Toolkit for building Vagrantboxes, VM and cloud images.'
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
module Boxes
|
2
|
+
class Command
|
3
|
+
# Command handling for the box building functionality.
|
4
|
+
class Build < Command
|
5
|
+
self.summary = 'Build boxes'
|
6
|
+
self.description = 'Builds boxes using templates and scripts.'
|
7
|
+
|
8
|
+
def self.options
|
9
|
+
[
|
10
|
+
['--name', 'The name for the build'],
|
11
|
+
['--provider=[virtualbox|vmware]',
|
12
|
+
'The provider to build the box for'],
|
13
|
+
['--template', 'Template to build the box with'],
|
14
|
+
['--scripts', 'Scripts to apply to the box']
|
15
|
+
].concat(super)
|
16
|
+
end
|
17
|
+
|
18
|
+
def initialize(argv)
|
19
|
+
@build = {}
|
20
|
+
@build[:name] = argv.option('name')
|
21
|
+
@build[:provider] = argv.option('provider')
|
22
|
+
@build[:template] = argv.option('template')
|
23
|
+
scripts = argv.option('scripts') || ''
|
24
|
+
@build[:scripts] = scripts.split(',')
|
25
|
+
|
26
|
+
super
|
27
|
+
end
|
28
|
+
|
29
|
+
def validate!
|
30
|
+
super
|
31
|
+
|
32
|
+
%w(name provider template).each do |key|
|
33
|
+
help! "A #{key} is required!" if @build[key.to_sym].nil?
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def run
|
38
|
+
env = Boxes::Environment.new
|
39
|
+
builder = Boxes::Builder.new(env, @build)
|
40
|
+
builder.run
|
41
|
+
builder.clean
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
module Boxes
|
2
|
+
class Command
|
3
|
+
# Command handling for the environment used for building boxes.
|
4
|
+
class Env < Command
|
5
|
+
self.abstract_command = true
|
6
|
+
self.default_subcommand = 'show'
|
7
|
+
|
8
|
+
self.summary = 'Manage the build environment'
|
9
|
+
self.description = 'Expore the environment that boxes uses for building '\
|
10
|
+
'inside of.'
|
11
|
+
|
12
|
+
# Prints out the environment and configuration.
|
13
|
+
class Show < Env
|
14
|
+
self.summary = 'Show the environment and configuration'
|
15
|
+
self.description = <<-DESC
|
16
|
+
This lists the environment variables and other parts of the
|
17
|
+
configuration that boxes uses to handle builds.
|
18
|
+
DESC
|
19
|
+
|
20
|
+
def run # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
|
21
|
+
puts 'Configuration:'.underline
|
22
|
+
puts ''
|
23
|
+
puts "HOME_DIR=\"#{Boxes.config.home_dir}\""
|
24
|
+
puts "WORKING_DIR=\"#{Boxes.config.working_dir}\""
|
25
|
+
puts "TEMPLATE_PATHS=\"#{Boxes.config.template_paths.join(', ')}\""
|
26
|
+
puts "SCRIPT_PATHS=\"#{Boxes.config.script_paths.join(', ')}\""
|
27
|
+
|
28
|
+
puts ''
|
29
|
+
puts 'Environment Variables:'.underline
|
30
|
+
puts ''
|
31
|
+
Boxes.config.environment_vars.each do |e|
|
32
|
+
puts "#{e.keys.join}=\"#{e.values.join}\""
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
# Tidies up the working environment
|
38
|
+
class Clean < Env
|
39
|
+
self.summary = 'Clean up the environment.'
|
40
|
+
self.description = 'Removes any files from the working directory.'
|
41
|
+
|
42
|
+
def run
|
43
|
+
working_dir = Boxes.config.working_dir
|
44
|
+
|
45
|
+
FileUtils.rm_rf(working_dir) if working_dir.exist?
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|