boxes 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
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