salt-matrix 0.1.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 51df135caadd82053d8c9d8f4eb5226e5426d825
4
+ data.tar.gz: 033cd2406ccbe7bee05e34e7cf726054a270826f
5
+ SHA512:
6
+ metadata.gz: f76d68d5200d533ae6b5d286998576288ab59f13dd983feb5274354411808351d726f2aafd74c5601c5c31ee070bee93c5d34bd9ce49ef7a60c097d2a76c49ad
7
+ data.tar.gz: cb7a5067e537d25d145bb3cab44779cfb57e0c97a090642b8d752b3c8f63e5ecb9199b1d444c8bc724c1fc840ed215f5ba0b857b7f96b0e5f4fb67b9d5a2e8db
@@ -0,0 +1,21 @@
1
+ salt-matrix
2
+ ===========
3
+
4
+
5
+
6
+ File Format
7
+ -----------
8
+
9
+ Saltfile
10
+
11
+ ```
12
+
13
+ formula 'custom_grains', :git => 'http://stash.service.audsci.net/scm/salt/custom_grains-formula.git', '0.1.0'
14
+
15
+ formula 'custom_grains', :git => 'http://stash.service.audsci.net/scm/salt/custom_grains-formula.git', :branch => 'master'
16
+
17
+ formula 'custom_grains', :git => 'http://stash.service.audsci.net/scm/salt/custom_grains-formula.git', :tag => 'this_rel'
18
+
19
+
20
+
21
+ ```
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.1.3
@@ -0,0 +1,20 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ lib = File.expand_path('../../lib', __FILE__)
4
+ $LOAD_PATH << lib unless $LOAD_PATH.include? lib
5
+
6
+ require 'colorize'
7
+ require 'salt/matrix'
8
+
9
+
10
+ begin
11
+ cli = Salt::Matrix::Cli.start
12
+ rescue Interrupt
13
+ exit(1)
14
+ rescue SystemExit => e
15
+ exit(e.status)
16
+ rescue Exception => e
17
+ $stderr.puts "\nUnhandled exception: #{e.inspect}".red
18
+ $stderr.puts e.backtrace.join("\n")
19
+ exit(1)
20
+ end
@@ -0,0 +1,36 @@
1
+
2
+
3
+ module Salt
4
+ module Formula
5
+
6
+ # Register an module implementation for later generation
7
+ def self.register(klass)
8
+ @klasses ||= []
9
+ @klasses << klass
10
+ end
11
+
12
+ # Look up the implementing class and instantiate an object
13
+ #
14
+ # This method takes the arguments for normal object generation and checks all
15
+ # inheriting classes to see if they implement the behavior needed to create
16
+ # the requested object. It selects the first class that can implement an object
17
+ # with `name, args`, and generates an object of that class.
18
+ #
19
+ # @param [String] name The unique name of the module
20
+ # @param [String] basedir The root to install the module in
21
+ # @param [Object] args An arbitary value or set of values that specifies the implementation
22
+ #
23
+ # @return [Object < R10K::Module] A member of the implementing subclass
24
+ def self.new(name, basedir, args)
25
+ if implementation = @klasses.find { |klass| klass.implement?(name, args) }
26
+ obj = implementation.new(name, basedir, args)
27
+ obj
28
+ else
29
+ raise "Module #{name} with args #{args.inspect} doesn't have an implementation. (Are you using the right arguments?)"
30
+ end
31
+ end
32
+
33
+ require 'salt/formula/base'
34
+ require 'salt/formula/git'
35
+ end
36
+ end
@@ -0,0 +1,78 @@
1
+
2
+ require 'salt/formula'
3
+
4
+
5
+ # This class defines a common interface for module implementations.
6
+ class Salt::Formula::Base
7
+
8
+ # @!attribute [r] name
9
+ # @return [String] The name of the module
10
+ attr_reader :name
11
+
12
+ # @param [r] dirname
13
+ # @return [String] The name of the directory containing this module
14
+ attr_reader :dirname
15
+
16
+ # @deprecated
17
+ alias :basedir :dirname
18
+
19
+ # @!attribute [r] path
20
+ # @return [Pathname] The full path of the module
21
+ attr_reader :path
22
+
23
+ # @param title [String]
24
+ # @param dirname [String]
25
+ # @param args [Array]
26
+ def initialize(name, dirname, args)
27
+ @name = name
28
+ @dirname = dirname
29
+ @args = args
30
+ @path = Pathname.new(File.join(@dirname, @name))
31
+ end
32
+
33
+ # @deprecated
34
+ # @return [String] The full filesystem path to the module.
35
+ def full_path
36
+ path.to_s
37
+ end
38
+
39
+ # Synchronize this module with the indicated state.
40
+ # @abstract
41
+ def sync
42
+ raise NotImplementedError
43
+ end
44
+
45
+ # Return the desired version of this module
46
+ # @abstract
47
+ def version
48
+ raise NotImplementedError
49
+ end
50
+
51
+ # Return the status of the currently installed module.
52
+ #
53
+ # This can return the following values:
54
+ #
55
+ # * :absent - there is no module installed
56
+ # * :mismatched - there is a module installed but it must be removed and reinstalled
57
+ # * :outdated - the correct module is installed but it needs to be updated
58
+ # * :insync - the correct module is installed and up to date, or the module is actually a boy band.
59
+ #
60
+ # @return [Symbol]
61
+ # @abstract
62
+ def status
63
+ raise NotImplementedError
64
+ end
65
+
66
+ def accept(visitor)
67
+ visitor.visit(:module, self)
68
+ end
69
+
70
+ # Return the properties of the module
71
+ #
72
+ # @return [Hash]
73
+ # @abstract
74
+ def properties
75
+ raise NotImplementedError
76
+ end
77
+
78
+ end
@@ -0,0 +1,70 @@
1
+ require 'salt/formula'
2
+ require 'salt/matrix/gitrepo'
3
+ require 'forwardable'
4
+
5
+ class Salt::Formula::Git < Salt::Formula::Base
6
+
7
+ Salt::Formula.register(self)
8
+
9
+ def self.implement?(name, args)
10
+ args.is_a? Hash and (args.has_key?(:git) or args.has_key?(:github))
11
+ rescue
12
+ false
13
+ end
14
+
15
+ # @!attribute [r] repo
16
+ # @api private
17
+ # @return [Salt::Matrix::Gitrepo]
18
+ attr_reader :repo
19
+
20
+ def initialize(name, dirname, args)
21
+ super
22
+ parse_options(@args)
23
+ @name = name
24
+ @repo = Salt::Matrix::Gitrepo.new(@remote, @name, @ref, dirname)
25
+ end
26
+
27
+ def version
28
+ @ref
29
+ end
30
+
31
+ def properties
32
+ {
33
+ :expected => @ref,
34
+ :actual => (@repo.head || "(unresolvable)"),
35
+ :type => :git,
36
+ }
37
+ end
38
+
39
+ extend Forwardable
40
+
41
+ def_delegators :@repo, :sync, :status
42
+
43
+ private
44
+
45
+ def parse_options(options)
46
+ @remote = options.delete(:git) || options.delete(:github)
47
+
48
+ if options[:branch]
49
+ @ref = "origin/#{options.delete(:branch)}"
50
+ end
51
+
52
+ if options[:tag]
53
+ @ref = options.delete(:tag)
54
+ end
55
+
56
+ if options[:commit]
57
+ @ref = options.delete(:commit)
58
+ end
59
+
60
+ if options[:ref]
61
+ @ref = options.delete(:ref)
62
+ end
63
+
64
+ @ref ||= 'master'
65
+
66
+ unless options.empty?
67
+ raise ArgumentError, "Unhandled options #{options.keys.inspect} specified for #{self.class}"
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,53 @@
1
+
2
+ require 'singleton'
3
+ require 'version'
4
+ require 'salt/saltfile'
5
+ require 'salt/matrix/error'
6
+
7
+
8
+ module Salt
9
+
10
+ class Matrix
11
+ include Singleton
12
+
13
+ autoload :Cli, 'salt/matrix/cli'
14
+
15
+ attr_reader :debug
16
+
17
+ is_versioned
18
+
19
+ def initialize
20
+ @debug_buf = []
21
+ end
22
+
23
+
24
+ def set_debug
25
+ @debug = true
26
+ unless @debug_buf.empty?
27
+ debug {|fh| @debug_buf.each {|m| fh.write "#{m}\n" }}
28
+ end
29
+ end
30
+
31
+ def self.set_debug
32
+ self.instance.set_debug
33
+ end
34
+
35
+
36
+ def debug(msg, &block)
37
+ if block_given?
38
+ yield $stdout
39
+ elsif @debug
40
+ puts "*** #{msg}"
41
+ else
42
+ # just in case we turn debug on in a bit.
43
+ @debug_buf << msg
44
+ end
45
+ end
46
+
47
+ def self.debug(msg, &block)
48
+ self.instance.debug(msg, &block)
49
+ end
50
+
51
+ end
52
+
53
+ end
@@ -0,0 +1,61 @@
1
+
2
+ require 'thor'
3
+
4
+
5
+ module Salt
6
+ class Matrix
7
+ class Cli < Thor
8
+
9
+ autoload :Deploy, 'salt/matrix/cli/deploy'
10
+
11
+
12
+ #class_option :trace, :type => :boolean
13
+
14
+
15
+ desc 'version', 'Display version information'
16
+ def version
17
+ puts Salt::Matrix::VERSION
18
+ end
19
+
20
+ desc 'deploy', 'Deploy an environment from Saltfile'
21
+ long_desc <<-LONGDESC
22
+ Process a Saltfile and build an environment from the formulas
23
+ specified within the file. Saltfile consists of one or more entries
24
+ of the form:
25
+ \n
26
+ formula 'NAME', ARG, ARG, ARG ...
27
+ \n
28
+ NAME is the formula name which will be the directory name that
29
+ contains the formula. ARGs will vary depending upon the location
30
+ of the formula. Generally the ARGs will consist of the key :git set
31
+ to the location of the Git repository for the formula and a refernce
32
+ to the Git tag, branch or commit ID.
33
+ \n
34
+ With the --dir option, one may specify another directory other than
35
+ the current working directory to find the Saltfile.
36
+ LONGDESC
37
+ option :dir, :default => '.'
38
+ option :debug, :default => false
39
+ def deploy
40
+ if options['debug']
41
+ Salt::Master.set_debug
42
+ end
43
+ deploy_dir = File.expand_path options['dir']
44
+ Salt::Matrix.debug "Deployment directory set to #{deploy_dir}"
45
+ saltfile = Salt::Saltfile.new deploy_dir
46
+ saltfile.load
47
+ saltfile.formulas.each do |f|
48
+ f.sync
49
+ end
50
+ end
51
+
52
+
53
+ desc 'foo', 'Throw an exception'
54
+ def foo
55
+ raise RuntimeError, 'This is foo'
56
+ end
57
+
58
+
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,20 @@
1
+
2
+ require 'thor'
3
+
4
+
5
+ module Salt
6
+ class Matrix
7
+ class Cli
8
+ class Deploy < Thor
9
+
10
+
11
+ desc 'deploy environment', 'Some description'
12
+ def environment
13
+
14
+
15
+ end
16
+
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,33 @@
1
+
2
+
3
+ module Salt
4
+ class Matrix
5
+
6
+ class Error < StandardError
7
+
8
+ attr_accessor :original
9
+
10
+ def self.wrap(original, mesg, options = {})
11
+ new(mesg, options).tap do |e|
12
+ e.set_backtrace(caller(4))
13
+ e.original = original
14
+ end
15
+ end
16
+
17
+
18
+ def initialize(mesg, options = {})
19
+ super(mesg)
20
+
21
+ bt = options.delete(:backtrace)
22
+ if bt
23
+ set_backtrace(bt)
24
+ end
25
+
26
+ @options = options
27
+ end
28
+
29
+ end
30
+
31
+ end
32
+
33
+ end
@@ -0,0 +1,178 @@
1
+
2
+ require 'fileutils'
3
+ require 'yaml'
4
+ require 'git'
5
+
6
+
7
+ module Salt
8
+ class Matrix
9
+
10
+ ##
11
+ # Gitrepo class provides the low level interface to a Git repository.
12
+
13
+ class Gitrepo
14
+
15
+ def initialize(remote, name, ref, dirname)
16
+ @ref = ref
17
+ @remote = remote
18
+ @dirname = dirname
19
+ @formuladir = File.join(dirname, name)
20
+ @repodir = File.join(dirname, '.cache', name)
21
+ @name = name
22
+
23
+ # Grab the last settings if they exist.
24
+ @settings = {}
25
+ if File.exist? "#{@formuladir}/.salt-matrix.yaml"
26
+ @settings = YAML.load_file("#{@formuladir}/.salt-matrix.yaml")
27
+ end
28
+
29
+ @git = nil
30
+ if Dir.exist? @repodir
31
+ @git = Git.open @repodir
32
+ end
33
+ end
34
+
35
+
36
+ def sync
37
+
38
+ case status
39
+ when :absent
40
+ puts "#{"%-30s" % @name}" + "Cloning".yellow
41
+ replicate_repo
42
+ puts "#{"%-30s" % @name}" + "Syncing".cyan
43
+ replicate_formula
44
+ when :mismatched
45
+ puts "#{"%-30s" % @name}" + "Syncing".cyan
46
+ replicate_formula
47
+ when :badrepo
48
+ puts "#{"%-30s" % @name}" + "Kill repo".yellow
49
+ destroy_repo
50
+ puts "#{"%-30s" % @name}" + "Kill formula".yellow
51
+ destroy_formula
52
+ puts "#{"%-30s" % @name}" + "Cloning".yellow
53
+ replicate_repo
54
+ puts "#{"%-30s" % @name}" + "Syncing".cyan
55
+ replicate_formula
56
+ when :outdated
57
+ puts "#{"%-30s" % @name}" + "Updating repo".cyan
58
+ update_repo
59
+ puts "#{"%-30s" % @name}" + "Syncing".cyan
60
+ replicate_formula
61
+ when :insync
62
+ puts "#{"%-30s" % @name}" + "OK".green
63
+ else
64
+ puts "#{"%-30s" % @name}" + "Invalid State".red
65
+ end
66
+
67
+ save_settings
68
+ end
69
+
70
+
71
+ def status
72
+ # Reported conditions:
73
+ #
74
+ # :absent Nothing currently exists
75
+ # :mismatched Formula is not derived from repo
76
+ # :badrepo Cloned repo is not what is specified
77
+ # :outdated Expected, but needs to be sync'ed
78
+ # :insync Expected and upto date
79
+
80
+ if !Dir.exist? @formuladir or !Dir.exist? @repodir
81
+ return :absent
82
+ end
83
+
84
+
85
+
86
+ if @settings.empty?
87
+ return :mismatched
88
+ elsif @settings[:remote] != @remote
89
+ return :badrepo
90
+ end
91
+
92
+ # Check the repo settings
93
+ unless @git.nil?
94
+ @git.fetch
95
+ if @settings[:remote] != @git.remote.url
96
+ return :badrepo
97
+ elsif @settings[:sha] != @git.object(@ref).sha
98
+ return :outdated
99
+ else
100
+ return :insync
101
+ end
102
+ else
103
+ # Ideally this should never get returned!
104
+ return :invalid
105
+ end
106
+ end
107
+
108
+
109
+
110
+ private
111
+
112
+ def destroy_repo
113
+ FileUtils.rm_r @repodir
114
+ @git = nil
115
+ end
116
+
117
+ def destroy_formula
118
+ FileUtils.rm_r @formuladir
119
+ end
120
+
121
+ def replicate_repo
122
+ unless Dir.exists? "#{@dirname}/.cache"
123
+ Dir.mkdir "#{@dirname}/.cache"
124
+ end
125
+
126
+ # clone to the .cache directory
127
+ Dir.chdir "#{@dirname}/.cache"
128
+ begin
129
+ if @git.nil?
130
+ Salt::Matrix.debug "Cloning: #{@remote}"
131
+ @git = Git.clone(@remote, @name)
132
+ end
133
+ rescue Exception => e
134
+ puts "Exception: #{e}"
135
+ puts e.backtrace.join("\n")
136
+ puts e.inspect
137
+ end
138
+
139
+ # Checkout to the correct revsion
140
+ Salt::Matrix.debug "Checking out: #{@ref}"
141
+ @git.checkout @ref
142
+
143
+ # Record the Git ID
144
+ @settings[:sha] = @git.object("HEAD").sha
145
+ end
146
+
147
+ def update_repo
148
+ @git.fetch
149
+ @git.pull
150
+ end
151
+
152
+
153
+ def replicate_formula
154
+ # Locate the formula directory and copy it
155
+ # for now we treat the name as the formula directory name
156
+ if Dir.exist? File.join(@repodir, @name)
157
+ system("rsync -a --delete --exclude .salt-matrix.yaml #{File.join(@repodir, @name)} #{@dirname}")
158
+ #FileUtils.cp_r(File.join(@repodir, @name), @dirname)
159
+ @settings[:name] = @name
160
+ @settings[:remote] = @remote
161
+ @settings[:ref] = @ref
162
+ else
163
+ puts "#{"%-30s" % @name}" + "Invalid formula".red
164
+ end
165
+ end
166
+
167
+
168
+ def save_settings
169
+ if Dir.exist? @formuladir
170
+ File.open("#{@formuladir}/.salt-matrix.yaml", 'w') do |fh|
171
+ fh.write @settings.to_yaml
172
+ end
173
+ end
174
+ end
175
+
176
+ end
177
+ end
178
+ end
@@ -0,0 +1,77 @@
1
+
2
+ require 'salt/formula'
3
+
4
+ module Salt
5
+
6
+ class Saltfile
7
+
8
+ attr_reader :basedir
9
+ attr_reader :formuladir
10
+ attr_reader :formulas
11
+ attr_reader :saltfile
12
+
13
+ # @param [String] basedir
14
+ # @param [String] formuladir
15
+ # @param [String] saltfile
16
+ def initialize(basedir='.', formuladir=nil, saltfile=nil)
17
+ @basedir = basedir
18
+ @formuladir = formuladir || @basedir
19
+ @saltfile = saltfile || File.join(@basedir, 'Saltfile')
20
+
21
+ @formulas = []
22
+ end
23
+
24
+
25
+ def load
26
+ if File.readable? @saltfile
27
+ self.load!
28
+ else
29
+ $stderr.puts "Saltfile (#{@saltfile}) missing or unreadable"
30
+ end
31
+ end
32
+
33
+
34
+ def load!
35
+ dsl = DSL.new(self)
36
+ dsl.instance_eval(saltfile_contents, @saltfile)
37
+ rescue SyntaxError, LoadError => e
38
+ puts e.inspect.magenta
39
+ raise Salt::Matrix::Error.wrap(e, "Failed to process #{@saltfile}")
40
+ end
41
+
42
+
43
+ # @param [String] name
44
+ # @param [*Object] args
45
+ def add_formula(name, args)
46
+ @formulas << Salt::Formula.new(name, @formuladir, args)
47
+ end
48
+
49
+ # @return [File]
50
+ def saltfile_contents
51
+ File.read(@saltfile)
52
+ end
53
+
54
+
55
+
56
+ class DSL
57
+
58
+ # @param [*Object] librarian
59
+ def initialize(librarian)
60
+ @librarian = librarian
61
+ end
62
+
63
+ # @param [String] name
64
+ # @param [*Object] args
65
+ def formula(name, args=nil)
66
+ @librarian.add_formula(name, args)
67
+ end
68
+
69
+ def method_missing(methods, *args)
70
+ raise NoMethodError, "unrecognized declaration: #{method}"
71
+ end
72
+
73
+ end
74
+
75
+ end
76
+
77
+ end
metadata ADDED
@@ -0,0 +1,172 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: salt-matrix
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.3
5
+ platform: ruby
6
+ authors:
7
+ - Gerard Hickey
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-09-22 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ~>
18
+ - !ruby/object:Gem::Version
19
+ version: '1.3'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ~>
25
+ - !ruby/object:Gem::Version
26
+ version: '1.3'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ~>
32
+ - !ruby/object:Gem::Version
33
+ version: '10.4'
34
+ - - '>='
35
+ - !ruby/object:Gem::Version
36
+ version: 10.4.0
37
+ type: :runtime
38
+ prerelease: false
39
+ version_requirements: !ruby/object:Gem::Requirement
40
+ requirements:
41
+ - - ~>
42
+ - !ruby/object:Gem::Version
43
+ version: '10.4'
44
+ - - '>='
45
+ - !ruby/object:Gem::Version
46
+ version: 10.4.0
47
+ - !ruby/object:Gem::Dependency
48
+ name: thor
49
+ requirement: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - ~>
52
+ - !ruby/object:Gem::Version
53
+ version: 0.19.1
54
+ type: :runtime
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - ~>
59
+ - !ruby/object:Gem::Version
60
+ version: 0.19.1
61
+ - !ruby/object:Gem::Dependency
62
+ name: colorize
63
+ requirement: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - ~>
66
+ - !ruby/object:Gem::Version
67
+ version: 0.7.5
68
+ type: :runtime
69
+ prerelease: false
70
+ version_requirements: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - ~>
73
+ - !ruby/object:Gem::Version
74
+ version: 0.7.5
75
+ - !ruby/object:Gem::Dependency
76
+ name: version
77
+ requirement: !ruby/object:Gem::Requirement
78
+ requirements:
79
+ - - ~>
80
+ - !ruby/object:Gem::Version
81
+ version: '1.0'
82
+ - - '>='
83
+ - !ruby/object:Gem::Version
84
+ version: 1.0.0
85
+ type: :runtime
86
+ prerelease: false
87
+ version_requirements: !ruby/object:Gem::Requirement
88
+ requirements:
89
+ - - ~>
90
+ - !ruby/object:Gem::Version
91
+ version: '1.0'
92
+ - - '>='
93
+ - !ruby/object:Gem::Version
94
+ version: 1.0.0
95
+ - !ruby/object:Gem::Dependency
96
+ name: git
97
+ requirement: !ruby/object:Gem::Requirement
98
+ requirements:
99
+ - - ~>
100
+ - !ruby/object:Gem::Version
101
+ version: 1.2.0
102
+ type: :runtime
103
+ prerelease: false
104
+ version_requirements: !ruby/object:Gem::Requirement
105
+ requirements:
106
+ - - ~>
107
+ - !ruby/object:Gem::Version
108
+ version: 1.2.0
109
+ - !ruby/object:Gem::Dependency
110
+ name: rspec
111
+ requirement: !ruby/object:Gem::Requirement
112
+ requirements:
113
+ - - ~>
114
+ - !ruby/object:Gem::Version
115
+ version: '3.1'
116
+ - - '>='
117
+ - !ruby/object:Gem::Version
118
+ version: 3.1.0
119
+ type: :development
120
+ prerelease: false
121
+ version_requirements: !ruby/object:Gem::Requirement
122
+ requirements:
123
+ - - ~>
124
+ - !ruby/object:Gem::Version
125
+ version: '3.1'
126
+ - - '>='
127
+ - !ruby/object:Gem::Version
128
+ version: 3.1.0
129
+ description: Tool to build salt environments from various sources
130
+ email: gerard.hickey@audiencescience.com
131
+ executables:
132
+ - salt-matrix
133
+ extensions: []
134
+ extra_rdoc_files: []
135
+ files:
136
+ - README.md
137
+ - VERSION
138
+ - bin/salt-matrix
139
+ - lib/salt/formula.rb
140
+ - lib/salt/formula/base.rb
141
+ - lib/salt/formula/git.rb
142
+ - lib/salt/matrix.rb
143
+ - lib/salt/matrix/cli.rb
144
+ - lib/salt/matrix/cli/deploy.rb
145
+ - lib/salt/matrix/error.rb
146
+ - lib/salt/matrix/gitrepo.rb
147
+ - lib/salt/saltfile.rb
148
+ homepage: http://stash.service.audsci.net/projects/SALT/repos/salt-matrix/
149
+ licenses:
150
+ - Apache-2.0
151
+ metadata: {}
152
+ post_install_message:
153
+ rdoc_options: []
154
+ require_paths:
155
+ - lib
156
+ required_ruby_version: !ruby/object:Gem::Requirement
157
+ requirements:
158
+ - - '>='
159
+ - !ruby/object:Gem::Version
160
+ version: 1.9.3
161
+ required_rubygems_version: !ruby/object:Gem::Requirement
162
+ requirements:
163
+ - - '>='
164
+ - !ruby/object:Gem::Version
165
+ version: '0'
166
+ requirements: []
167
+ rubyforge_project:
168
+ rubygems_version: 2.2.2
169
+ signing_key:
170
+ specification_version: 4
171
+ summary: Tool to build salt environments
172
+ test_files: []