minimart 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +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
|