minimart 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +15 -0
- data/.gitignore +21 -0
- data/.rspec +3 -0
- data/.travis.yml +13 -0
- data/Gemfile +3 -0
- data/README.md +198 -0
- data/Rakefile +45 -0
- data/bin/minimart +4 -0
- data/lib/minimart.rb +15 -0
- data/lib/minimart/cli.rb +93 -0
- data/lib/minimart/commands/mirror.rb +30 -0
- data/lib/minimart/commands/web.rb +91 -0
- data/lib/minimart/configuration.rb +46 -0
- data/lib/minimart/cookbook.rb +173 -0
- data/lib/minimart/download/cookbook.rb +70 -0
- data/lib/minimart/download/git_cache.rb +60 -0
- data/lib/minimart/download/git_repository.rb +41 -0
- data/lib/minimart/error.rb +32 -0
- data/lib/minimart/inventory_requirement/base_requirement.rb +81 -0
- data/lib/minimart/inventory_requirement/git_requirement.rb +87 -0
- data/lib/minimart/inventory_requirement/git_requirements_builder.rb +101 -0
- data/lib/minimart/inventory_requirement/local_path_requirement.rb +45 -0
- data/lib/minimart/inventory_requirement/local_requirements_builder.rb +31 -0
- data/lib/minimart/inventory_requirement/supermarket_requirements_builder.rb +35 -0
- data/lib/minimart/mirror.rb +12 -0
- data/lib/minimart/mirror/dependency_graph.rb +73 -0
- data/lib/minimart/mirror/download_metadata.rb +57 -0
- data/lib/minimart/mirror/inventory_builder.rb +143 -0
- data/lib/minimart/mirror/inventory_configuration.rb +74 -0
- data/lib/minimart/mirror/inventory_requirements.rb +104 -0
- data/lib/minimart/mirror/local_store.rb +107 -0
- data/lib/minimart/mirror/source.rb +57 -0
- data/lib/minimart/mirror/source_cookbook.rb +77 -0
- data/lib/minimart/mirror/sources.rb +37 -0
- data/lib/minimart/output.rb +34 -0
- data/lib/minimart/utils/archive.rb +39 -0
- data/lib/minimart/utils/file_helper.rb +34 -0
- data/lib/minimart/utils/http.rb +60 -0
- data/lib/minimart/version.rb +3 -0
- data/lib/minimart/web.rb +10 -0
- data/lib/minimart/web/cookbook_show_page_generator.rb +78 -0
- data/lib/minimart/web/cookbooks.rb +83 -0
- data/lib/minimart/web/dashboard_generator.rb +46 -0
- data/lib/minimart/web/html_generator.rb +52 -0
- data/lib/minimart/web/markdown_parser.rb +47 -0
- data/lib/minimart/web/template_helper.rb +132 -0
- data/lib/minimart/web/universe_generator.rb +109 -0
- data/minimart.gemspec +36 -0
- data/spec/fixtures/sample_cookbook.tar.gz +0 -0
- data/spec/fixtures/sample_cookbook/Berksfile +3 -0
- data/spec/fixtures/sample_cookbook/CHANGELOG.md +3 -0
- data/spec/fixtures/sample_cookbook/Gemfile +16 -0
- data/spec/fixtures/sample_cookbook/LICENSE +3 -0
- data/spec/fixtures/sample_cookbook/README.md +42 -0
- data/spec/fixtures/sample_cookbook/Thorfile +5 -0
- data/spec/fixtures/sample_cookbook/Vagrantfile +90 -0
- data/spec/fixtures/sample_cookbook/chefignore +94 -0
- data/spec/fixtures/sample_cookbook/metadata.rb +9 -0
- data/spec/fixtures/sample_cookbook/recipes/default.rb +8 -0
- data/spec/fixtures/sample_inventory.yml +16 -0
- data/spec/fixtures/simple_git_inventory.yml +8 -0
- data/spec/fixtures/simple_inventory.yml +6 -0
- data/spec/fixtures/simple_local_path_inventory.yml +5 -0
- data/spec/fixtures/universe.json +42 -0
- data/spec/fixtures/vcr_cassettes/local_path_cookbooks.yml +3316 -0
- data/spec/fixtures/vcr_cassettes/location_specific_cookbooks.yml +3316 -0
- data/spec/fixtures/vcr_cassettes/supermarket_cookbooks_graph.yml +905 -0
- data/spec/fixtures/vcr_cassettes/supermarket_cookbooks_installing_cookbooks.yml +4218 -0
- data/spec/lib/minimart/cli_spec.rb +104 -0
- data/spec/lib/minimart/commands/mirror_spec.rb +37 -0
- data/spec/lib/minimart/commands/web_spec.rb +75 -0
- data/spec/lib/minimart/configuration_spec.rb +54 -0
- data/spec/lib/minimart/cookbook_spec.rb +137 -0
- data/spec/lib/minimart/download/cookbook_spec.rb +135 -0
- data/spec/lib/minimart/download/git_cache_spec.rb +69 -0
- data/spec/lib/minimart/download/git_repository_spec.rb +39 -0
- data/spec/lib/minimart/error_spec.rb +18 -0
- data/spec/lib/minimart/inventory_requirement/base_requirement_spec.rb +38 -0
- data/spec/lib/minimart/inventory_requirement/git_requirement_spec.rb +92 -0
- data/spec/lib/minimart/inventory_requirement/git_requirements_builder_spec.rb +130 -0
- data/spec/lib/minimart/inventory_requirement/local_path_requirement_spec.rb +35 -0
- data/spec/lib/minimart/inventory_requirement/local_requirements_builder_spec.rb +33 -0
- data/spec/lib/minimart/inventory_requirement/supermarket_requirements_builder_spec.rb +69 -0
- data/spec/lib/minimart/mirror/dependency_graph_spec.rb +123 -0
- data/spec/lib/minimart/mirror/download_metadata_spec.rb +73 -0
- data/spec/lib/minimart/mirror/inventory_builder_spec.rb +195 -0
- data/spec/lib/minimart/mirror/inventory_configuration_spec.rb +86 -0
- data/spec/lib/minimart/mirror/inventory_requirements_spec.rb +78 -0
- data/spec/lib/minimart/mirror/local_store_spec.rb +64 -0
- data/spec/lib/minimart/mirror/source_spec.rb +54 -0
- data/spec/lib/minimart/mirror/sources_spec.rb +50 -0
- data/spec/lib/minimart/output_spec.rb +29 -0
- data/spec/lib/minimart/utils/archive_spec.rb +38 -0
- data/spec/lib/minimart/utils/file_helper_spec.rb +43 -0
- data/spec/lib/minimart/utils/http_spec.rb +37 -0
- data/spec/lib/minimart/web/cookbook_show_page_generator_spec.rb +101 -0
- data/spec/lib/minimart/web/cookbooks_spec.rb +70 -0
- data/spec/lib/minimart/web/dashboard_generator_spec.rb +33 -0
- data/spec/lib/minimart/web/html_generator_spec.rb +34 -0
- data/spec/lib/minimart/web/markdown_parser_spec.rb +54 -0
- data/spec/lib/minimart/web/template_helper_spec.rb +86 -0
- data/spec/lib/minimart/web/universe_generator_spec.rb +125 -0
- data/spec/spec_helper.rb +35 -0
- data/spec/support/file_system.rb +22 -0
- data/web/_assets/javascripts/app.js +164 -0
- data/web/_assets/javascripts/backbone.min.js +6 -0
- data/web/_assets/javascripts/jquery.min.js +4 -0
- data/web/_assets/javascripts/jquery.tabslet.min.js +9 -0
- data/web/_assets/javascripts/manifest.js +5 -0
- data/web/_assets/javascripts/underscore.min.js +5 -0
- data/web/_assets/stylesheets/font-awesome.min.css +4 -0
- data/web/_assets/stylesheets/font-mfizz.css +318 -0
- data/web/_assets/stylesheets/main.css +720 -0
- data/web/_assets/stylesheets/manifest.css +4 -0
- data/web/_assets/stylesheets/normalize.css +427 -0
- data/web/assets/fonts/FontAwesome.otf +0 -0
- data/web/assets/fonts/font-mfizz.eot +0 -0
- data/web/assets/fonts/font-mfizz.svg +1344 -0
- data/web/assets/fonts/font-mfizz.ttf +0 -0
- data/web/assets/fonts/font-mfizz.woff +0 -0
- data/web/assets/fonts/fontawesome-webfont.eot +0 -0
- data/web/assets/fonts/fontawesome-webfont.svg +520 -0
- data/web/assets/fonts/fontawesome-webfont.ttf +0 -0
- data/web/assets/fonts/fontawesome-webfont.woff +0 -0
- data/web/assets/images/header-slim.jpg +0 -0
- data/web/assets/images/icon-search.png +0 -0
- data/web/assets/images/mad-glory-logo.png +0 -0
- data/web/assets/images/main-gradient.png +0 -0
- data/web/assets/images/top-bar-logo.png +0 -0
- data/web/assets/javascripts/application.min.js +5 -0
- data/web/assets/stylesheets/application.min.css +4 -0
- data/web/templates/cookbook_show.erb +96 -0
- data/web/templates/dashboard.erb +81 -0
- data/web/templates/layout.erb +38 -0
- metadata +433 -0
@@ -0,0 +1,32 @@
|
|
1
|
+
module Minimart
|
2
|
+
# The collection of Minimart specific errors.
|
3
|
+
module Error
|
4
|
+
class BaseError < StandardError; end
|
5
|
+
|
6
|
+
# Raised when a dependency cannot be met.
|
7
|
+
class UnresolvedDependency < BaseError; end
|
8
|
+
|
9
|
+
# Raised when there is an error parsing the inventory file.
|
10
|
+
class InvalidInventoryError < BaseError; end
|
11
|
+
|
12
|
+
# Raised when a source does not respond to '/universe' correctly.
|
13
|
+
class UniverseNotFoundError < BaseError; end
|
14
|
+
|
15
|
+
# Raised when none of the available sources have a given cookbook.
|
16
|
+
class CookbookNotFound < BaseError; end
|
17
|
+
|
18
|
+
# Raised when there is a conflict between different versions of the same cookbook.
|
19
|
+
class BrokenDependency < BaseError; end
|
20
|
+
|
21
|
+
# Raised when Minimart encounters a cookbook with a location type that it can't handle
|
22
|
+
class UnknownLocationType < BaseError; end
|
23
|
+
|
24
|
+
# Gracefully handle any errors raised by Minimart, and exit with a failure
|
25
|
+
# status code.
|
26
|
+
# @param [Minimart::Error::BaseError] ex
|
27
|
+
def self.handle_exception(ex)
|
28
|
+
Configuration.output.puts_red(ex.message)
|
29
|
+
exit false
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,81 @@
|
|
1
|
+
module Minimart
|
2
|
+
module InventoryRequirement
|
3
|
+
|
4
|
+
# BaseRequirement represents a single cookbook entry as listed in the inventory.
|
5
|
+
# BaseRequirement is a generic interface for other inventory requirements.
|
6
|
+
class BaseRequirement
|
7
|
+
|
8
|
+
# @return [String] The name of the cookbook
|
9
|
+
attr_reader :name
|
10
|
+
|
11
|
+
# @return [String] The SemVer requirement for the cookbook
|
12
|
+
attr_reader :version_requirement
|
13
|
+
|
14
|
+
# @return [Minimart::Cookbook] The resolved cookbook
|
15
|
+
attr_reader :cookbook
|
16
|
+
|
17
|
+
# @param [String] name The name of the cookbook
|
18
|
+
# @param [Hash] opts
|
19
|
+
# @option opts [String] :version_requirement The SemVer requirement for the cookbook
|
20
|
+
def initialize(name, opts)
|
21
|
+
@name = name
|
22
|
+
@version_requirement = opts[:version_requirement]
|
23
|
+
end
|
24
|
+
|
25
|
+
# Determine whether or not this is a requirement which explicitly defines
|
26
|
+
# it's location (e.g. Git repo). Defaults to FALSE.
|
27
|
+
# @return [Boolean]
|
28
|
+
def explicit_location?
|
29
|
+
false
|
30
|
+
end
|
31
|
+
|
32
|
+
# The requirements to download this cookbook.
|
33
|
+
# @return [Hash]
|
34
|
+
def requirements
|
35
|
+
# if this cookbook has it's location specified, we instead return it's
|
36
|
+
# dependencies as we don't need to resolve them elsewhere
|
37
|
+
explicit_location? ? cookbook.dependencies : {name => version_requirement}
|
38
|
+
end
|
39
|
+
|
40
|
+
# Download a cookbook that has it's location explicitly defined (see #explicit_location?)
|
41
|
+
# @yield [Minimart::Cookbook]
|
42
|
+
def fetch_cookbook(&block)
|
43
|
+
return unless explicit_location?
|
44
|
+
|
45
|
+
download_cookbook do |cookbook|
|
46
|
+
@cookbook = cookbook
|
47
|
+
block.call(cookbook) if block
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
# Determine whether or not a version requirement was defined for the given
|
52
|
+
# cookbook.
|
53
|
+
# @return [Boolean]
|
54
|
+
def version_requirement?
|
55
|
+
!!version_requirement
|
56
|
+
end
|
57
|
+
|
58
|
+
# Convert the requirement to a Hash.
|
59
|
+
# @return [Hash]
|
60
|
+
def to_hash
|
61
|
+
{}
|
62
|
+
end
|
63
|
+
|
64
|
+
# Determine if a cookbook in the inventory has metadata matching this requirement
|
65
|
+
# @param [Minimart::Mirror::DownloadMetadata] metadata The download metadata for a cookbook
|
66
|
+
# in the inventory.
|
67
|
+
# @return [Boolean] Defaults to true
|
68
|
+
def matching_source?(metadata)
|
69
|
+
return true
|
70
|
+
end
|
71
|
+
|
72
|
+
private
|
73
|
+
|
74
|
+
# This method must be overridden by any subclasses.
|
75
|
+
def download_cookbook(&block)
|
76
|
+
nil
|
77
|
+
end
|
78
|
+
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
@@ -0,0 +1,87 @@
|
|
1
|
+
require 'minimart/download/git_repository'
|
2
|
+
|
3
|
+
module Minimart
|
4
|
+
module InventoryRequirement
|
5
|
+
|
6
|
+
# A single Git requirement for a cookbook as specified in the inventory.
|
7
|
+
# This represents a single brach, ref, or tag for a cookbook.
|
8
|
+
class GitRequirement < BaseRequirement
|
9
|
+
|
10
|
+
# @return [String] the location to fetch this cookbook from.
|
11
|
+
attr_reader :location
|
12
|
+
|
13
|
+
# @return [String] the branch to checkout once this cookbook has been fetched.
|
14
|
+
attr_reader :branch
|
15
|
+
|
16
|
+
# @return [String] the SHA of the Git commit to checkout once this cookbook has been fetched.
|
17
|
+
attr_reader :ref
|
18
|
+
|
19
|
+
# @return [String] the tag to checkout once this cookbook has been fetched
|
20
|
+
attr_reader :tag
|
21
|
+
|
22
|
+
# @param [String] name The name of the cookbook defined by this requirement.
|
23
|
+
# @param [Hash] opts
|
24
|
+
# @option opts [String] branch The branch to checkout once this cookbook has been fetched.
|
25
|
+
# @option opts [String] tag The tag to checkout once this cookbook has been fetched
|
26
|
+
# @option opts [String] ref The SHA of the Git commit to checkout once this cookbook has been fetched.
|
27
|
+
def initialize(name, opts)
|
28
|
+
super
|
29
|
+
@branch = opts[:branch]
|
30
|
+
@ref = opts[:ref]
|
31
|
+
@tag = opts[:tag]
|
32
|
+
@location = opts[:location]
|
33
|
+
end
|
34
|
+
|
35
|
+
# Git requirements explicitly define their location, so this method will return true.
|
36
|
+
# @return [Boolean] TRUE
|
37
|
+
def explicit_location?
|
38
|
+
true
|
39
|
+
end
|
40
|
+
|
41
|
+
# Convert this requirement to a hash
|
42
|
+
# @return [Hash]
|
43
|
+
def to_hash
|
44
|
+
result = super
|
45
|
+
result[:source_type] = :git
|
46
|
+
result[:location] = location
|
47
|
+
result[:commitish_type] = commitish_type
|
48
|
+
result[:commitish] = commitish
|
49
|
+
result
|
50
|
+
end
|
51
|
+
|
52
|
+
# Determine if a Git cookbook in the inventory has metadata matching this requirement.
|
53
|
+
# This method will return true if the metadata has the same commit information
|
54
|
+
# as this requirement.
|
55
|
+
# @param [Minimart::Mirror::DownloadMetadata] metadata The download metadata for a cookbook
|
56
|
+
# in the inventory.
|
57
|
+
# @return [Boolean] Defaults to true
|
58
|
+
def matching_source?(metadata)
|
59
|
+
metadata['source_type'] == 'git' &&
|
60
|
+
metadata['commitish_type'] == commitish_type.to_s &&
|
61
|
+
(metadata['commitish_type'] == 'ref' ? true : metadata['commitish'] == commitish.to_s)
|
62
|
+
end
|
63
|
+
|
64
|
+
private
|
65
|
+
|
66
|
+
def download_cookbook(&block)
|
67
|
+
Configuration.output.puts "-- Fetching '#{name}[#{commitish}]' from '#{location}'"
|
68
|
+
|
69
|
+
downloader = Download::GitRepository.new(location)
|
70
|
+
downloader.fetch(commitish) do |path_to_cookbook|
|
71
|
+
block.call(Minimart::Cookbook.from_path(path_to_cookbook))
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
def commitish
|
76
|
+
ref || branch || tag
|
77
|
+
end
|
78
|
+
|
79
|
+
def commitish_type
|
80
|
+
return :ref if ref
|
81
|
+
return :branch if branch
|
82
|
+
return :tag if tag
|
83
|
+
end
|
84
|
+
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
@@ -0,0 +1,101 @@
|
|
1
|
+
require 'minimart/inventory_requirement/git_requirement'
|
2
|
+
|
3
|
+
module Minimart
|
4
|
+
module InventoryRequirement
|
5
|
+
# This class is used to parse any Git requirements specified in the inventory
|
6
|
+
# and build Minimart::Inventory::GitRequirements from them.
|
7
|
+
class GitRequirementsBuilder
|
8
|
+
|
9
|
+
# @return [String] the name of the cookbook defined by this requirement.
|
10
|
+
attr_reader :name
|
11
|
+
|
12
|
+
# @return [String] the location to fetch this cookbook from.
|
13
|
+
attr_reader :location
|
14
|
+
|
15
|
+
# @return [Array<String>] a listing of branches to checkout when fetching this cookbook.
|
16
|
+
attr_reader :branches
|
17
|
+
|
18
|
+
# @return [Array<String>] a listing of tags to checkout when fetching this cookbook.
|
19
|
+
attr_reader :tags
|
20
|
+
|
21
|
+
# @return [Array<String>] a listing of refs to checkout when fetching this cookbook.
|
22
|
+
attr_reader :refs
|
23
|
+
|
24
|
+
# @param [String] name The name of the cookbook defined by this requirement.
|
25
|
+
# @param [Hash] reqs
|
26
|
+
# * 'git' [Hash] The git specific requirements for this cookbook
|
27
|
+
# * 'branches' [Array<String>] A listing of branches to checkout when fetching this cookbook.
|
28
|
+
# * 'branch' [String] A single branch to checkout when fetching this cookbook.
|
29
|
+
# * 'tags' [Array<String>] A listing of tags to checkout when fetching this cookbook.
|
30
|
+
# * 'tag' [String] A single tag to checkout when fetching this cookbook.
|
31
|
+
# * 'refs' [Array<String>] A listing of ref to checkout when fetching this cookbook.
|
32
|
+
# * 'ref' [String] A single ref to checkout when fetching this cookbook.
|
33
|
+
def initialize(name, reqs)
|
34
|
+
@name = name
|
35
|
+
git_reqs = reqs.fetch('git', {})
|
36
|
+
|
37
|
+
@location = git_reqs['location']
|
38
|
+
@branches = raw_location_type_requirement(%w[branches branch], git_reqs)
|
39
|
+
@tags = raw_location_type_requirement(%w[tags tag], git_reqs)
|
40
|
+
@refs = raw_location_type_requirement(%w[refs ref], git_reqs)
|
41
|
+
|
42
|
+
validate_requirements(git_reqs)
|
43
|
+
end
|
44
|
+
|
45
|
+
# Build the git requirements.
|
46
|
+
# @return [Array<Minimart::InventoryRequirement::GitRequirement>]
|
47
|
+
def build
|
48
|
+
from_branches + from_tags + from_refs
|
49
|
+
end
|
50
|
+
|
51
|
+
private
|
52
|
+
|
53
|
+
def from_branches
|
54
|
+
branches.map { |b| build_requirement(:branch, b) }
|
55
|
+
end
|
56
|
+
|
57
|
+
def from_tags
|
58
|
+
tags.map { |t| build_requirement(:tag, t) }
|
59
|
+
end
|
60
|
+
|
61
|
+
def from_refs
|
62
|
+
refs.map { |r| build_requirement(:ref, r) }
|
63
|
+
end
|
64
|
+
|
65
|
+
def build_requirement(type, value)
|
66
|
+
InventoryRequirement::GitRequirement.new(name, {type => value}.merge(location: location))
|
67
|
+
end
|
68
|
+
|
69
|
+
def raw_location_type_requirement(location_types, requirements)
|
70
|
+
location_types.inject([]) do |memo, type|
|
71
|
+
if requirements[type]
|
72
|
+
req = requirements[type]
|
73
|
+
req = [req] if req.is_a?(String)
|
74
|
+
memo.concat(req)
|
75
|
+
end
|
76
|
+
memo
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
def validate_requirements(reqs)
|
81
|
+
return if reqs.nil? || reqs.empty?
|
82
|
+
|
83
|
+
validate_location
|
84
|
+
validate_commitish
|
85
|
+
end
|
86
|
+
|
87
|
+
def validate_location
|
88
|
+
return unless location.nil? || location.empty?
|
89
|
+
raise Minimart::Error::InvalidInventoryError,
|
90
|
+
"'#{name}' specifies Git requirements, but does not have a location."
|
91
|
+
end
|
92
|
+
|
93
|
+
def validate_commitish
|
94
|
+
return unless branches.empty? && tags.empty? && refs.empty?
|
95
|
+
raise Minimart::Error::InvalidInventoryError,
|
96
|
+
"'#{name}' specified Git requirements, but does not provide a branch|tag|ref"
|
97
|
+
end
|
98
|
+
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
module Minimart
|
2
|
+
module InventoryRequirement
|
3
|
+
|
4
|
+
# A requirement to a cookbook found in the local file system
|
5
|
+
class LocalPathRequirement < BaseRequirement
|
6
|
+
|
7
|
+
# @return [String] the path to the cookbook
|
8
|
+
attr_reader :path
|
9
|
+
|
10
|
+
# @param [String] name The name of the cookbook
|
11
|
+
# @param [Hash] opts
|
12
|
+
# @option opts [String] path The path to the cookbook
|
13
|
+
def initialize(name, opts)
|
14
|
+
super
|
15
|
+
@path = opts[:path]
|
16
|
+
end
|
17
|
+
|
18
|
+
# Local path requirements explicitly define their location, so this method will return true.
|
19
|
+
# @return [Boolean] TRUE
|
20
|
+
def explicit_location?
|
21
|
+
true
|
22
|
+
end
|
23
|
+
|
24
|
+
# Convert this requirement to a hash
|
25
|
+
# @return [Hash]
|
26
|
+
def to_hash
|
27
|
+
result = super
|
28
|
+
result[:source_type] = :local_path
|
29
|
+
result
|
30
|
+
end
|
31
|
+
|
32
|
+
def matching_source?(metadata)
|
33
|
+
metadata['source_type'] == 'local_path'
|
34
|
+
end
|
35
|
+
|
36
|
+
private
|
37
|
+
|
38
|
+
def download_cookbook(&block)
|
39
|
+
Configuration.output.puts "-- Fetching '#{name}' from path '#{path}'"
|
40
|
+
block.call(Minimart::Cookbook.from_path(path))
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'minimart/inventory_requirement/local_path_requirement'
|
2
|
+
|
3
|
+
module Minimart
|
4
|
+
module InventoryRequirement
|
5
|
+
# This class is used to parse any local path requirements specified in the inventory
|
6
|
+
# and build Minimart::Inventory::LocalPathRequirements from them.
|
7
|
+
class LocalRequirementsBuilder
|
8
|
+
|
9
|
+
# @return [String] the name of the cookbook defined by this requirement.
|
10
|
+
attr_reader :name
|
11
|
+
|
12
|
+
# @return [String] the path to the cookbook
|
13
|
+
attr_reader :path
|
14
|
+
|
15
|
+
# @param [String] name The name of the cookbook defined by this requirement.
|
16
|
+
# @param [Hash] reqs
|
17
|
+
# @option reqs [String] 'path' The path to the cookbook
|
18
|
+
def initialize(name, reqs)
|
19
|
+
@name = name
|
20
|
+
@path = reqs['path']
|
21
|
+
end
|
22
|
+
|
23
|
+
# Build the local path requirements.
|
24
|
+
# @return [Array<Minimart::InventoryRequirement::LocalPathRequirement>]
|
25
|
+
def build
|
26
|
+
return [] if path.nil? || path.empty?
|
27
|
+
[InventoryRequirement::LocalPathRequirement.new(name, path: path)]
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'minimart/inventory_requirement/base_requirement'
|
2
|
+
|
3
|
+
module Minimart
|
4
|
+
module InventoryRequirement
|
5
|
+
|
6
|
+
# This class is used to parse any Supermarket requirements specified in the inventory
|
7
|
+
# and build Minimart::Inventory::BaseRequirements from them.
|
8
|
+
class SupermarketRequirementsBuilder
|
9
|
+
|
10
|
+
# @return [String] the name of the cookbook
|
11
|
+
attr_reader :name
|
12
|
+
|
13
|
+
# @return [Array<String>] an array of versions to fetch for this cookbook
|
14
|
+
attr_reader :versions
|
15
|
+
|
16
|
+
# @param [String] name The name of the cookbook
|
17
|
+
# @param [Hash] reqs
|
18
|
+
# * 'versions' [Array<String>] A listing of versions to fetch.
|
19
|
+
# * 'version' [String] A single version to fetch.
|
20
|
+
def initialize(name, reqs)
|
21
|
+
@name = name
|
22
|
+
@versions = reqs['versions'] || reqs['version'] || []
|
23
|
+
@versions = [@versions] if @versions.is_a? String
|
24
|
+
end
|
25
|
+
|
26
|
+
# Build the Supemarket requirements.
|
27
|
+
# @return [Array<Minimart::InventoryRequirement::BaseRequirement>]
|
28
|
+
def build
|
29
|
+
versions.map do |v|
|
30
|
+
InventoryRequirement::BaseRequirement.new(name, version_requirement: v)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
module Minimart
|
2
|
+
# The Mirror namespace is used to build the local cookbook inventory.
|
3
|
+
module Mirror
|
4
|
+
require 'minimart/mirror/dependency_graph'
|
5
|
+
require 'minimart/mirror/inventory_builder'
|
6
|
+
require 'minimart/mirror/inventory_configuration'
|
7
|
+
require 'minimart/mirror/local_store'
|
8
|
+
require 'minimart/mirror/source_cookbook'
|
9
|
+
require 'minimart/mirror/source'
|
10
|
+
require 'minimart/mirror/sources'
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
require 'solve'
|
2
|
+
|
3
|
+
module Minimart
|
4
|
+
module Mirror
|
5
|
+
|
6
|
+
# A dependency graph for managing any remote cookbooks and their dependencies.
|
7
|
+
# This can be used to resolve any requirements found in the inventory file.
|
8
|
+
class DependencyGraph
|
9
|
+
|
10
|
+
|
11
|
+
attr_reader :graph
|
12
|
+
attr_reader :inventory_requirements
|
13
|
+
|
14
|
+
def initialize
|
15
|
+
@graph = Solve::Graph.new
|
16
|
+
@inventory_requirements = []
|
17
|
+
end
|
18
|
+
|
19
|
+
# Add an artifact (cookbook), and its dependencies to the graph.
|
20
|
+
# @param [Minimart::Mirror::SourceCookbook] cookbook
|
21
|
+
def add_artifact(cookbook)
|
22
|
+
return if source_cookbook_added?(cookbook.name, cookbook.version)
|
23
|
+
|
24
|
+
graph.artifact(cookbook.name, cookbook.version).tap do |artifact|
|
25
|
+
cookbook.dependencies.each do |dependency|
|
26
|
+
name, requirements = dependency
|
27
|
+
artifact.depends(name, requirements)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
# Determine whether or not the graph has a given cookbook.
|
33
|
+
# @param [String] name The name of the cookbook
|
34
|
+
# @param [String] version The version of the cookbook
|
35
|
+
# @return [Boolean]
|
36
|
+
def source_cookbook_added?(name, version)
|
37
|
+
graph.artifact?(name, version)
|
38
|
+
end
|
39
|
+
|
40
|
+
# Get a cookbook out of the graph.
|
41
|
+
# @param [Minimart::Mirror::SourceCookbook] cookbook The cookbook to fetch.
|
42
|
+
# @return [Solve::Artifact]
|
43
|
+
def find_graph_artifact(cookbook)
|
44
|
+
graph.find(cookbook.name, cookbook.version)
|
45
|
+
end
|
46
|
+
|
47
|
+
# Add a new requirement to be resolved by the graph
|
48
|
+
# @param [Hash] requirements (ex. { 'minimart' => '> 0.0.1' })
|
49
|
+
def add_requirement(requirements = {})
|
50
|
+
inventory_requirements.concat(requirements.to_a)
|
51
|
+
end
|
52
|
+
|
53
|
+
# Resolve any requirements against the graph
|
54
|
+
# @return [Array] The requirements as resolved by the graph (ex. [['minimart', '0.0.5']])
|
55
|
+
# @raise [Minimart::Error::UnresolvedDependency] Raised when a dependency cannot be resolved
|
56
|
+
def resolved_requirements
|
57
|
+
inventory_requirements.inject([]) do |result, requirement|
|
58
|
+
result.concat(resolve_requirement(requirement).to_a)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
private
|
63
|
+
|
64
|
+
def resolve_requirement(requirement)
|
65
|
+
Solve.it!(graph, [requirement])
|
66
|
+
|
67
|
+
rescue Solve::Errors::NoSolutionError => e
|
68
|
+
raise Error::UnresolvedDependency, e.message
|
69
|
+
end
|
70
|
+
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|