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,57 @@
|
|
|
1
|
+
require 'minimart/utils/http'
|
|
2
|
+
|
|
3
|
+
module Minimart
|
|
4
|
+
module Mirror
|
|
5
|
+
|
|
6
|
+
# Source represents a single remote source to fetch cookbooks from.
|
|
7
|
+
# Each source is specified in the inventory using the 'sources' key.
|
|
8
|
+
class Source
|
|
9
|
+
|
|
10
|
+
# @return [String] The URL for this source
|
|
11
|
+
attr_accessor :base_url
|
|
12
|
+
|
|
13
|
+
# @param [String] base_url The URL for this source
|
|
14
|
+
def initialize(base_url)
|
|
15
|
+
@base_url = base_url
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
# Search through the cookbooks available at this source, and return
|
|
19
|
+
# the relevant version if it is available.
|
|
20
|
+
# @return [Minimart::Mirror::SourceCookbook]
|
|
21
|
+
def find_cookbook(cookbook_name, version)
|
|
22
|
+
cookbooks.find do |cookbook|
|
|
23
|
+
cookbook.name == cookbook_name && cookbook.version == version
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
# Query this source for it's available cookbooks using the '/universe' endpoint.
|
|
28
|
+
# @return [Array<Minimart::Mirror::SourceCookbook]
|
|
29
|
+
def cookbooks
|
|
30
|
+
@cookbooks ||= fetch_universe_data.each_with_object([]) do |cookbook_info, memo|
|
|
31
|
+
name, versions = cookbook_info
|
|
32
|
+
memo.concat versions.map { |version, attrs| build_cookbook(name, version, attrs) }
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def to_s
|
|
37
|
+
base_url
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
private
|
|
41
|
+
|
|
42
|
+
def build_cookbook(name, version, attrs)
|
|
43
|
+
attrs = attrs.merge(name: name, version: version)
|
|
44
|
+
SourceCookbook.new(attrs)
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def fetch_universe_data
|
|
48
|
+
Configuration.output.puts "Fetching the universe for #{base_url} ..."
|
|
49
|
+
|
|
50
|
+
Utils::Http.get_json(base_url, 'universe')
|
|
51
|
+
|
|
52
|
+
rescue RestClient::ResourceNotFound
|
|
53
|
+
raise Error::UniverseNotFoundError.new "no universe found for #{base_url}"
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
require 'minimart/download/cookbook'
|
|
2
|
+
|
|
3
|
+
module Minimart
|
|
4
|
+
module Mirror
|
|
5
|
+
|
|
6
|
+
# A wrapper around a cookbook as found in the universe.json file from an
|
|
7
|
+
# external source (Chef Supermarket, etc...).
|
|
8
|
+
class SourceCookbook
|
|
9
|
+
|
|
10
|
+
# @return [String] the name of the cookbook
|
|
11
|
+
attr_accessor :name
|
|
12
|
+
|
|
13
|
+
# @return [String] the version of the cookbook
|
|
14
|
+
attr_accessor :version
|
|
15
|
+
|
|
16
|
+
# @return [Hash<String,String>] any dependencies the cookbook has
|
|
17
|
+
attr_accessor :dependencies
|
|
18
|
+
|
|
19
|
+
# @return [String] the path to the cookbook
|
|
20
|
+
attr_accessor :location_path
|
|
21
|
+
|
|
22
|
+
# @return [String] the type of location the cookbook is stored in (supermarket, etc.)
|
|
23
|
+
attr_accessor :location_type
|
|
24
|
+
|
|
25
|
+
# @return [String] URL to download the cookbook
|
|
26
|
+
attr_accessor :download_url
|
|
27
|
+
|
|
28
|
+
# @param [Hash] opts
|
|
29
|
+
# @option opts [String] name The name of the cookbook
|
|
30
|
+
# @option opts [String] version The version of the cookbook
|
|
31
|
+
# @option opts [String] location_path The path to the cookbook
|
|
32
|
+
# @option opts [String] download_url URL to download the cookbook
|
|
33
|
+
# @option opts [Hash] dependencies A hash containing any of the cookbook's dependencies.
|
|
34
|
+
# @option opts [String] location_type The type of location the cookbook is stored in (supermarket, etc.)
|
|
35
|
+
def initialize(opts)
|
|
36
|
+
@name = fetch_from_options(opts, 'name')
|
|
37
|
+
@version = fetch_from_options(opts, 'version')
|
|
38
|
+
@location_path = fetch_from_options(opts, 'location_path')
|
|
39
|
+
@download_url = fetch_from_options(opts, 'download_url')
|
|
40
|
+
@dependencies = fetch_from_options(opts, 'dependencies') || {}
|
|
41
|
+
@location_type = fetch_from_options(opts, 'location_type')
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
# Download this remote cookbook
|
|
45
|
+
# @yield [Dir] The path to the downloaded cookbook. This directory will be removed when the block exits.
|
|
46
|
+
def fetch(&block)
|
|
47
|
+
Download::Cookbook.new(self).fetch(&block)
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
# Convert this remote cookbook to a Hash
|
|
51
|
+
# @return [Hash]
|
|
52
|
+
def to_hash
|
|
53
|
+
{
|
|
54
|
+
source_type: location_type,
|
|
55
|
+
location: location_path
|
|
56
|
+
}
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
# Get the location_path as a URI
|
|
60
|
+
# @return [URI]
|
|
61
|
+
def location_path_uri
|
|
62
|
+
URI.parse(location_path)
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def web_friendly_version
|
|
66
|
+
version.gsub('.', '_')
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
private
|
|
70
|
+
|
|
71
|
+
def fetch_from_options(opts, key)
|
|
72
|
+
opts[key] || opts[key.to_sym]
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
end
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
module Minimart
|
|
2
|
+
module Mirror
|
|
3
|
+
# A collection of Minimart::Mirror::Source
|
|
4
|
+
class Sources < Array
|
|
5
|
+
|
|
6
|
+
# @param [Array<String>] source_urls An array of source URL's specified in the inventory
|
|
7
|
+
def initialize(source_urls = [])
|
|
8
|
+
source_urls.each { |source_url| add_source(source_url) }
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
# Iterate over each cookbook defined in each source
|
|
12
|
+
# @yield [Minimart::Mirror::SourceCookbook]
|
|
13
|
+
def each_cookbook(&block)
|
|
14
|
+
each { |source| source.cookbooks.each(&block) }
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
# Find the first cookbook from the avaiable sources with a matching name, and
|
|
18
|
+
# version
|
|
19
|
+
# @param [String] name The name of the cookbook to search for
|
|
20
|
+
# @param [String] version The version of the cookbook to search for
|
|
21
|
+
def find_cookbook(name, version)
|
|
22
|
+
each do |source|
|
|
23
|
+
cookbook = source.find_cookbook(name, version)
|
|
24
|
+
return cookbook if cookbook
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
raise Error::CookbookNotFound, "The cookbook #{name} with the version #{version} could not be found"
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
private
|
|
31
|
+
|
|
32
|
+
def add_source(source_url)
|
|
33
|
+
self << Source.new(source_url)
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
module Minimart
|
|
2
|
+
# Wrapper for IO to provide colored output.
|
|
3
|
+
class Output
|
|
4
|
+
|
|
5
|
+
attr_reader :io
|
|
6
|
+
|
|
7
|
+
def initialize(io)
|
|
8
|
+
@io = io
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def puts(*args)
|
|
12
|
+
io.puts(args)
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def puts_red(str)
|
|
16
|
+
puts_color(31, str)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def puts_green(str)
|
|
20
|
+
puts_color(32, str)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def puts_yellow(str)
|
|
24
|
+
puts_color(33, str)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
private
|
|
28
|
+
|
|
29
|
+
def puts_color(color_code, str)
|
|
30
|
+
self.puts "\e[#{color_code}m#{str}\e[0m"
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
end
|
|
34
|
+
end
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
require 'archive/tar/minitar'
|
|
2
|
+
require 'zlib'
|
|
3
|
+
require 'minimart/mirror/download_metadata'
|
|
4
|
+
|
|
5
|
+
module Minimart
|
|
6
|
+
module Utils
|
|
7
|
+
|
|
8
|
+
# Archive manages tarring, and gzipping files
|
|
9
|
+
module Archive
|
|
10
|
+
|
|
11
|
+
# Extract a tar.gz archive
|
|
12
|
+
# @param [String] archive_file The path to the archive file
|
|
13
|
+
# @param [String] destination The directory to unpack the archive to
|
|
14
|
+
def self.extract_archive(archive_file, destination)
|
|
15
|
+
tar = Zlib::GzipReader.new(File.open(archive_file, 'rb'))
|
|
16
|
+
::Archive::Tar::Minitar.unpack(tar, destination)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
# Build a tar.tz archive from a directory
|
|
20
|
+
# @param [Minimart::Cookbook] cookbook The cookbook to archive
|
|
21
|
+
# @param [String] destination The path to store the tar.gz archive
|
|
22
|
+
def self.pack_archive(cookbook, destination)
|
|
23
|
+
Dir.mktmpdir do |tmp|
|
|
24
|
+
Dir.chdir(tmp) do
|
|
25
|
+
archive_dir = File.join(tmp, cookbook.name)
|
|
26
|
+
FileUtils.mkdir_p(archive_dir)
|
|
27
|
+
FileUtils.cp_r(File.join(cookbook.path, '.'), archive_dir)
|
|
28
|
+
meta_file = File.join(archive_dir, Minimart::Mirror::DownloadMetadata::FILE_NAME)
|
|
29
|
+
FileUtils.remove_entry(meta_file) if File.exists?(meta_file)
|
|
30
|
+
|
|
31
|
+
tgz = Zlib::GzipWriter.new(File.open(destination, 'wb'))
|
|
32
|
+
::Archive::Tar::Minitar.pack(cookbook.name, tgz)
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
module Minimart
|
|
2
|
+
module Utils
|
|
3
|
+
# FileHelper contains helper methods for dealing with the file system.
|
|
4
|
+
module FileHelper
|
|
5
|
+
|
|
6
|
+
# Find the first cookbook in the given path
|
|
7
|
+
# @param [String] path The directory to search for cookbooks in
|
|
8
|
+
# @return [String] The path to the cookbook
|
|
9
|
+
def self.cookbook_path_in_directory(path)
|
|
10
|
+
cookbook_in_path?(path) ? path : find_cookbooks_in_directory(path).first
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
# List all of the cookbooks in a given directory
|
|
14
|
+
# @param [String] path The directory to find cookbooks in
|
|
15
|
+
# @return [Array<String>] An array of paths to any cookbooks found in the supplied path.
|
|
16
|
+
def self.find_cookbooks_in_directory(path)
|
|
17
|
+
Dir.glob(File.join(path, '/*/')).select { |d| cookbook_in_path?(d) }
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
# Determine whether or not a given directory contains a cookbook.
|
|
21
|
+
# @param [String] path The directory to check
|
|
22
|
+
# @return [Boolean]
|
|
23
|
+
def self.cookbook_in_path?(path)
|
|
24
|
+
file_exists?(File.join(path, 'metadata.json')) ||
|
|
25
|
+
file_exists?(File.join(path, 'metadata.rb'))
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def self.file_exists?(path)
|
|
29
|
+
File.exists?(path)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
require 'rest_client'
|
|
2
|
+
require 'uri'
|
|
3
|
+
|
|
4
|
+
module Minimart
|
|
5
|
+
module Utils
|
|
6
|
+
# A collection of methods to help issue HTTP requests
|
|
7
|
+
module Http
|
|
8
|
+
|
|
9
|
+
# Issue a GET request to a URL, and return parsed JSON.
|
|
10
|
+
# @param [String] url The base URL to hit
|
|
11
|
+
# @param [String] path The path to the RESTful resource to fetch
|
|
12
|
+
# @return [Hash] The parsed JSON response
|
|
13
|
+
def self.get_json(url, path=nil)
|
|
14
|
+
JSON.parse(get(url, path, accept: 'application/json'))
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
# Issue a GET request to a URL
|
|
18
|
+
# @param [String] base_url The base URL to hit
|
|
19
|
+
# @param [String] path The path to the RESTful resource to fetch
|
|
20
|
+
def self.get(base_url, path=nil, headers={})
|
|
21
|
+
headers = headers.merge(verify_ssl: Minimart::Configuration.verify_ssl)
|
|
22
|
+
|
|
23
|
+
resource = RestClient::Resource.new(base_url.to_s)
|
|
24
|
+
path ? resource[path].get(headers) : resource.get(headers)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
# GET a binary file
|
|
28
|
+
# @param [String] base_name A base name to give the returned file
|
|
29
|
+
# @param [String] url The base URL to hit
|
|
30
|
+
# @param [String] path The path to the RESTful resource to fetch
|
|
31
|
+
# @return [Tempfile]
|
|
32
|
+
def self.get_binary(base_name, url, path=nil)
|
|
33
|
+
result = Tempfile.new(base_name)
|
|
34
|
+
result.binmode
|
|
35
|
+
result.write(get(url, path))
|
|
36
|
+
result.close(false)
|
|
37
|
+
result
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
# Build a URL from a base URL, and a path
|
|
41
|
+
# @param [String] base_url The base URL to hit
|
|
42
|
+
# @param [String] path
|
|
43
|
+
def self.build_url(base_url, path=nil)
|
|
44
|
+
result = (base_url =~ /\A[a-z].*:\/\//i) ? base_url : "http://#{base_url}"
|
|
45
|
+
result = URI.parse(result).to_s
|
|
46
|
+
result = concat_url_fragment(result, path)
|
|
47
|
+
return result
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def self.concat_url_fragment(frag_one, frag_two)
|
|
51
|
+
return frag_one unless frag_two
|
|
52
|
+
result = frag_one
|
|
53
|
+
result << '/' unless result[-1] == '/'
|
|
54
|
+
result << ((frag_two[0] == '/') ? frag_two[1..-1] : frag_two)
|
|
55
|
+
result
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
data/lib/minimart/web.rb
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
module Minimart
|
|
2
|
+
# The Web namespace is used for building the cookbook index, and generating
|
|
3
|
+
# any HTML.
|
|
4
|
+
module Web
|
|
5
|
+
require 'minimart/web/cookbooks'
|
|
6
|
+
require 'minimart/web/html_generator'
|
|
7
|
+
require 'minimart/web/template_helper'
|
|
8
|
+
require 'minimart/web/universe_generator'
|
|
9
|
+
end
|
|
10
|
+
end
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
module Minimart
|
|
2
|
+
module Web
|
|
3
|
+
# Generate "show" pages for a set of cookbooks
|
|
4
|
+
class CookbookShowPageGenerator
|
|
5
|
+
include TemplateHelper
|
|
6
|
+
|
|
7
|
+
# @return [String] the directory to put any generated HTML in
|
|
8
|
+
attr_reader :web_directory
|
|
9
|
+
|
|
10
|
+
# @return [Minimart::Web::Cookbooks] the cookbooks to generate show pages for
|
|
11
|
+
attr_reader :cookbooks
|
|
12
|
+
|
|
13
|
+
# @param [Hash] opts
|
|
14
|
+
# @option opts [String] :web_directory The directory to put any generated HTML in
|
|
15
|
+
# @option opts [String] :cookbooks The cookbooks to generate show pages for
|
|
16
|
+
def initialize(opts = {})
|
|
17
|
+
@web_directory = opts[:web_directory]
|
|
18
|
+
@cookbooks = opts[:cookbooks]
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# Generate the HTML!
|
|
22
|
+
def generate
|
|
23
|
+
clean_web_cookbooks_directory
|
|
24
|
+
make_web_cookbooks_directory
|
|
25
|
+
create_html_files
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
private
|
|
29
|
+
|
|
30
|
+
def clean_web_cookbooks_directory
|
|
31
|
+
return unless Dir.exists?(cookbooks_directory)
|
|
32
|
+
FileUtils.remove_entry(cookbooks_directory)
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def make_web_cookbooks_directory
|
|
36
|
+
FileUtils.mkdir_p(cookbooks_directory)
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def create_html_files
|
|
40
|
+
cookbooks.each do |cookbook_name, versions|
|
|
41
|
+
versions.each do |cookbook|
|
|
42
|
+
write_to_file(file(cookbook), template_content(cookbook, versions))
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def file(cookbook)
|
|
48
|
+
FileUtils.mkdir_p(File.join(web_directory, cookbook_dir(cookbook)))
|
|
49
|
+
File.join(web_directory, cookbook_file(cookbook))
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def template_content(cookbook, versions)
|
|
53
|
+
render_in_base_layout do
|
|
54
|
+
render_template('cookbook_show.erb', self, {cookbook: cookbook, other_versions: versions})
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def write_to_file(file_path, content)
|
|
59
|
+
File.open(file_path, 'w+') { |f| f.write(content) }
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def cookbooks_directory
|
|
63
|
+
File.join(web_directory, 'cookbooks')
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def cookbook_for_requirement(name, version_requirement)
|
|
67
|
+
(cookbooks[name] || []).find do |c|
|
|
68
|
+
c.satisfies_requirement?(version_requirement)
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def level
|
|
73
|
+
2
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
end
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
require 'forwardable'
|
|
2
|
+
|
|
3
|
+
require 'minimart/cookbook'
|
|
4
|
+
require 'minimart/utils/file_helper'
|
|
5
|
+
|
|
6
|
+
module Minimart
|
|
7
|
+
module Web
|
|
8
|
+
# Given a path to the inventory directory, this class will generate the necessary
|
|
9
|
+
# JSON output to power the main dashboard, and return cookbooks in a format
|
|
10
|
+
# that can be used to build the various web pages.
|
|
11
|
+
class Cookbooks
|
|
12
|
+
extend Forwardable
|
|
13
|
+
|
|
14
|
+
include Enumerable
|
|
15
|
+
|
|
16
|
+
FILE_NAME = 'data.json'
|
|
17
|
+
|
|
18
|
+
# @return [String] The path to the cookbook inventory
|
|
19
|
+
attr_reader :inventory_directory
|
|
20
|
+
|
|
21
|
+
# @param [Hash] opts
|
|
22
|
+
# @option opts [String] :inventory_directory The path to the cookbook inventory
|
|
23
|
+
def initialize(opts)
|
|
24
|
+
@inventory_directory = opts[:inventory_directory]
|
|
25
|
+
@data_structure = {}
|
|
26
|
+
|
|
27
|
+
generate
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
# Get a JSON representation of the most recent version of each cookbook
|
|
31
|
+
# found in the inventory_directory.
|
|
32
|
+
# @return [Hash]
|
|
33
|
+
def to_json
|
|
34
|
+
map do |cookbook_name, cookbook_versions|
|
|
35
|
+
cookbook_versions.first.to_hash.merge(available_versions: cookbook_versions.size)
|
|
36
|
+
end.to_json
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def_delegators :data_structure, :each, :keys, :values, :[]
|
|
40
|
+
|
|
41
|
+
# Get a non-nested version of the cookbooks structure
|
|
42
|
+
def individual_cookbooks
|
|
43
|
+
values.flatten
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# Add a cookbook to the data structure.
|
|
47
|
+
# @param [Minimart::Cookbook] cookbook The cookbook to add
|
|
48
|
+
def add(cookbook)
|
|
49
|
+
data_structure[cookbook.name] ||= []
|
|
50
|
+
data_structure[cookbook.name] << cookbook
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
private
|
|
54
|
+
|
|
55
|
+
attr_reader :data_structure
|
|
56
|
+
|
|
57
|
+
def generate
|
|
58
|
+
build_data_structure
|
|
59
|
+
sort_data
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def build_data_structure
|
|
63
|
+
cookbooks.each { |cookbook| add(cookbook) }
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
# Sort cookbooks in version desc order
|
|
67
|
+
def sort_data
|
|
68
|
+
data_structure.values.map! do |versions|
|
|
69
|
+
versions.sort!.reverse!
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def cookbooks
|
|
74
|
+
inventory_cookbook_paths.map { |path| Minimart::Cookbook.from_path(path) }
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def inventory_cookbook_paths
|
|
78
|
+
Utils::FileHelper.find_cookbooks_in_directory(inventory_directory)
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
end
|