niman 0.0.1 → 0.0.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +2 -0
- data/.rspec +3 -0
- data/.travis.yml +10 -0
- data/Gemfile +8 -0
- data/README.md +56 -2
- data/bin/niman +4 -0
- data/lib/niman/cli/application.rb +48 -0
- data/lib/niman/exceptions.rb +10 -0
- data/lib/niman/installer.rb +18 -0
- data/lib/niman/library/file.rb +24 -0
- data/lib/niman/library/package.rb +18 -0
- data/lib/niman/nimanfile.rb +23 -0
- data/lib/niman/platform.rb +43 -0
- data/lib/niman/provisioner.rb +28 -0
- data/lib/niman/recipe.rb +28 -0
- data/lib/niman/shell.rb +27 -0
- data/lib/niman/vagrant/plugin.rb +10 -0
- data/lib/niman/vagrant/provisioner.rb +24 -0
- data/lib/niman/vagrant/shell.rb +46 -0
- data/lib/niman/version.rb +1 -1
- data/lib/niman.rb +5 -1
- data/niman.gemspec +4 -0
- data/spec/lib/installer_spec.rb +58 -0
- data/spec/lib/library/file_spec.rb +77 -0
- data/spec/lib/library/package_spec.rb +35 -0
- data/spec/lib/nimanfile_spec.rb +40 -0
- data/spec/lib/provisioner_spec.rb +68 -0
- data/spec/lib/recipe_spec.rb +59 -0
- data/spec/spec_helper.rb +89 -0
- metadata +91 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f4b4fbde2c69d5428cdeef5956a0781eded47766
|
4
|
+
data.tar.gz: cc99ba94749c533e2d0a953695a4b03ec0aec32e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 25581ac834d6daa7134e5ecf6708a22bd5e7e7bc74568325fd3389bafa7f2e9b7d3079115beed68848f69222933c7da194c70903360a24fae1909595e872c0ea
|
7
|
+
data.tar.gz: a98b0c0aa0417876e61c269aa8c203181ea74ae28194a397f6c79593c0d3ff39bf27af2152d170baf9be62378695e01c394ca538fa92211824abd276da2bc7fc
|
data/.gitignore
CHANGED
data/.rspec
ADDED
data/.travis.yml
ADDED
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# Niman
|
2
2
|
|
3
|
-
|
3
|
+
Niman is a proof-of-concept provisioner.
|
4
4
|
|
5
5
|
## Installation
|
6
6
|
|
@@ -20,7 +20,61 @@ Or install it yourself as:
|
|
20
20
|
|
21
21
|
## Usage
|
22
22
|
|
23
|
-
|
23
|
+
It starts with a `Nimanfile`:
|
24
|
+
|
25
|
+
```ruby
|
26
|
+
Niman::Recipe.configure do |config|
|
27
|
+
config.file do |file|
|
28
|
+
file.path = '/home/bob/hello.txt'
|
29
|
+
file.content = 'hello from alice'
|
30
|
+
file.mode = '0600'
|
31
|
+
end
|
32
|
+
end
|
33
|
+
```
|
34
|
+
This places a new file `hello.txt` in `/home/bob` with rights 0600.
|
35
|
+
|
36
|
+
A `Nimanfile` contains all necessary commands for `niman` to run.
|
37
|
+
|
38
|
+
### Packages
|
39
|
+
|
40
|
+
Use a concrete package in your script:
|
41
|
+
|
42
|
+
```ruby
|
43
|
+
Niman::Recipe.configure do |config|
|
44
|
+
config.package do |package|
|
45
|
+
package.name = "vim"
|
46
|
+
package.version = "7.4"
|
47
|
+
end
|
48
|
+
end
|
49
|
+
```
|
50
|
+
|
51
|
+
Custom packages live in `packages/`. Every package gets its own file.
|
52
|
+
Package description:
|
53
|
+
```ruby
|
54
|
+
#packages/ruby.rb
|
55
|
+
require 'niman'
|
56
|
+
class RubyPackage < Niman::Package
|
57
|
+
package :ubuntu, "ruby1.9.1"
|
58
|
+
package :centos, "ruby1.9.1"
|
59
|
+
end
|
60
|
+
```
|
61
|
+
In your `Nimanfile`:
|
62
|
+
```ruby
|
63
|
+
Niman::Recipe.configure do |config|
|
64
|
+
config.package do |package|
|
65
|
+
package.name "ruby"
|
66
|
+
package.path = "packages/ruby"
|
67
|
+
end
|
68
|
+
end
|
69
|
+
```
|
70
|
+
|
71
|
+
### Apply `Nimanfile`
|
72
|
+
|
73
|
+
To apply a `Nimanfile` run:
|
74
|
+
|
75
|
+
```bash
|
76
|
+
$ niman apply
|
77
|
+
```
|
24
78
|
|
25
79
|
## Contributing
|
26
80
|
|
data/bin/niman
ADDED
@@ -0,0 +1,48 @@
|
|
1
|
+
require 'thor'
|
2
|
+
require 'niman/recipe'
|
3
|
+
require 'niman/provisioner'
|
4
|
+
require "niman/shell"
|
5
|
+
require "niman/installer"
|
6
|
+
|
7
|
+
module Niman
|
8
|
+
module CLI
|
9
|
+
class Application < Thor
|
10
|
+
attr_accessor :client_shell, :silent
|
11
|
+
|
12
|
+
def initialize(*args)
|
13
|
+
super
|
14
|
+
@client_shell= Niman::Shell.new
|
15
|
+
@silent = false
|
16
|
+
end
|
17
|
+
|
18
|
+
desc "apply", "Applies a Nimanfile"
|
19
|
+
def apply
|
20
|
+
Niman::Recipe.from_file
|
21
|
+
config = Niman::Recipe.configuration
|
22
|
+
installer = Niman::Installer.new(shell: client_shell, managers:{
|
23
|
+
debian: 'apt-get -y',
|
24
|
+
redhat: 'yum -y'
|
25
|
+
})
|
26
|
+
provisioner = Niman::Provisioner.new(installer, config.instructions)
|
27
|
+
this = self
|
28
|
+
provisioner.run do |instruction|
|
29
|
+
this.say "Executing task #{instruction.description}" unless @quiet
|
30
|
+
end
|
31
|
+
rescue LoadError => e
|
32
|
+
error e.message
|
33
|
+
end
|
34
|
+
|
35
|
+
desc "setup", "Generates an empty Nimanfile"
|
36
|
+
def setup
|
37
|
+
content = <<-EOS
|
38
|
+
# -*- mode: ruby -*-
|
39
|
+
# vi: set ft=ruby :
|
40
|
+
Niman::Recipe.configure do |config|
|
41
|
+
end
|
42
|
+
EOS
|
43
|
+
File.open(Niman::Recipe::DEFAULT_FILENAME, "w") { |handle| handle.write(content) }
|
44
|
+
say "Created new file #{Niman::Recipe::DEFAULT_FILENAME}"
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'virtus'
|
2
|
+
require 'niman/exceptions'
|
3
|
+
|
4
|
+
module Niman
|
5
|
+
class Installer
|
6
|
+
include Virtus.model
|
7
|
+
|
8
|
+
attribute :managers, Hash[Symbol=>String], default: Hash.new
|
9
|
+
attribute :shell, Object
|
10
|
+
|
11
|
+
def install(packages)
|
12
|
+
package_manager = managers.fetch(shell.os.to_sym) { raise Niman::InstallError, shell.os }
|
13
|
+
Array(packages).each do |package|
|
14
|
+
shell.exec("#{package_manager} install #{package.name}", true)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'virtus'
|
2
|
+
|
3
|
+
module Niman
|
4
|
+
module Library
|
5
|
+
class File
|
6
|
+
include Virtus.model
|
7
|
+
|
8
|
+
attribute :path, String, default: ''
|
9
|
+
attribute :content, String, default: ''
|
10
|
+
|
11
|
+
def valid?
|
12
|
+
!self.path.nil? && !self.path.empty?
|
13
|
+
end
|
14
|
+
|
15
|
+
def run
|
16
|
+
::File.open(::File.expand_path(path), "w") { |handle| handle.write(content) }
|
17
|
+
end
|
18
|
+
|
19
|
+
def description
|
20
|
+
"File #{path}"
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module Niman
|
2
|
+
module Library
|
3
|
+
class Package
|
4
|
+
include Virtus.model
|
5
|
+
|
6
|
+
attribute :name, String, default: ""
|
7
|
+
attribute :version, String, default: ""
|
8
|
+
|
9
|
+
def description
|
10
|
+
name
|
11
|
+
end
|
12
|
+
|
13
|
+
def valid?
|
14
|
+
!name.empty?
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'niman/library/file'
|
2
|
+
|
3
|
+
module Niman
|
4
|
+
class Nimanfile
|
5
|
+
attr_reader :instructions
|
6
|
+
|
7
|
+
def initialize
|
8
|
+
@instructions = []
|
9
|
+
end
|
10
|
+
|
11
|
+
def file
|
12
|
+
f = Niman::Library::File.new
|
13
|
+
yield(f)
|
14
|
+
@instructions.push(f)
|
15
|
+
end
|
16
|
+
|
17
|
+
def package
|
18
|
+
package = Niman::Library::Package.new
|
19
|
+
yield(package)
|
20
|
+
@instructions.push(package)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
module Niman
|
2
|
+
class Platform
|
3
|
+
def initialize(platform)
|
4
|
+
@platform = platform
|
5
|
+
end
|
6
|
+
|
7
|
+
def windows?
|
8
|
+
(/cygwin|mswin|mingw|bccwin|wince|emx/ =~ @platform) != nil
|
9
|
+
end
|
10
|
+
|
11
|
+
def mac?
|
12
|
+
(/darwin/ =~ @platform) != nil
|
13
|
+
end
|
14
|
+
|
15
|
+
def unix?
|
16
|
+
!windows?
|
17
|
+
end
|
18
|
+
|
19
|
+
def linux?
|
20
|
+
unix? && !mac?
|
21
|
+
end
|
22
|
+
|
23
|
+
def linux_variant(exists_block, read_block)
|
24
|
+
variant = { :distro => nil, :family => nil }
|
25
|
+
|
26
|
+
if exists_block.('/etc/lsb-release')
|
27
|
+
lsb_release = read_block.('/etc/lsb-release')
|
28
|
+
variant = { :distro => $1 } if lsb_release =~ /^DISTRIB_ID=(.*)/
|
29
|
+
end
|
30
|
+
|
31
|
+
if exists_block.('/etc/debian_version')
|
32
|
+
variant[:distro] = :debian if variant[:distro].nil?
|
33
|
+
variant[:family] = :debian if variant[:variant].nil?
|
34
|
+
elsif exists_block.('/etc/redhat-release') or exists_block.('/etc/centos-release')
|
35
|
+
variant[:family] = :redhat if variant[:family].nil?
|
36
|
+
variant[:distro] = :centos if exists_block.('/etc/centos-release')
|
37
|
+
elsif exists_block.('/etc/SuSE-release')
|
38
|
+
variant[:distro] = :sles if variant[:distro].nil?
|
39
|
+
end
|
40
|
+
variant
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'niman/exceptions'
|
2
|
+
|
3
|
+
module Niman
|
4
|
+
class Provisioner
|
5
|
+
attr_reader :instructions
|
6
|
+
|
7
|
+
def initialize(installer, instructions)
|
8
|
+
@installer = installer
|
9
|
+
@instructions = Array(instructions)
|
10
|
+
end
|
11
|
+
|
12
|
+
def valid?
|
13
|
+
@instructions.all?(&:valid?)
|
14
|
+
end
|
15
|
+
|
16
|
+
def run
|
17
|
+
raise Niman::ConfigError unless self.valid?
|
18
|
+
@instructions.each do |instruction|
|
19
|
+
yield(instruction) if block_given?
|
20
|
+
if instruction.respond_to?(:run)
|
21
|
+
instruction.run
|
22
|
+
else
|
23
|
+
@installer.install(instruction)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
data/lib/niman/recipe.rb
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'niman/nimanfile'
|
2
|
+
|
3
|
+
module Niman
|
4
|
+
class Recipe
|
5
|
+
DEFAULT_FILENAME = 'Nimanfile'
|
6
|
+
class << self
|
7
|
+
attr_writer :configuration
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.configure
|
11
|
+
@configuration ||= Niman::Nimanfile.new
|
12
|
+
yield(@configuration)
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.configuration
|
16
|
+
@configuration
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.reset!
|
20
|
+
@configuration = Niman::Nimanfile.new
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.from_file
|
24
|
+
path = File.join(Dir.pwd, DEFAULT_FILENAME)
|
25
|
+
load DEFAULT_FILENAME
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
data/lib/niman/shell.rb
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'niman/platform'
|
2
|
+
|
3
|
+
module Niman
|
4
|
+
class Shell
|
5
|
+
def initialize
|
6
|
+
@platform = Niman::Platform.new(RUBY_PLATFORM)
|
7
|
+
end
|
8
|
+
|
9
|
+
def os
|
10
|
+
if @platform.linux?
|
11
|
+
variant = @platform.linux_variant(-> (fn){ File.exists?(fn)},
|
12
|
+
-> (fn){ File.read(fn)})
|
13
|
+
variant[:family]
|
14
|
+
else
|
15
|
+
raise Niman::UnsupportedOSError
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def exec(command, use_sudo=false)
|
20
|
+
if use_sudo
|
21
|
+
`sudo #{command}`
|
22
|
+
else
|
23
|
+
`#{command}`
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require "vagrant/util/retryable"
|
2
|
+
require 'niman/vagrant/shell'
|
3
|
+
|
4
|
+
module VagrantPlugins
|
5
|
+
class Provisioner < Vagrant.plugin("2", :provisioner)
|
6
|
+
include Vagrant::Util::Retryable
|
7
|
+
def configure(root_config)
|
8
|
+
end
|
9
|
+
|
10
|
+
def provision
|
11
|
+
require 'niman'
|
12
|
+
@machine.communicate.tap do |comm|
|
13
|
+
vagrant_shell = VagrantPlugins::RemoteShell.new(comm, @machine)
|
14
|
+
app = Niman::CLI::Application.new
|
15
|
+
app.client_shell = vagrant_shell
|
16
|
+
app.silent = true
|
17
|
+
app.apply
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def cleanup
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
module VagrantPlugins
|
2
|
+
class RemoteShell
|
3
|
+
def initialize(communication, machine)
|
4
|
+
@channel = communication
|
5
|
+
@machine = machine
|
6
|
+
@platform = Niman::Platform.new(ruby_platform)
|
7
|
+
end
|
8
|
+
|
9
|
+
def os
|
10
|
+
if @platform.linux?
|
11
|
+
variant = @platform.linux_variant(-> (fn){ @machine.communicate.test("cat #{fn}")},
|
12
|
+
-> (fn){ @channel.execute("cat #{fn}") do |type, data|
|
13
|
+
data.chomp
|
14
|
+
end})
|
15
|
+
variant[:family]
|
16
|
+
else
|
17
|
+
raise Niman::UnsupportedOSError
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def exec(command, use_sudo=false)
|
22
|
+
@machine.ui.info(command, {color: :green})
|
23
|
+
opts = { error_check: false, elevated: true }
|
24
|
+
@channel.sudo(command, opts) do |type, data|
|
25
|
+
if [:stderr, :stdout].include?(type)
|
26
|
+
#Output the data with the proper color based on the stream.
|
27
|
+
color = type == :stdout ? :green : :red
|
28
|
+
# Clear out the newline since we add one
|
29
|
+
data = data.chomp
|
30
|
+
next if data.empty?
|
31
|
+
options = {}
|
32
|
+
options[:color] = :green
|
33
|
+
@machine.ui.info(data.chomp, options)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
private
|
39
|
+
|
40
|
+
def ruby_platform
|
41
|
+
@channel.execute("ruby -e 'puts RUBY_PLATFORM'") do |type, data|
|
42
|
+
return data.chomp
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
data/lib/niman/version.rb
CHANGED
data/lib/niman.rb
CHANGED
data/niman.gemspec
CHANGED
@@ -17,6 +17,10 @@ Gem::Specification.new do |spec|
|
|
17
17
|
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
18
18
|
spec.require_paths = ["lib"]
|
19
19
|
|
20
|
+
spec.add_dependency 'thor', '~> 0.19'
|
21
|
+
spec.add_dependency "virtus", "~> 1.0.4"
|
22
|
+
spec.add_development_dependency "fakefs", "~> 0.5"
|
23
|
+
spec.add_development_dependency "rspec", "3.1"
|
20
24
|
spec.add_development_dependency "bundler", "~> 1.7"
|
21
25
|
spec.add_development_dependency "rake", "~> 10.0"
|
22
26
|
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'niman/installer'
|
3
|
+
|
4
|
+
describe Niman::Installer do
|
5
|
+
describe '#initialize' do
|
6
|
+
it 'accepts a hash of package managers' do
|
7
|
+
managers = {
|
8
|
+
ubuntu: 'apt-get',
|
9
|
+
centos: 'yum'
|
10
|
+
}
|
11
|
+
installer = Niman::Installer.new(managers: managers)
|
12
|
+
expect(installer.managers).to eq managers
|
13
|
+
end
|
14
|
+
|
15
|
+
it 'accepts a shell' do
|
16
|
+
shell = double()
|
17
|
+
installer = Niman::Installer.new(shell: shell)
|
18
|
+
expect(installer.shell).to eq shell
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
describe "#managers" do
|
23
|
+
it 'defaults to empty hash' do
|
24
|
+
installer = Niman::Installer.new
|
25
|
+
expect(installer.managers).to eq Hash.new
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
describe "#install" do
|
30
|
+
let(:shell) { double() }
|
31
|
+
subject(:installer) { Niman::Installer.new(managers: {
|
32
|
+
debian: 'apt-get',
|
33
|
+
redhat: 'yum'
|
34
|
+
}, shell: shell)}
|
35
|
+
let(:vim_package) { Niman::Library::Package.new(name: 'vim') }
|
36
|
+
let(:ssh_package) { Niman::Library::Package.new(name: 'ssh') }
|
37
|
+
let(:packages) { [vim_package, ssh_package] }
|
38
|
+
|
39
|
+
context 'with valid operating system' do
|
40
|
+
before do
|
41
|
+
allow(shell).to receive(:os).and_return(:debian)
|
42
|
+
allow(shell).to receive(:exec)
|
43
|
+
installer.install(packages)
|
44
|
+
end
|
45
|
+
|
46
|
+
['vim', 'ssh'].each do |package|
|
47
|
+
it "calls shell for #{package}" do
|
48
|
+
expect(shell).to have_received(:exec).with("apt-get install #{package}", true)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
it 'raises for unknown operating system' do
|
54
|
+
allow(shell).to receive(:os).and_return(:freebsd)
|
55
|
+
expect { installer.install(packages) }.to raise_error(Niman::InstallError)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,77 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'niman/library/file'
|
3
|
+
require 'fakefs'
|
4
|
+
|
5
|
+
describe Niman::Library::File do
|
6
|
+
subject(:file) { Niman::Library::File.new }
|
7
|
+
[:path, :content].each do |attribute|
|
8
|
+
it "responds to #{attribute}" do
|
9
|
+
expect(file.respond_to?(attribute)).to be true
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
describe '#initialize' do
|
14
|
+
it 'accepts path' do
|
15
|
+
f = Niman::Library::File.new(path: '/foo/bar')
|
16
|
+
expect(f.path).to eq '/foo/bar'
|
17
|
+
end
|
18
|
+
|
19
|
+
it 'accepts content' do
|
20
|
+
f = Niman::Library::File.new(content: 'Alice likes Bob')
|
21
|
+
expect(f.content).to eq 'Alice likes Bob'
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
describe '#content' do
|
26
|
+
it 'defaults to empty string' do
|
27
|
+
expect(file.content).to eq ''
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
describe '#path' do
|
32
|
+
it 'defaults to empty string' do
|
33
|
+
expect(file.path).to eq ''
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
describe "#valid?" do
|
38
|
+
specify 'if it has path' do
|
39
|
+
file.path = '/foo/bar'
|
40
|
+
expect(file.valid?).to be true
|
41
|
+
end
|
42
|
+
|
43
|
+
it 'is not valid when path is empty' do
|
44
|
+
expect(file.valid?).to be false
|
45
|
+
end
|
46
|
+
|
47
|
+
it 'is not valid when path is nil' do
|
48
|
+
file.path = nil
|
49
|
+
expect(file.valid?).to be false
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
describe "#run" do
|
54
|
+
let(:path) { 'hello.txt' }
|
55
|
+
let(:content) { 'FooBar' }
|
56
|
+
subject(:file) { Niman::Library::File.new(path: path, content: content) }
|
57
|
+
before do
|
58
|
+
file.run
|
59
|
+
end
|
60
|
+
|
61
|
+
it 'creates a file at path' do
|
62
|
+
expect(File.exists?(path)).to be true
|
63
|
+
end
|
64
|
+
|
65
|
+
it 'file has expected content' do
|
66
|
+
expect(File.read(path)).to eq content
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
describe "#description" do
|
71
|
+
let(:path) { 'hello.txt' }
|
72
|
+
subject(:file) { Niman::Library::File.new(path: path) }
|
73
|
+
it 'contains path' do
|
74
|
+
expect(file.description).to eq "File #{path}"
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'niman/library/package'
|
3
|
+
|
4
|
+
describe Niman::Library::Package do
|
5
|
+
subject(:package) { Niman::Library::Package.new }
|
6
|
+
[:name, :version, :description].each do |attribute|
|
7
|
+
it "responds to #{attribute}" do
|
8
|
+
expect(package.respond_to?(attribute)).to be true
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
describe "#name" do
|
13
|
+
it "defaults to empty string" do
|
14
|
+
expect(package.name).to eq ""
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
describe "#version" do
|
19
|
+
it "defaults to empty string" do
|
20
|
+
expect(package.version).to eq ""
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
describe '#valid?' do
|
25
|
+
it 'is true when name is present' do
|
26
|
+
package = Niman::Library::Package.new(name: 'vim')
|
27
|
+
expect(package.valid?).to be true
|
28
|
+
end
|
29
|
+
|
30
|
+
it 'is false when name is not present' do
|
31
|
+
package = Niman::Library::Package.new
|
32
|
+
expect(package.valid?).to be false
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'niman/nimanfile'
|
3
|
+
require 'niman/library/file'
|
4
|
+
|
5
|
+
describe Niman::Nimanfile do
|
6
|
+
subject(:niman_file) { Niman::Nimanfile.new }
|
7
|
+
|
8
|
+
it 'has no instructions' do
|
9
|
+
expect(niman_file.instructions.length).to eq 0
|
10
|
+
end
|
11
|
+
|
12
|
+
[:file, :package].each do |attribute|
|
13
|
+
it "has #{attribute} method" do
|
14
|
+
expect(niman_file.respond_to?(attribute)).to be true
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
specify 'file calls block with config object' do
|
19
|
+
expect { |b| niman_file.file(&b) }.to yield_with_args(Niman::Library::File)
|
20
|
+
end
|
21
|
+
|
22
|
+
specify 'package calls block with config object' do
|
23
|
+
expect { |b| niman_file.package(&b) }.to yield_with_args(Niman::Library::Package)
|
24
|
+
end
|
25
|
+
|
26
|
+
describe '#instructions' do
|
27
|
+
before do
|
28
|
+
niman_file.file {}
|
29
|
+
end
|
30
|
+
|
31
|
+
specify 'increases when #file is being called' do
|
32
|
+
expect(niman_file.instructions.length).to eq 1
|
33
|
+
end
|
34
|
+
|
35
|
+
specify 'contains file object' do
|
36
|
+
expect(niman_file.instructions.first).to be_kind_of(Niman::Library::File)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'niman/provisioner'
|
3
|
+
require 'niman/installer'
|
4
|
+
require 'niman/exceptions'
|
5
|
+
|
6
|
+
describe Niman::Provisioner do
|
7
|
+
let(:file) { Niman::Library::File.new(path: '~/hello.txt', content: 'ohai') }
|
8
|
+
let(:vim_package) { Niman::Library::Package.new(name: 'vim') }
|
9
|
+
let(:instructions) { [file, vim_package] }
|
10
|
+
let(:installer) { double(Niman::Installer) }
|
11
|
+
subject(:provisioner) { Niman::Provisioner.new(installer, instructions) }
|
12
|
+
|
13
|
+
describe "#initialize" do
|
14
|
+
it 'accepts a list of instructions' do
|
15
|
+
expect(provisioner.instructions).to eq [file, vim_package]
|
16
|
+
end
|
17
|
+
|
18
|
+
it 'accepts a single instruction' do
|
19
|
+
provisioner = Niman::Provisioner.new(installer, file)
|
20
|
+
expect(provisioner.instructions).to eq [file]
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
describe "#valid?" do
|
25
|
+
context 'with valid instructions' do
|
26
|
+
it 'returns true' do
|
27
|
+
expect(provisioner.valid?).to be true
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
context 'with invalid instructions' do
|
32
|
+
let(:invalid_file) { Niman::Library::File.new() }
|
33
|
+
let(:instructions) { [file, invalid_file] }
|
34
|
+
it 'returns false' do
|
35
|
+
expect(provisioner.valid?).to be false
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
describe "#run" do
|
41
|
+
context 'with invalid instructions' do
|
42
|
+
it 'raises when instruction is invalid' do
|
43
|
+
allow(provisioner).to receive(:valid?).and_return(false)
|
44
|
+
expect { provisioner.run }.to raise_error(Niman::ConfigError)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
context 'with valid instructions' do
|
49
|
+
before do
|
50
|
+
allow(file).to receive(:run)
|
51
|
+
allow(installer).to receive(:install)
|
52
|
+
provisioner.run
|
53
|
+
end
|
54
|
+
|
55
|
+
it 'calls run for runable instructions' do
|
56
|
+
expect(file).to have_received(:run)
|
57
|
+
end
|
58
|
+
|
59
|
+
it 'calls installer for package' do
|
60
|
+
expect(installer).to have_received(:install).with(vim_package)
|
61
|
+
end
|
62
|
+
|
63
|
+
it 'calls block for every instruction' do
|
64
|
+
expect { |b| provisioner.run(&b) }.to yield_successive_args(file, vim_package)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'niman/recipe'
|
3
|
+
|
4
|
+
describe Niman::Recipe do
|
5
|
+
describe '.configure' do
|
6
|
+
before do
|
7
|
+
Niman::Recipe.configure do |config|
|
8
|
+
config.file do |file|
|
9
|
+
file.path = '/home/bob/hello.txt'
|
10
|
+
file.content = 'hello from alice'
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
specify 'configuration has a file call' do
|
16
|
+
expect(Niman::Recipe.configuration.instructions.length).to eq 1
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
describe '.reset' do
|
21
|
+
before do
|
22
|
+
Niman::Recipe.configure do |config|
|
23
|
+
config.file do |file|
|
24
|
+
file.path = '/home/bob/hello.txt'
|
25
|
+
file.content = 'hello from alice'
|
26
|
+
end
|
27
|
+
end
|
28
|
+
Niman::Recipe.reset!
|
29
|
+
end
|
30
|
+
|
31
|
+
it 'erases current configuration' do
|
32
|
+
expect(Niman::Recipe.configuration.instructions.length).to eq 0
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
describe '.from_file' do
|
37
|
+
before do
|
38
|
+
FakeFS.deactivate!
|
39
|
+
content = <<-EOS
|
40
|
+
Niman::Recipe.configure do |config|
|
41
|
+
config.file do |file|
|
42
|
+
file.path = '/home/bob/hello.txt'
|
43
|
+
file.content = 'hello from alice'
|
44
|
+
end
|
45
|
+
end
|
46
|
+
EOS
|
47
|
+
File.open(Niman::Recipe::DEFAULT_FILENAME, "w") {|handle| handle.write(content) }
|
48
|
+
end
|
49
|
+
after do
|
50
|
+
File.delete(Niman::Recipe::DEFAULT_FILENAME)
|
51
|
+
FakeFS.activate!
|
52
|
+
end
|
53
|
+
|
54
|
+
it 'loads "Nimanfile" by default' do
|
55
|
+
Niman::Recipe.from_file
|
56
|
+
expect(Niman::Recipe.configuration.instructions.length).to eq 1
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,89 @@
|
|
1
|
+
# This file was generated by the `rspec --init` command. Conventionally, all
|
2
|
+
# specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
|
3
|
+
# The generated `.rspec` file contains `--require spec_helper` which will cause this
|
4
|
+
# file to always be loaded, without a need to explicitly require it in any files.
|
5
|
+
#
|
6
|
+
# Given that it is always loaded, you are encouraged to keep this file as
|
7
|
+
# light-weight as possible. Requiring heavyweight dependencies from this file
|
8
|
+
# will add to the boot time of your test suite on EVERY test run, even for an
|
9
|
+
# individual file that may not need all of that loaded. Instead, consider making
|
10
|
+
# a separate helper file that requires the additional dependencies and performs
|
11
|
+
# the additional setup, and require it from the spec files that actually need it.
|
12
|
+
#
|
13
|
+
# The `.rspec` file also contains a few flags that are not defaults but that
|
14
|
+
# users commonly want.
|
15
|
+
#
|
16
|
+
# See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
|
17
|
+
RSpec.configure do |config|
|
18
|
+
# rspec-expectations config goes here. You can use an alternate
|
19
|
+
# assertion/expectation library such as wrong or the stdlib/minitest
|
20
|
+
# assertions if you prefer.
|
21
|
+
config.expect_with :rspec do |expectations|
|
22
|
+
# This option will default to `true` in RSpec 4. It makes the `description`
|
23
|
+
# and `failure_message` of custom matchers include text for helper methods
|
24
|
+
# defined using `chain`, e.g.:
|
25
|
+
# be_bigger_than(2).and_smaller_than(4).description
|
26
|
+
# # => "be bigger than 2 and smaller than 4"
|
27
|
+
# ...rather than:
|
28
|
+
# # => "be bigger than 2"
|
29
|
+
expectations.include_chain_clauses_in_custom_matcher_descriptions = true
|
30
|
+
end
|
31
|
+
|
32
|
+
# rspec-mocks config goes here. You can use an alternate test double
|
33
|
+
# library (such as bogus or mocha) by changing the `mock_with` option here.
|
34
|
+
config.mock_with :rspec do |mocks|
|
35
|
+
# Prevents you from mocking or stubbing a method that does not exist on
|
36
|
+
# a real object. This is generally recommended, and will default to
|
37
|
+
# `true` in RSpec 4.
|
38
|
+
mocks.verify_partial_doubles = true
|
39
|
+
end
|
40
|
+
|
41
|
+
# The settings below are suggested to provide a good initial experience
|
42
|
+
# with RSpec, but feel free to customize to your heart's content.
|
43
|
+
=begin
|
44
|
+
# These two settings work together to allow you to limit a spec run
|
45
|
+
# to individual examples or groups you care about by tagging them with
|
46
|
+
# `:focus` metadata. When nothing is tagged with `:focus`, all examples
|
47
|
+
# get run.
|
48
|
+
config.filter_run :focus
|
49
|
+
config.run_all_when_everything_filtered = true
|
50
|
+
|
51
|
+
# Limits the available syntax to the non-monkey patched syntax that is recommended.
|
52
|
+
# For more details, see:
|
53
|
+
# - http://myronmars.to/n/dev-blog/2012/06/rspecs-new-expectation-syntax
|
54
|
+
# - http://teaisaweso.me/blog/2013/05/27/rspecs-new-message-expectation-syntax/
|
55
|
+
# - http://myronmars.to/n/dev-blog/2014/05/notable-changes-in-rspec-3#new__config_option_to_disable_rspeccore_monkey_patching
|
56
|
+
config.disable_monkey_patching!
|
57
|
+
|
58
|
+
# This setting enables warnings. It's recommended, but in some cases may
|
59
|
+
# be too noisy due to issues in dependencies.
|
60
|
+
config.warnings = true
|
61
|
+
|
62
|
+
# Many RSpec users commonly either run the entire suite or an individual
|
63
|
+
# file, and it's useful to allow more verbose output when running an
|
64
|
+
# individual spec file.
|
65
|
+
if config.files_to_run.one?
|
66
|
+
# Use the documentation formatter for detailed output,
|
67
|
+
# unless a formatter has already been configured
|
68
|
+
# (e.g. via a command-line flag).
|
69
|
+
config.default_formatter = 'doc'
|
70
|
+
end
|
71
|
+
|
72
|
+
# Print the 10 slowest examples and example groups at the
|
73
|
+
# end of the spec run, to help surface which specs are running
|
74
|
+
# particularly slow.
|
75
|
+
config.profile_examples = 10
|
76
|
+
|
77
|
+
# Run specs in random order to surface order dependencies. If you find an
|
78
|
+
# order dependency and want to debug it, you can fix the order by providing
|
79
|
+
# the seed, which is printed after each run.
|
80
|
+
# --seed 1234
|
81
|
+
config.order = :random
|
82
|
+
|
83
|
+
# Seed global randomization in this process using the `--seed` CLI option.
|
84
|
+
# Setting this allows you to use `--seed` to deterministically reproduce
|
85
|
+
# test failures related to randomization by passing the same `--seed` value
|
86
|
+
# as the one that triggered the failure.
|
87
|
+
Kernel.srand config.seed
|
88
|
+
=end
|
89
|
+
end
|
metadata
CHANGED
@@ -1,15 +1,71 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: niman
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jan Schulte
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-02-
|
11
|
+
date: 2015-02-08 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: thor
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0.19'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0.19'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: virtus
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 1.0.4
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: 1.0.4
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: fakefs
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0.5'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0.5'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: rspec
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - '='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '3.1'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - '='
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '3.1'
|
13
69
|
- !ruby/object:Gem::Dependency
|
14
70
|
name: bundler
|
15
71
|
requirement: !ruby/object:Gem::Requirement
|
@@ -41,18 +97,42 @@ dependencies:
|
|
41
97
|
description:
|
42
98
|
email:
|
43
99
|
- hello@unexpected-co.de
|
44
|
-
executables:
|
100
|
+
executables:
|
101
|
+
- niman
|
45
102
|
extensions: []
|
46
103
|
extra_rdoc_files: []
|
47
104
|
files:
|
48
105
|
- ".gitignore"
|
106
|
+
- ".rspec"
|
107
|
+
- ".travis.yml"
|
49
108
|
- Gemfile
|
50
109
|
- LICENSE.txt
|
51
110
|
- README.md
|
52
111
|
- Rakefile
|
112
|
+
- bin/niman
|
53
113
|
- lib/niman.rb
|
114
|
+
- lib/niman/cli/application.rb
|
115
|
+
- lib/niman/exceptions.rb
|
116
|
+
- lib/niman/installer.rb
|
117
|
+
- lib/niman/library/file.rb
|
118
|
+
- lib/niman/library/package.rb
|
119
|
+
- lib/niman/nimanfile.rb
|
120
|
+
- lib/niman/platform.rb
|
121
|
+
- lib/niman/provisioner.rb
|
122
|
+
- lib/niman/recipe.rb
|
123
|
+
- lib/niman/shell.rb
|
124
|
+
- lib/niman/vagrant/plugin.rb
|
125
|
+
- lib/niman/vagrant/provisioner.rb
|
126
|
+
- lib/niman/vagrant/shell.rb
|
54
127
|
- lib/niman/version.rb
|
55
128
|
- niman.gemspec
|
129
|
+
- spec/lib/installer_spec.rb
|
130
|
+
- spec/lib/library/file_spec.rb
|
131
|
+
- spec/lib/library/package_spec.rb
|
132
|
+
- spec/lib/nimanfile_spec.rb
|
133
|
+
- spec/lib/provisioner_spec.rb
|
134
|
+
- spec/lib/recipe_spec.rb
|
135
|
+
- spec/spec_helper.rb
|
56
136
|
homepage: ''
|
57
137
|
licenses:
|
58
138
|
- MIT
|
@@ -77,4 +157,11 @@ rubygems_version: 2.4.3
|
|
77
157
|
signing_key:
|
78
158
|
specification_version: 4
|
79
159
|
summary: Provisions your machine
|
80
|
-
test_files:
|
160
|
+
test_files:
|
161
|
+
- spec/lib/installer_spec.rb
|
162
|
+
- spec/lib/library/file_spec.rb
|
163
|
+
- spec/lib/library/package_spec.rb
|
164
|
+
- spec/lib/nimanfile_spec.rb
|
165
|
+
- spec/lib/provisioner_spec.rb
|
166
|
+
- spec/lib/recipe_spec.rb
|
167
|
+
- spec/spec_helper.rb
|