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 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
@@ -0,0 +1,13 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+
11
+ output-*
12
+ *.box
13
+ packer_cache/
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
@@ -0,0 +1,3 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
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
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'rubygems'
4
+ require 'boxes'
5
+
6
+ Boxes::Command.run(ARGV)
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,8 @@
1
+ Feature: We can return the boxes help
2
+
3
+ Scenario: A successful response
4
+ When I run `boxes --help`
5
+ Then the output should contain "$ boxes"
6
+ Then the output should contain "Usage:"
7
+ Then the output should contain "Options:"
8
+ And the exit status should be 0
@@ -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