middleman-hashicorp 0.2.0
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 +7 -0
- data/.gitignore +15 -0
- data/.travis.yml +12 -0
- data/Gemfile +2 -0
- data/LICENSE +21 -0
- data/Makefile +21 -0
- data/README.md +183 -0
- data/Rakefile +11 -0
- data/assets/fonts/glyphicons-halflings-regular.eot +0 -0
- data/assets/fonts/glyphicons-halflings-regular.svg +229 -0
- data/assets/fonts/glyphicons-halflings-regular.ttf +0 -0
- data/assets/fonts/glyphicons-halflings-regular.woff +0 -0
- data/assets/images/fastly_logo.png +0 -0
- data/assets/images/icons/icon_centos.png +0 -0
- data/assets/images/icons/icon_darwin.png +0 -0
- data/assets/images/icons/icon_debian.png +0 -0
- data/assets/images/icons/icon_freebsd.png +0 -0
- data/assets/images/icons/icon_hashios.png +0 -0
- data/assets/images/icons/icon_linux.png +0 -0
- data/assets/images/icons/icon_macosx.png +0 -0
- data/assets/images/icons/icon_netbsd.png +0 -0
- data/assets/images/icons/icon_openbsd.png +0 -0
- data/assets/images/icons/icon_rpm.png +0 -0
- data/assets/images/icons/icon_solaris.png +0 -0
- data/assets/images/icons/icon_windows.png +0 -0
- data/assets/javascripts/bootstrap.js +2114 -0
- data/assets/javascripts/ie-compat.js +1 -0
- data/assets/javascripts/ie-compat/html5shiv-printshiv.js +520 -0
- data/assets/javascripts/ie-compat/html5shiv.js +322 -0
- data/assets/javascripts/ie-compat/respond.js +353 -0
- data/assets/javascripts/jquery.js +9190 -0
- data/docker/Dockerfile +22 -0
- data/lib/middleman-hashicorp.rb +6 -0
- data/lib/middleman-hashicorp/bintray.rb +98 -0
- data/lib/middleman-hashicorp/extension.rb +237 -0
- data/lib/middleman-hashicorp/redcarpet.rb +134 -0
- data/lib/middleman-hashicorp/releases.rb +32 -0
- data/lib/middleman-hashicorp/rouge.rb +16 -0
- data/lib/middleman-hashicorp/version.rb +5 -0
- data/lib/middleman_extension.rb +1 -0
- data/middleman-hashicorp.gemspec +48 -0
- data/spec/spec_helper.rb +34 -0
- data/spec/unit/helper_spec.rb +71 -0
- data/spec/unit/markdown_spec.rb +206 -0
- data/spec/unit/releases_spec.rb +34 -0
- metadata +330 -0
data/docker/Dockerfile
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
FROM ruby:2.3-slim
|
2
|
+
MAINTAINER Seth Vargo <seth@hashicorp.com>
|
3
|
+
|
4
|
+
# Required packages
|
5
|
+
RUN \
|
6
|
+
apt-get -qq update && \
|
7
|
+
apt-get install -yqq build-essential git python-setuptools
|
8
|
+
|
9
|
+
# Install s3cmd
|
10
|
+
RUN \
|
11
|
+
curl -sLo /s3cmd-1.6.1.tar.gz https://github.com/s3tools/s3cmd/releases/download/v1.6.1/s3cmd-1.6.1.tar.gz && \
|
12
|
+
tar -xzvf /s3cmd-1.6.1.tar.gz && \
|
13
|
+
cd /s3cmd-1.6.1 && \
|
14
|
+
python setup.py install && \
|
15
|
+
rm -rf /s3cmd-1.6.1*
|
16
|
+
|
17
|
+
# Install the bundle
|
18
|
+
RUN \
|
19
|
+
gem install middleman-hashicorp --version "${VERSION}"
|
20
|
+
|
21
|
+
CMD (bundle check || bundle install) && \
|
22
|
+
bundle exec middleman build --clean
|
@@ -0,0 +1,98 @@
|
|
1
|
+
require "open-uri"
|
2
|
+
|
3
|
+
class Middleman::HashiCorp::BintrayAPI
|
4
|
+
attr_reader :filter
|
5
|
+
attr_reader :prefixed
|
6
|
+
|
7
|
+
#
|
8
|
+
# @param [String] :repo (e.g. mitchellh/packer)
|
9
|
+
# @param [String] :user (e.g. mitchellh/packer)
|
10
|
+
# @param [String] :key (e.g. abcd1234)
|
11
|
+
# @param [Proc] :filter
|
12
|
+
# @param [Boolean] :prefixed
|
13
|
+
#
|
14
|
+
def initialize(repo: nil, user: nil, key: nil, filter: nil, prefixed: true)
|
15
|
+
set_or_raise(:repo, repo)
|
16
|
+
set_or_raise(:user, user)
|
17
|
+
set_or_raise(:key, key)
|
18
|
+
|
19
|
+
@filter = filter || Proc.new {}
|
20
|
+
@prefixed = prefixed
|
21
|
+
end
|
22
|
+
|
23
|
+
#
|
24
|
+
# Get the structured downloads for the given version and required OSes.
|
25
|
+
#
|
26
|
+
# @example
|
27
|
+
# api.downloads_for_version("1.0.0") #=>
|
28
|
+
# {
|
29
|
+
# "os" => {
|
30
|
+
# "arch" => "http://download.url",
|
31
|
+
# }
|
32
|
+
# }
|
33
|
+
#
|
34
|
+
# @return [Hash]
|
35
|
+
#
|
36
|
+
def downloads_for_version(version)
|
37
|
+
url = "http://dl.bintray.com/#{repo}/"
|
38
|
+
options = { http_basic_authentication: [user, key] }
|
39
|
+
|
40
|
+
if prefixed
|
41
|
+
project = repo.split("/", 2).last
|
42
|
+
regex = /(#{Regexp.escape(project)}_#{Regexp.escape(version)}_.+?)('|")/
|
43
|
+
else
|
44
|
+
regex = /(#{Regexp.escape(version)}_.+?)('|")/
|
45
|
+
end
|
46
|
+
|
47
|
+
result = {}
|
48
|
+
|
49
|
+
open(url, options) do |file|
|
50
|
+
file.readlines.each do |line|
|
51
|
+
if line.chomp! =~ regex
|
52
|
+
filename = $1
|
53
|
+
|
54
|
+
# Hardcoded filter
|
55
|
+
next if filename.include?("SHA256SUMS")
|
56
|
+
|
57
|
+
os = filename.strip.split("_")[-2].strip
|
58
|
+
|
59
|
+
# Custom filter
|
60
|
+
next if filter.call(os, filename)
|
61
|
+
|
62
|
+
arch = line.split("_").last.split(".", 2).first
|
63
|
+
|
64
|
+
result[os] ||= {}
|
65
|
+
result[os][arch] = "https://dl.bintray.com/#{repo}/#{filename}"
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
result
|
71
|
+
rescue OpenURI::HTTPError
|
72
|
+
# Ignore HTTP errors and just have no versions
|
73
|
+
return {}
|
74
|
+
end
|
75
|
+
|
76
|
+
private
|
77
|
+
|
78
|
+
#
|
79
|
+
# Magical method that checks if the value is truly present (i.e. not an
|
80
|
+
# empty string), raising an exception if it is not. If the value is present,
|
81
|
+
# the named instance variable and attr_reader are defined.
|
82
|
+
#
|
83
|
+
# @raise [RuntimeError]
|
84
|
+
# @return [true]
|
85
|
+
#
|
86
|
+
def set_or_raise(key, value)
|
87
|
+
value = value.to_s.strip
|
88
|
+
|
89
|
+
if value.empty?
|
90
|
+
raise "Bintray #{key} was not given!"
|
91
|
+
end
|
92
|
+
|
93
|
+
instance_variable_set(:"@#{key}", value)
|
94
|
+
self.class.send(:attr_reader, :"#{key}")
|
95
|
+
|
96
|
+
true
|
97
|
+
end
|
98
|
+
end
|
@@ -0,0 +1,237 @@
|
|
1
|
+
module Middleman
|
2
|
+
module HashiCorp
|
3
|
+
require_relative "bintray"
|
4
|
+
require_relative "redcarpet"
|
5
|
+
require_relative "releases"
|
6
|
+
require_relative "rouge"
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
class Middleman::HashiCorpExtension < ::Middleman::Extension
|
11
|
+
option :bintray_enabled, false, "Whether Bintray is enabeld"
|
12
|
+
option :bintray_repo, nil, "The Bintray repo name (e.g. mitchellh/packer)"
|
13
|
+
option :bintray_user, nil, "The Bintray http basic auth user (e.g. mitchellh)"
|
14
|
+
option :bintray_key, nil, "The Bintray http basic auth key (e.g. abcd1234)"
|
15
|
+
option :bintray_exclude_proc, nil, "A filter to apply for packages"
|
16
|
+
option :bintray_prefixed, true, "Whether packages are prefixed with the project name"
|
17
|
+
|
18
|
+
option :name, nil, "The name of the package (e.g. 'consul')"
|
19
|
+
option :version, nil, "The version of the package (e.g. 0.1.0)"
|
20
|
+
option :minify_javascript, true, "Whether to minimize JS or not"
|
21
|
+
option :github_slug, nil, "The project's GitHub namespace/project_name duo (e.g. hashicorp/serf)"
|
22
|
+
option :website_root, "website", "The project's middleman directory relative to the Git root"
|
23
|
+
option :releases_enabled, true, "Whether to fetch releases"
|
24
|
+
|
25
|
+
def initialize(app, options_hash = {}, &block)
|
26
|
+
super
|
27
|
+
|
28
|
+
# Grab a reference to self so we can access it deep inside blocks
|
29
|
+
_self = self
|
30
|
+
|
31
|
+
# Use syntax highlighting on fenced code blocks
|
32
|
+
# This is super hacky, but middleman does not let you activate an
|
33
|
+
# extension on "app" outside of the "configure" block.
|
34
|
+
require "middleman-syntax"
|
35
|
+
syntax = Proc.new { activate :syntax }
|
36
|
+
app.configure(:development, &syntax)
|
37
|
+
app.configure(:build, &syntax)
|
38
|
+
|
39
|
+
# Organize assets like Rails
|
40
|
+
app.set :css_dir, "assets/stylesheets"
|
41
|
+
app.set :js_dir, "assets/javascripts"
|
42
|
+
app.set :images_dir, "assets/images"
|
43
|
+
app.set :fonts_dir, "assets/fonts"
|
44
|
+
|
45
|
+
# Make custom assets available
|
46
|
+
assets = Proc.new { sprockets.import_asset "ie-compat.js" }
|
47
|
+
app.configure(:development, &assets)
|
48
|
+
app.configure(:build, &assets)
|
49
|
+
|
50
|
+
# Override the default Markdown settings to use our customer renderer
|
51
|
+
# and the options we want!
|
52
|
+
app.set :markdown_engine, :redcarpet
|
53
|
+
app.set :markdown, Middleman::HashiCorp::RedcarpetHTML::REDCARPET_OPTIONS.merge(
|
54
|
+
renderer: Middleman::HashiCorp::RedcarpetHTML
|
55
|
+
)
|
56
|
+
|
57
|
+
# Set the latest version
|
58
|
+
app.set :latest_version, options.version
|
59
|
+
|
60
|
+
# Do the releases dance
|
61
|
+
app.set :product_versions, _self.product_versions
|
62
|
+
|
63
|
+
app.set :github_slug, options.github_slug
|
64
|
+
app.set :website_root, options.website_root
|
65
|
+
|
66
|
+
# Configure the development-specific environment
|
67
|
+
app.configure :development do
|
68
|
+
# Reload the browser automatically whenever files change
|
69
|
+
require "middleman-livereload"
|
70
|
+
activate :livereload
|
71
|
+
end
|
72
|
+
|
73
|
+
# Configure the build-specific environment
|
74
|
+
minify_javascript = options.minify_javascript
|
75
|
+
app.configure :build do
|
76
|
+
# Minify CSS on build
|
77
|
+
activate :minify_css
|
78
|
+
|
79
|
+
if minify_javascript
|
80
|
+
# Minify Javascript on build
|
81
|
+
activate :minify_javascript
|
82
|
+
end
|
83
|
+
|
84
|
+
# Minify HTML
|
85
|
+
require "middleman-minify-html"
|
86
|
+
activate :minify_html do |html|
|
87
|
+
html.remove_quotes = false
|
88
|
+
html.remove_script_attributes = false
|
89
|
+
html.remove_multi_spaces = false
|
90
|
+
html.remove_http_protocol = false
|
91
|
+
html.remove_https_protocol = false
|
92
|
+
end
|
93
|
+
|
94
|
+
# Enable cache buster
|
95
|
+
activate :asset_hash
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
helpers do
|
100
|
+
#
|
101
|
+
# Output an image that corresponds to the given operating system using the
|
102
|
+
# vendored image icons.
|
103
|
+
#
|
104
|
+
# @return [String] (html)
|
105
|
+
#
|
106
|
+
def system_icon(name)
|
107
|
+
image_tag("icons/icon_#{name.to_s.downcase}.png")
|
108
|
+
end
|
109
|
+
|
110
|
+
#
|
111
|
+
# The formatted operating system name.
|
112
|
+
#
|
113
|
+
# @return [String]
|
114
|
+
#
|
115
|
+
def pretty_os(os)
|
116
|
+
case os
|
117
|
+
when /darwin/
|
118
|
+
"Mac OS X"
|
119
|
+
when /freebsd/
|
120
|
+
"FreeBSD"
|
121
|
+
when /openbsd/
|
122
|
+
"OpenBSD"
|
123
|
+
when /netbsd/
|
124
|
+
"NetBSD"
|
125
|
+
when /linux/
|
126
|
+
"Linux"
|
127
|
+
when /windows/
|
128
|
+
"Windows"
|
129
|
+
else
|
130
|
+
os.capitalize
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
#
|
135
|
+
# The formatted architecture name.
|
136
|
+
#
|
137
|
+
# @return [String]
|
138
|
+
#
|
139
|
+
def pretty_arch(arch)
|
140
|
+
case arch
|
141
|
+
when /all/
|
142
|
+
"Universal (32 and 64-bit)"
|
143
|
+
when /686/, /386/
|
144
|
+
"32-bit"
|
145
|
+
when /86_64/, /amd64/
|
146
|
+
"64-bit"
|
147
|
+
else
|
148
|
+
parts = arch.split("_")
|
149
|
+
|
150
|
+
if parts.empty?
|
151
|
+
raise "Could not determine pretty arch `#{arch}'!"
|
152
|
+
end
|
153
|
+
|
154
|
+
parts.last.capitalize
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
#
|
159
|
+
# Calculate the architecture for the given filename (from Bintray).
|
160
|
+
#
|
161
|
+
# @return [String]
|
162
|
+
#
|
163
|
+
def arch_for_filename(path)
|
164
|
+
file = File.basename(path, File.extname(path))
|
165
|
+
|
166
|
+
case file
|
167
|
+
when /686/, /386/
|
168
|
+
"32-bit"
|
169
|
+
when /86_64/, /amd64/
|
170
|
+
"64-bit"
|
171
|
+
else
|
172
|
+
parts = file.split("_")
|
173
|
+
|
174
|
+
if parts.empty?
|
175
|
+
raise "Could not determine arch for filename `#{file}'!"
|
176
|
+
end
|
177
|
+
|
178
|
+
parts.last.capitalize
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
#
|
183
|
+
# Return the GitHub URL associated with the project
|
184
|
+
# @return [String] the project's URL on GitHub
|
185
|
+
# @return [false] if github_slug hasn't been set
|
186
|
+
#
|
187
|
+
def github_url(specificity = :repo)
|
188
|
+
return false if github_slug.nil?
|
189
|
+
base_url = "https://github.com/#{github_slug}"
|
190
|
+
if specificity == :repo
|
191
|
+
base_url
|
192
|
+
elsif specificity == :current_page
|
193
|
+
base_url + "/blob/master/" + path_in_repository(current_page)
|
194
|
+
end
|
195
|
+
end
|
196
|
+
|
197
|
+
#
|
198
|
+
# Return a resource's path relative to its source repo's root directory.
|
199
|
+
# @param page [Middleman::Sitemap::Resource] a sitemap resource object
|
200
|
+
# @return [String] a resource's path relative to its source repo's root
|
201
|
+
# directory
|
202
|
+
#
|
203
|
+
def path_in_repository(resource)
|
204
|
+
relative_path = resource.path.match(/.*\//).to_s
|
205
|
+
file = resource.source_file.split("/").last
|
206
|
+
website_root + "/source/" + relative_path + file
|
207
|
+
end
|
208
|
+
end
|
209
|
+
|
210
|
+
#
|
211
|
+
# Query the Bintray API to get the real product download versions.
|
212
|
+
#
|
213
|
+
# @return [Hash]
|
214
|
+
#
|
215
|
+
def product_versions
|
216
|
+
if !options.bintray_enabled && !options.releases_enabled
|
217
|
+
return {
|
218
|
+
"HashiOS" => {
|
219
|
+
"amd64" => "/0.1.0_hashios_amd64.zip",
|
220
|
+
"i386" => "/0.1.0_hashios_i386.zip",
|
221
|
+
}
|
222
|
+
}
|
223
|
+
end
|
224
|
+
|
225
|
+
if options.bintray_repo
|
226
|
+
Middleman::HashiCorp::BintrayAPI.new(
|
227
|
+
repo: options.bintray_repo,
|
228
|
+
user: options.bintray_user,
|
229
|
+
key: options.bintray_key,
|
230
|
+
filter: options.bintray_exclude_proc,
|
231
|
+
prefixed: options.bintray_prefixed,
|
232
|
+
).downloads_for_version(options.version)
|
233
|
+
else
|
234
|
+
Middleman::HashiCorp::Releases.fetch(options.name, options.version)
|
235
|
+
end
|
236
|
+
end
|
237
|
+
end
|
@@ -0,0 +1,134 @@
|
|
1
|
+
require "middleman-core"
|
2
|
+
require "middleman-core/renderers/redcarpet"
|
3
|
+
require "active_support/core_ext/module/attribute_accessors"
|
4
|
+
|
5
|
+
# Our custom Markdown parser - extends middleman's customer parser so we pick up
|
6
|
+
# all the magic.
|
7
|
+
class Middleman::HashiCorp::RedcarpetHTML < ::Middleman::Renderers::MiddlemanRedcarpetHTML
|
8
|
+
# Custom RedCarpet options.
|
9
|
+
REDCARPET_OPTIONS = {
|
10
|
+
autolink: true,
|
11
|
+
fenced_code_blocks: true,
|
12
|
+
tables: true,
|
13
|
+
no_intra_emphasis: true,
|
14
|
+
with_toc_data: true,
|
15
|
+
xhtml: true,
|
16
|
+
strikethrough: true,
|
17
|
+
superscript: true,
|
18
|
+
}.freeze
|
19
|
+
|
20
|
+
def initialize(options = {})
|
21
|
+
super(options.merge(REDCARPET_OPTIONS))
|
22
|
+
end
|
23
|
+
|
24
|
+
#
|
25
|
+
# Override list_item to automatically add links for documentation
|
26
|
+
#
|
27
|
+
# @param [String] text
|
28
|
+
# @param [String] list_type
|
29
|
+
#
|
30
|
+
def list_item(text, list_type)
|
31
|
+
md = text.match(/(<code>(.+?)<\/code>)/)
|
32
|
+
linked = !text.match(/^(<p>)?<a(.+?)>(.+?)<\/a>\s*?[-:]?/).nil?
|
33
|
+
|
34
|
+
if !md.nil? && !linked
|
35
|
+
container, name = md.captures
|
36
|
+
anchor = anchor_for(name)
|
37
|
+
|
38
|
+
replace = %|<a name="#{anchor}" /><a href="##{anchor}">#{container}</a>|
|
39
|
+
text.sub!(container, replace)
|
40
|
+
end
|
41
|
+
|
42
|
+
"<li>#{text}</li>\n"
|
43
|
+
end
|
44
|
+
|
45
|
+
#
|
46
|
+
# Override block_html to support parsing nested markdown blocks.
|
47
|
+
#
|
48
|
+
# @param [String] raw
|
49
|
+
#
|
50
|
+
def block_html(raw)
|
51
|
+
raw = unindent(raw)
|
52
|
+
|
53
|
+
if md = raw.match(/\<(.+?)\>(.*)\<(\/.+?)\>/m)
|
54
|
+
open_tag, content, close_tag = md.captures
|
55
|
+
"<#{open_tag}>\n#{recursive_render(unindent(content))}<#{close_tag}>"
|
56
|
+
else
|
57
|
+
raw
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
#
|
62
|
+
# Override paragraph to support custom alerts.
|
63
|
+
#
|
64
|
+
# @param [String] text
|
65
|
+
# @return [String]
|
66
|
+
#
|
67
|
+
def paragraph(text)
|
68
|
+
add_alerts("<p>#{text.strip}</p>\n")
|
69
|
+
end
|
70
|
+
|
71
|
+
private
|
72
|
+
|
73
|
+
#
|
74
|
+
# Remove any special characters from the anchor name.
|
75
|
+
#
|
76
|
+
# @example
|
77
|
+
# anchor_for("this") #=> "this"
|
78
|
+
# anchor_for("this is cool") #=> "this_is_cool"
|
79
|
+
# anchor_for("this__is__cool!") #=> "this__is__cool_"
|
80
|
+
#
|
81
|
+
#
|
82
|
+
# @param [String] text
|
83
|
+
# @return [String]
|
84
|
+
#
|
85
|
+
def anchor_for(text)
|
86
|
+
text.gsub(/[^[:word:]]/, "_").squeeze("_")
|
87
|
+
end
|
88
|
+
|
89
|
+
#
|
90
|
+
# This is jank, but Redcarpet does not provide a way to access the
|
91
|
+
# renderer from inside Redcarpet::Markdown. Since we know who we are, we
|
92
|
+
# can cheat a bit.
|
93
|
+
#
|
94
|
+
# @param [String] markdown
|
95
|
+
# @return [String]
|
96
|
+
#
|
97
|
+
def recursive_render(markdown)
|
98
|
+
Redcarpet::Markdown.new(self.class, REDCARPET_OPTIONS).render(markdown)
|
99
|
+
end
|
100
|
+
|
101
|
+
#
|
102
|
+
# Add alert text to the given markdown.
|
103
|
+
#
|
104
|
+
# @param [String] text
|
105
|
+
# @return [String]
|
106
|
+
#
|
107
|
+
def add_alerts(text)
|
108
|
+
map = {
|
109
|
+
"=>" => "success",
|
110
|
+
"->" => "info",
|
111
|
+
"~>" => "warning",
|
112
|
+
"!>" => "danger",
|
113
|
+
}
|
114
|
+
|
115
|
+
regexp = map.map { |k, _| Regexp.escape(k) }.join("|")
|
116
|
+
|
117
|
+
if md = text.match(/^<p>(#{regexp})/)
|
118
|
+
key = md.captures[0]
|
119
|
+
klass = map[key]
|
120
|
+
text.gsub!(/#{Regexp.escape(key)}\s+?/, "")
|
121
|
+
|
122
|
+
return <<-EOH.gsub(/^ {8}/, "")
|
123
|
+
<div class="alert alert-#{klass}" role="alert">
|
124
|
+
#{text}</div>
|
125
|
+
EOH
|
126
|
+
else
|
127
|
+
return text
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
def unindent(string)
|
132
|
+
string.gsub(/^#{string.scan(/^[[:blank:]]+/).min_by { |l| l.length }}/, "")
|
133
|
+
end
|
134
|
+
end
|