Skip to content
This repository was archived by the owner on Feb 7, 2024. It is now read-only.

Commit 5346fcd

Browse files
committed
(maint) Add Github pages documentation website
1 parent bbb743b commit 5346fcd

14 files changed

+453
-0
lines changed

_config.yml

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
theme: jekyll-theme-midnight

docs/.gitignore

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
_site
2+
.sass-cache
3+
.jekyll-metadata

docs/404.html

+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
---
2+
layout: default
3+
---
4+
5+
<style type="text/css" media="screen">
6+
.container {
7+
margin: 10px auto;
8+
max-width: 600px;
9+
text-align: center;
10+
}
11+
h1 {
12+
margin: 30px 0;
13+
font-size: 4em;
14+
line-height: 1;
15+
letter-spacing: -1px;
16+
}
17+
</style>
18+
19+
<div class="container">
20+
<h1>404</h1>
21+
22+
<p><strong>Page not found :(</strong></p>
23+
<p>The requested page could not be found.</p>
24+
</div>

docs/Gemfile

+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
source ENV['GEM_SOURCE'] || "https://rubygems.org"
2+
3+
gem "rake"
4+
5+
if Gem.win_platform?
6+
# Jekyll really hates Windows :-( Need to use WSL instead
7+
raise 'Jekyll really hates Windows :-( Need to use WSL instead'
8+
end
9+
10+
# If you want to use GitHub Pages, remove the "gem "jekyll"" above and
11+
# uncomment the line below. To upgrade, run `bundle update github-pages`.
12+
gem "github-pages", group: :jekyll_plugins
13+
14+
# If you have any plugins, put them here!
15+
group :jekyll_plugins do
16+
gem "jekyll-feed", "~> 0.6"
17+
end
18+
19+
# Evaluate Gemfile.local if it exists
20+
if File.exists? "#{__FILE__}.local"
21+
eval(File.read("#{__FILE__}.local"), binding)
22+
end

docs/Rakefile

+63
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
is_windows = (ENV['OS'] == 'Windows_NT')
2+
3+
# clean settings
4+
desc 'Clean'
5+
task :clean do
6+
puts 'Cleaning Jekyll'
7+
system 'jekyll clean'
8+
end
9+
10+
basicSettings = '--trace --safe --host=0.0.0.0'
11+
devConfig = '--config _config.yml,_config.dev.yml --unpublished --future'
12+
13+
namespace :build do
14+
desc 'Build Jekyll with production settings'
15+
task :prod => [:clean] do
16+
puts 'Building Jekyll with PRODUCTION settings...'
17+
system "JEKYLL_ENV=production jekyll build #{basicSettings} --no-watch"
18+
end
19+
20+
desc 'Build Jekyll with development settings'
21+
task :dev do
22+
puts 'Building Jekyll with DEVELOPMENT settings...'
23+
system "JEKYLL_ENV=development jekyll build #{basicSettings} #{devConfig} --no-watch"
24+
end
25+
end
26+
27+
namespace :serve do
28+
desc 'Serve Jekyll with production settings'
29+
task :prod => [:clean] do
30+
puts 'Building Jekyll with PRODUCTION settings...'
31+
if is_windows then
32+
ENV['JEKYLL_ENV'] = "production"
33+
system "jekyll serve #{basicSettings}"
34+
else
35+
system "JEKYLL_ENV=production jekyll serve #{basicSettings}"
36+
end
37+
end
38+
39+
desc 'Serve Jekyll with development settings'
40+
task :dev => [:clean] do
41+
puts 'Building Jekyll with DEVELOPMENT settings...'
42+
if is_windows then
43+
ENV['JEKYLL_ENV'] = "development"
44+
system "jekyll serve #{basicSettings} #{devConfig}"
45+
else
46+
system "JEKYLL_ENV=development jekyll serve #{basicSettings} #{devConfig}"
47+
end
48+
end
49+
50+
end
51+
52+
namespace :watch do
53+
desc 'Serve and watch Jekyll with development settings'
54+
task :dev => [:clean] do
55+
puts 'Building Jekyll with DEVELOPMENT settings...'
56+
if is_windows then
57+
ENV['JEKYLL_ENV'] = "development"
58+
system "jekyll serve #{basicSettings} #{devConfig} --livereload --incremental"
59+
else
60+
system "JEKYLL_ENV=development jekyll serve --incremental #{basicSettings} #{devConfig} --livereload"
61+
end
62+
end
63+
end

docs/_config.dev.yml

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
---

docs/_config.yml

+46
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
# Welcome to Jekyll!
2+
#
3+
# This config file is meant for settings that affect your whole blog, values
4+
# which you are expected to set up once and rarely edit after that. If you find
5+
# yourself editing this file very often, consider using Jekyll's data files
6+
# feature for the data you need to update frequently.
7+
#
8+
# For technical reasons, this file is *NOT* reloaded automatically when you use
9+
# 'bundle exec jekyll serve'. If you change this file, please restart the server process.
10+
11+
# Site settings
12+
# These are used to personalize your new site. If you look in the HTML files,
13+
# you will see them accessed via {{ site.title }}, {{ site.email }}, and so on.
14+
# You can create any custom variable you would like, and they will be accessible
15+
# in the templates via {{ site.myvariable }}.
16+
title: Puppetfile Resolver
17+
email:
18+
description: Dependency resolver for Puppet Modules and Puppetfiles, as a gem!
19+
baseurl: "/puppetfile-resolver" # the subpath of your site, e.g. /blog
20+
url: "https://glennsarti.github.io" # the base hostname & protocol for your site, e.g. http://example.com
21+
twitter_username: glennsarti
22+
github_username: glennsarti
23+
24+
theme: jekyll-theme-cayman
25+
#theme: cayman
26+
27+
# Build settings
28+
markdown: kramdown
29+
plugins:
30+
- jekyll-feed
31+
- jekyll-github-metadata
32+
33+
# Github Info
34+
repository: "glennsarti/puppetfile-resolver"
35+
36+
# Exclude from processing.
37+
# The following items will not be processed, by default. Create a custom list
38+
# to override the default setting.
39+
exclude:
40+
- Gemfile
41+
- Gemfile.lock
42+
- node_modules
43+
- vendor/bundle/
44+
- vendor/cache/
45+
- vendor/gems/
46+
- vendor/ruby/

docs/_includes/sections.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{% if page.title == "Puppetfile Resolver" %}- About{% else %}- [About](.){% endif %}
2+
{% if page.title == "Architecture" %}- Architecture{% else %}- [Architecture](./architecture){% endif %}
3+
{% if page.title == "Parsers" %}- Parsers{% else %}- [Parsers](./parsers){% endif %}
4+
{% if page.title == 'Example Usage' %}- Example Usage{% else %}- [Example Usage](./example_usage){% endif %}
5+
{% if page.title == 'Known Issues' %}- Known Issues{% else %}- [Known Issues](./known_issues){% endif %}

docs/architecture.md

+141
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
---
2+
---
3+
4+
# Architecture
5+
6+
{% include sections.md %}
7+
8+
---
9+
10+
## Why a library and not a CLI tool?
11+
12+
Due to all of the different needs of tool developers, this is offered as a library instead of full blown CLI tool. For example, the needs of a VSCode Extensions developer are very different than that of the Puppet Developer Kit developer.
13+
14+
Therefore this is a library which is intended to be used by tool developers to create useful tools for users, and not really for direct use by users.
15+
16+
Note that a CLI is included (`puppetfile-cli.rb`) only as an example of how to create a tool using this library.
17+
18+
## Architecture
19+
20+
``` text
21+
+-----------------+ +-----------------+ +-----------------+
22+
| Forge Searcher | | Github Searcher | | Local Searcher |
23+
+-------+---------+ +--------+--------+ +-------+---------+
24+
| | |
25+
+----------------------+--------------------+
26+
|
27+
|
28+
V
29+
+--------+ +----------+ +-------------------+
30+
-- Text --> | Parser | -- Document Model -+-> | Resolver | -- Dependency Graph -+-> | Resolution Result |
31+
+--------+ | +----------+ | +-------------------+
32+
| |
33+
| |
34+
V V
35+
+-----------+ +------------+
36+
| Document | | Resolution |
37+
| Validator | | Validator |
38+
+-----------+ +------------+
39+
```
40+
41+
### Workflow
42+
43+
The workflow of the library is, hopefully, straightforward:
44+
45+
1. A list of modules needed, typically expressed as a Puppetfile is parsed into a Document Model. This model means that additional parsers can be added a later time, or users can craft their own Document Model and not need a parser at all. See _Creating a document model_ below for more information.
46+
47+
2. The Document Model can then, optionally, be validated
48+
49+
3. The Resolver can then be called on the Document Model, which outputs a Resolution Result (if successful) or an appropriate error
50+
51+
4. The Resolution Result can also be validated according to Puppetfile rules. For example, it must not include modules which were not declared in the Puppetfile.
52+
53+
### Puppetfile Parser
54+
55+
The parser converts the content of a Puppetfile into a document model (`PuppetfileResolver::Puppetfile::Document`).
56+
57+
See [Parsers](./parsers) for more information about the available parsers.
58+
59+
### Creating a document model
60+
61+
A user of the library can craft a document model object in any fashion they require. To do so, first the user needs to create a blank document model (`PuppetfileResolver::Puppetfile::Document.new('')`), and call `add_module` with an appropriately created module definition:
62+
63+
- `PuppetfileResolver::Puppetfile::ForgeModule`
64+
- `PuppetfileResolver::Puppetfile::GitModule`
65+
- `PuppetfileResolver::Puppetfile::LocalModule`
66+
- `PuppetfileResolver::Puppetfile::SvnModule`
67+
68+
Note that the `PuppetfileResolver::Puppetfile::InvalidModule` class should not really be used as it will cause validation errors. Typically this is used by parsers to express that it found a module definition but it could not determine the type of module it is.
69+
70+
A complete example is shown below, where it creates a document of all the latest modules in the `module_list` array
71+
72+
``` ruby
73+
module_list = ['puppetlabs/stdlib']
74+
75+
# Build the document model from the module names, defaulting to the latest version of each module
76+
model = PuppetfileResolver::Puppetfile::Document.new('')
77+
module_list.each do |mod_name|
78+
model.add_module(
79+
PuppetfileResolver::Puppetfile::ForgeModule.new(mod_name).tap { |mod| mod.version = :latest }
80+
)
81+
end
82+
```
83+
84+
85+
### Puppetfile Document Validation
86+
87+
Even though a Puppetfile can be parsed, doesn't mean it's valid. For example, defining a module twice.
88+
89+
### Puppetfile Resolution
90+
91+
Given a Puppetfile document model, the library can attempt to recursively resolve all of the modules and their dependencies. The resolver be default will not be strict, that is, missing dependencies will not throw an error, and will attempt to also be resolved. When in strict mode, any missing dependencies will throw errors.
92+
93+
### Module Searchers
94+
95+
The Puppetfile resolution needs information about all of the available modules and versions, and does this through calling various Specification Searchers. Currently Puppet Forge, Github and Local FileSystem searchers are implemented. Additional searchers could be added, for example GitLab or SVN.
96+
97+
The result is a dependency graph listing all of the modules, dependencies and version information.
98+
99+
### Resolution validation
100+
101+
Even though a Puppetfile can be resolved, doesn't mean it is valid. For example, missing module dependencies are not considered valid.
102+
103+
### Dependency Graph
104+
105+
The resolver uses the [Molinillo](https://github.com/CocoaPods/Molinillo) ruby gem for dependency resolution. Molinillo is used in Bundler, among other gems, so it's well used and maintained project.
106+
107+
### Example usage
108+
109+
``` ruby
110+
puppetfile_path = '/path/to/Puppetfile'
111+
112+
# Parse the Puppetfile into an object model
113+
content = File.open(puppetfile_path, 'rb') { |f| f.read }
114+
require 'puppetfile-resolver/puppetfile/parser/r10k_eval'
115+
puppetfile = ::PuppetfileResolver::Puppetfile::Parser::R10KEval.parse(content)
116+
117+
# Make sure the Puppetfile is valid
118+
unless puppetfile.valid?
119+
puts 'Puppetfile is not valid'
120+
puppetfile.validation_errors.each { |err| puts err }
121+
exit 1
122+
end
123+
124+
# Create the resolver
125+
# - Use the document we just parsed (puppetfile)
126+
# - Don't restrict by Puppet version (nil)
127+
resolver = PuppetfileResolver::Resolver.new(puppetfile, nil)
128+
129+
# Configure the resolver
130+
cache = nil # Use the default inmemory cache
131+
ui = nil # Don't output any information
132+
module_paths = [] # List of paths to search for modules on the local filesystem
133+
allow_missing_modules = true # Allow missing dependencies to be resolved
134+
opts = { cache: cache, ui: ui, module_paths: module_paths, allow_missing_modules: allow_missing_modules }
135+
136+
# Resolve
137+
result = resolver.resolve(opts)
138+
139+
# Output resolution validation errors
140+
result.validation_errors.each { |err| puts "Resolution Validation Error: #{err}\n"}
141+
```

docs/assets/css/style.scss

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
---
2+
---
3+
4+
@import "{{ site.theme }}";

docs/example_usage.md

+44
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
---
2+
---
3+
4+
# Example Usage
5+
6+
{% include sections.md %}
7+
8+
---
9+
10+
This example reads in a Puppet file from `'/path/to/Puppetfile'` and outputs any validation errors to the console
11+
12+
``` ruby
13+
puppetfile_path = '/path/to/Puppetfile'
14+
15+
# Parse the Puppetfile into an object model
16+
content = File.open(puppetfile_path, 'rb') { |f| f.read }
17+
require 'puppetfile-resolver/puppetfile/parser/r10k_eval'
18+
puppetfile = ::PuppetfileResolver::Puppetfile::Parser::R10KEval.parse(content)
19+
20+
# Make sure the Puppetfile is valid
21+
unless puppetfile.valid?
22+
puts 'Puppetfile is not valid'
23+
puppetfile.validation_errors.each { |err| puts err }
24+
exit 1
25+
end
26+
27+
# Create the resolver
28+
# - Use the document we just parsed (puppetfile)
29+
# - Don't restrict by Puppet version (nil)
30+
resolver = PuppetfileResolver::Resolver.new(puppetfile, nil)
31+
32+
# Configure the resolver
33+
cache = nil # Use the default inmemory cache
34+
ui = nil # Don't output any information
35+
module_paths = [] # List of paths to search for modules on the local filesystem
36+
allow_missing_modules = true # Allow missing dependencies to be resolved
37+
opts = { cache: cache, ui: ui, module_paths: module_paths, allow_missing_modules: allow_missing_modules }
38+
39+
# Resolve
40+
result = resolver.resolve(opts)
41+
42+
# Output resolution validation errors
43+
result.validation_errors.each { |err| puts "Resolution Validation Error: #{err}\n"}
44+
```

docs/index.md

+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
---
2+
title: "Puppetfile Resolver"
3+
layout: default
4+
---
5+
[![Open Issues](https://img.shields.io/github/issues/glennsarti/puppetfile-resolver)](https://github.com/glennsarti/puppetfile-resolver/issues)
6+
[![License](https://img.shields.io/github/license/glennsarti/puppetfile-resolver)](https://github.com/glennsarti/puppetfile-resolver)
7+
[![Gem Version](https://img.shields.io/gem/v/puppetfile-resolver)](https://rubygems.org/gems/puppetfile-resolver)
8+
9+
{% include sections.md %}
10+
11+
---
12+
13+
# Puppetfile Resolver
14+
15+
The [Puppetfile](https://puppet.com/docs/pe/latest/puppetfile.html) is used by Puppet to manage the collection of modules used by a Puppet master. The Puppetfile is then used by tools like [R10K](https://github.com/puppetlabs/r10k) and [Code Manager](https://puppet.com/docs/pe/latest/code_mgr_how_it_works.html#how-code-manager-works) to download and install the required modules.
16+
17+
However, the Puppetfile is designed to have explicit dependencies, that is, **all** modules and **all** of the dependencies must be specified in Puppetfile. This is very different to formats like `Gemfile` (Ruby) or `package.json` (NodeJS) where dependencies are brought in as needed.
18+
19+
Using explicit dependencies is great in a configuration management system like Puppet, but it puts the burden on updates onto the user.
20+
21+
This library includes all of the code to parse a Puppetfile and then calculate a dependency graph to try and resolve all of the module dependencies and versions. The resolver can also restrict on Puppet version, for example, only Modules which support Puppet 6.
22+
23+
**Note** This library is in active development!
24+
25+
## To Do
26+
27+
- Could do with more tests
28+
- Add YARD documentation

0 commit comments

Comments
 (0)