guide: Start of HCL usage guide
This is guide-style documentation to introduce the different parts of HCL, as a complement to the reference documentation provided in godoc.
This commit is contained in:
parent
d754d5a269
commit
c6f6feed76
2
guide/.gitignore
vendored
Normal file
2
guide/.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
env/*
|
||||||
|
_build/*
|
20
guide/Makefile
Normal file
20
guide/Makefile
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
# Minimal makefile for Sphinx documentation
|
||||||
|
#
|
||||||
|
|
||||||
|
# You can set these variables from the command line.
|
||||||
|
SPHINXOPTS =
|
||||||
|
SPHINXBUILD = sphinx-build
|
||||||
|
SPHINXPROJ = HCL
|
||||||
|
SOURCEDIR = .
|
||||||
|
BUILDDIR = _build
|
||||||
|
|
||||||
|
# Put it first so that "make" without argument is like "make help".
|
||||||
|
help:
|
||||||
|
@$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
|
||||||
|
|
||||||
|
.PHONY: help Makefile
|
||||||
|
|
||||||
|
# Catch-all target: route all unknown targets to Sphinx using the new
|
||||||
|
# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
|
||||||
|
%: Makefile
|
||||||
|
@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
|
164
guide/conf.py
Normal file
164
guide/conf.py
Normal file
@ -0,0 +1,164 @@
|
|||||||
|
import subprocess
|
||||||
|
import os.path
|
||||||
|
|
||||||
|
# -- Project information -----------------------------------------------------
|
||||||
|
|
||||||
|
project = u'HCL'
|
||||||
|
copyright = u'2018, HashiCorp'
|
||||||
|
author = u'HashiCorp'
|
||||||
|
|
||||||
|
git_version = subprocess.check_output(['git', 'describe', '--always']).strip()
|
||||||
|
|
||||||
|
# The short X.Y version
|
||||||
|
version = unicode(git_version)
|
||||||
|
# The full version, including alpha/beta/rc tags
|
||||||
|
release = unicode(git_version)
|
||||||
|
|
||||||
|
|
||||||
|
# -- General configuration ---------------------------------------------------
|
||||||
|
|
||||||
|
# If your documentation needs a minimal Sphinx version, state it here.
|
||||||
|
#
|
||||||
|
# needs_sphinx = '1.0'
|
||||||
|
|
||||||
|
# Add any Sphinx extension module names here, as strings. They can be
|
||||||
|
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
|
||||||
|
# ones.
|
||||||
|
extensions = [
|
||||||
|
'sphinx.ext.todo',
|
||||||
|
'sphinx.ext.githubpages',
|
||||||
|
'sphinxcontrib.golangdomain',
|
||||||
|
'sphinx.ext.autodoc',
|
||||||
|
'autoapi.extension',
|
||||||
|
]
|
||||||
|
|
||||||
|
# Add any paths that contain templates here, relative to this directory.
|
||||||
|
templates_path = ['_templates']
|
||||||
|
|
||||||
|
# The suffix(es) of source filenames.
|
||||||
|
# You can specify multiple suffix as a list of string:
|
||||||
|
#
|
||||||
|
# source_suffix = ['.rst', '.md']
|
||||||
|
source_suffix = '.rst'
|
||||||
|
|
||||||
|
# The master toctree document.
|
||||||
|
master_doc = 'index'
|
||||||
|
|
||||||
|
# The language for content autogenerated by Sphinx. Refer to documentation
|
||||||
|
# for a list of supported languages.
|
||||||
|
#
|
||||||
|
# This is also used if you do content translation via gettext catalogs.
|
||||||
|
# Usually you set "language" from the command line for these cases.
|
||||||
|
language = None
|
||||||
|
|
||||||
|
# List of patterns, relative to source directory, that match files and
|
||||||
|
# directories to ignore when looking for source files.
|
||||||
|
# This pattern also affects html_static_path and html_extra_path .
|
||||||
|
exclude_patterns = [u'_build', 'Thumbs.db', '.DS_Store', 'env']
|
||||||
|
|
||||||
|
# The name of the Pygments (syntax highlighting) style to use.
|
||||||
|
pygments_style = 'sphinx'
|
||||||
|
|
||||||
|
|
||||||
|
# -- Options for HTML output -------------------------------------------------
|
||||||
|
|
||||||
|
# The theme to use for HTML and HTML Help pages. See the documentation for
|
||||||
|
# a list of builtin themes.
|
||||||
|
#
|
||||||
|
html_theme = 'alabaster'
|
||||||
|
|
||||||
|
# Theme options are theme-specific and customize the look and feel of a theme
|
||||||
|
# further. For a list of options available for each theme, see the
|
||||||
|
# documentation.
|
||||||
|
#
|
||||||
|
# html_theme_options = {}
|
||||||
|
|
||||||
|
# Add any paths that contain custom static files (such as style sheets) here,
|
||||||
|
# relative to this directory. They are copied after the builtin static files,
|
||||||
|
# so a file named "default.css" will overwrite the builtin "default.css".
|
||||||
|
html_static_path = ['_static']
|
||||||
|
|
||||||
|
# Custom sidebar templates, must be a dictionary that maps document names
|
||||||
|
# to template names.
|
||||||
|
#
|
||||||
|
# The default sidebars (for documents that don't match any pattern) are
|
||||||
|
# defined by theme itself. Builtin themes are using these templates by
|
||||||
|
# default: ``['localtoc.html', 'relations.html', 'sourcelink.html',
|
||||||
|
# 'searchbox.html']``.
|
||||||
|
#
|
||||||
|
# html_sidebars = {}
|
||||||
|
|
||||||
|
|
||||||
|
# -- Options for HTMLHelp output ---------------------------------------------
|
||||||
|
|
||||||
|
# Output file base name for HTML help builder.
|
||||||
|
htmlhelp_basename = 'HCLdoc'
|
||||||
|
|
||||||
|
|
||||||
|
# -- Options for LaTeX output ------------------------------------------------
|
||||||
|
|
||||||
|
latex_elements = {
|
||||||
|
# The paper size ('letterpaper' or 'a4paper').
|
||||||
|
#
|
||||||
|
# 'papersize': 'letterpaper',
|
||||||
|
|
||||||
|
# The font size ('10pt', '11pt' or '12pt').
|
||||||
|
#
|
||||||
|
# 'pointsize': '10pt',
|
||||||
|
|
||||||
|
# Additional stuff for the LaTeX preamble.
|
||||||
|
#
|
||||||
|
# 'preamble': '',
|
||||||
|
|
||||||
|
# Latex figure (float) alignment
|
||||||
|
#
|
||||||
|
# 'figure_align': 'htbp',
|
||||||
|
}
|
||||||
|
|
||||||
|
# Grouping the document tree into LaTeX files. List of tuples
|
||||||
|
# (source start file, target name, title,
|
||||||
|
# author, documentclass [howto, manual, or own class]).
|
||||||
|
latex_documents = [
|
||||||
|
(master_doc, 'HCL.tex', u'HCL Documentation',
|
||||||
|
u'HashiCorp', 'manual'),
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
# -- Options for manual page output ------------------------------------------
|
||||||
|
|
||||||
|
# One entry per manual page. List of tuples
|
||||||
|
# (source start file, name, description, authors, manual section).
|
||||||
|
man_pages = [
|
||||||
|
(master_doc, 'hcl', u'HCL Documentation',
|
||||||
|
[author], 1)
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
# -- Options for Texinfo output ----------------------------------------------
|
||||||
|
|
||||||
|
# Grouping the document tree into Texinfo files. List of tuples
|
||||||
|
# (source start file, target name, title, author,
|
||||||
|
# dir menu entry, description, category)
|
||||||
|
texinfo_documents = [
|
||||||
|
(master_doc, 'HCL', u'HCL Documentation',
|
||||||
|
author, 'HCL', 'One line description of project.',
|
||||||
|
'Miscellaneous'),
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
# -- Extension configuration -------------------------------------------------
|
||||||
|
|
||||||
|
# -- Options for todo extension ----------------------------------------------
|
||||||
|
|
||||||
|
# If true, `todo` and `todoList` produce output, else they produce nothing.
|
||||||
|
todo_include_todos = True
|
||||||
|
|
||||||
|
autoapi_type = 'go'
|
||||||
|
autoapi_dirs = [
|
||||||
|
os.path.join(os.path.dirname(__file__), '..', x)
|
||||||
|
for x in ['gohcl', 'hcl', 'hcldec', 'hcled', 'hclparse', 'hcltest', 'hclwrite']
|
||||||
|
]
|
||||||
|
autoapi_root = 'api'
|
||||||
|
autoapi_add_toctree_entry = False
|
||||||
|
autoapi_keep_files = True
|
||||||
|
autoapi_generate_api_docs = False
|
27
guide/go.rst
Normal file
27
guide/go.rst
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
Using HCL in a Go application
|
||||||
|
=============================
|
||||||
|
|
||||||
|
HCL is itself written in Go_ and currently it is primarily intended for use as
|
||||||
|
a library within other Go programs.
|
||||||
|
|
||||||
|
This section describes a number of different ways HCL can be used to define
|
||||||
|
and process a configuration language within a Go program. For simple situations,
|
||||||
|
HCL can decode directly into Go ``struct`` values in a similar way as encoding
|
||||||
|
packages such as ``encoding/json`` and ``encoding/xml``.
|
||||||
|
|
||||||
|
The HCL Go API also offers some alternative approaches however, for processing
|
||||||
|
languages that may be more complex or that include portions whose expected
|
||||||
|
structure cannot be determined until runtime.
|
||||||
|
|
||||||
|
The following sections give an overview of different ways HCL can be used in
|
||||||
|
a Go program.
|
||||||
|
|
||||||
|
.. toctree::
|
||||||
|
:maxdepth: 1
|
||||||
|
:caption: Sub-sections:
|
||||||
|
|
||||||
|
go_parsing
|
||||||
|
go_diagnostics
|
||||||
|
go_decoding_gohcl
|
||||||
|
|
||||||
|
.. _Go: https://golang.org/
|
126
guide/go_decoding_gohcl.rst
Normal file
126
guide/go_decoding_gohcl.rst
Normal file
@ -0,0 +1,126 @@
|
|||||||
|
.. go:package:: gohcl
|
||||||
|
|
||||||
|
Decoding Into Native Go Values
|
||||||
|
==============================
|
||||||
|
|
||||||
|
The most straightforward way to access the content of an HCL file is to
|
||||||
|
decode into native Go values using ``reflect``, similar to the technique used
|
||||||
|
by packages like ``encoding/json`` and ``encoding/xml``.
|
||||||
|
|
||||||
|
Package ``gohcl`` provides functions for this sort of decoding. Function
|
||||||
|
``DecodeBody`` attempts to extract values from an HCL *body* and write them
|
||||||
|
into a Go value given as a pointer:
|
||||||
|
|
||||||
|
.. code-block:: go
|
||||||
|
|
||||||
|
type ServiceConfig struct {
|
||||||
|
Type string `hcl:"type,label"`
|
||||||
|
Name string `hcl:"name,label"`
|
||||||
|
ListenAddr string `hcl:"listen_addr"`
|
||||||
|
}
|
||||||
|
type Config struct {
|
||||||
|
IOMode string `hcl:"io_mode"`
|
||||||
|
Services []ServiceConfig `hcl:"service,block"`
|
||||||
|
}
|
||||||
|
|
||||||
|
var c Config
|
||||||
|
moreDiags := gohcl.DecodeBody(f.Body, nil, &c)
|
||||||
|
diags = append(diags, moreDiags...)
|
||||||
|
|
||||||
|
The above example decodes the *root body* of a file ``f``, presumably loaded
|
||||||
|
previously using a parser, into the variable ``c``. The field labels within
|
||||||
|
the struct types imply the schema of the expected language, which is a cut-down
|
||||||
|
version of the hypothetical language we showed in :ref:`intro`.
|
||||||
|
|
||||||
|
The struct field labels consist of two comma-separated values. The first is
|
||||||
|
the name of the corresponding argument or block type as it will appear in
|
||||||
|
the input file, and the second is the type of element being named. If the
|
||||||
|
second value is omitted, it defaults to ``attr``, requesting an attribute.
|
||||||
|
|
||||||
|
Nested blocks are represented by a struct or a slice of that struct, and the
|
||||||
|
special element type ``label`` within that struct declares that each instance
|
||||||
|
of that block type must be followed by one or more block labels. In the above
|
||||||
|
example, the ``service`` block type is defined to require two labels, named
|
||||||
|
``type`` and ``name``. For label fields in particular, the given name is used
|
||||||
|
only to refer to the particular label in error messages when the wrong number
|
||||||
|
of labels is used.
|
||||||
|
|
||||||
|
By default, all declared attributes and blocks are considered to be required.
|
||||||
|
An optional value is indicated by making its field have a pointer type, in
|
||||||
|
which case ``nil`` is written to indicate the absense of the argument.
|
||||||
|
|
||||||
|
The sections below discuss some additional decoding use-cases. For full details
|
||||||
|
on the `gohcl` package, see
|
||||||
|
`the godoc reference <https://godoc.org/github.com/hashicorp/hcl2/gohcl>`_.
|
||||||
|
|
||||||
|
Variables and Functions
|
||||||
|
-----------------------
|
||||||
|
|
||||||
|
By default, arguments given in the configuration may use only literal values
|
||||||
|
and the built in expression language operators, such as arithmetic.
|
||||||
|
|
||||||
|
The second argument to ``gohcl.DecodeBody``, shown as ``nil`` in the previous
|
||||||
|
example, allows the calling application to additionally offer variables and
|
||||||
|
functions for use in expressions. Its value is a pointer to an
|
||||||
|
``hcl.EvalContext``, which will be covered in more detail in the later section
|
||||||
|
:ref:`expression-eval`. For now, a simple example of making the id of the
|
||||||
|
current process available as a single variable called ``pid``:
|
||||||
|
|
||||||
|
.. code-block:: go
|
||||||
|
|
||||||
|
type Context struct {
|
||||||
|
Pid string
|
||||||
|
}
|
||||||
|
ctx := gohcl.EvalContext(&Context{
|
||||||
|
Pid: os.Getpid()
|
||||||
|
})
|
||||||
|
var c Config
|
||||||
|
moreDiags := gohcl.DecodeBody(f.Body, ctx, &c)
|
||||||
|
diags = append(diags, moreDiags...)
|
||||||
|
|
||||||
|
``gohcl.EvalContext`` constructs an expression evaluation context from a Go
|
||||||
|
struct value, making the fields available as variables and the methods
|
||||||
|
available as functions, after transforming the field and method names such
|
||||||
|
that each word (starting with an uppercase letter) is all lowercase and
|
||||||
|
separated by underscores.
|
||||||
|
|
||||||
|
.. code-block:: hcl
|
||||||
|
|
||||||
|
name = "example-program (${pid})"
|
||||||
|
|
||||||
|
Partial Decoding
|
||||||
|
----------------
|
||||||
|
|
||||||
|
In the examples so far, we've extracted the content from the entire input file
|
||||||
|
in a single call to ``DecodeBody``. This is sufficient for many simple
|
||||||
|
situations, but sometimes different parts of the file must be evaluated
|
||||||
|
separately. For example:
|
||||||
|
|
||||||
|
* If different parts of the file must be evaluated with different variables
|
||||||
|
or functions available.
|
||||||
|
|
||||||
|
* If the result of evaluating one part of the file is used to set variables
|
||||||
|
or functions in another part of the file.
|
||||||
|
|
||||||
|
There are several ways to perform partial decoding with ``gohcl``, all of
|
||||||
|
which involve decoding into HCL's own types, such as ``hcl.Body``.
|
||||||
|
|
||||||
|
The most general approach is to declare an additional struct field of type
|
||||||
|
``hcl.Body``, with the special field tag type ``remain``:
|
||||||
|
|
||||||
|
.. code-block:: go
|
||||||
|
|
||||||
|
type ServiceConfig struct {
|
||||||
|
Type string `hcl:"type,label"`
|
||||||
|
Name string `hcl:"name,label"`
|
||||||
|
ListenAddr string `hcl:"listen_addr"`
|
||||||
|
Remain hcl.Body `hcl:",remain"`
|
||||||
|
}
|
||||||
|
|
||||||
|
When a ``remain`` field is present, any element of the input body that is
|
||||||
|
not matched is retained in a body saved into that field, which can then be
|
||||||
|
decoded in a later call, potentially with a different evaluation context.
|
||||||
|
|
||||||
|
Another option is to decode an attribute into a value of type `hcl.Expression`,
|
||||||
|
which can then be evaluated separately as described in
|
||||||
|
:ref:`expression-eval`.
|
97
guide/go_diagnostics.rst
Normal file
97
guide/go_diagnostics.rst
Normal file
@ -0,0 +1,97 @@
|
|||||||
|
.. _go-diagnostics:
|
||||||
|
|
||||||
|
Diagnostic Messages
|
||||||
|
===================
|
||||||
|
|
||||||
|
An important concern for any machine language intended for human authoring is
|
||||||
|
to produce good error messages when the input is somehow invalid, or has
|
||||||
|
other problems.
|
||||||
|
|
||||||
|
HCL uses *diagnostics* to describe problems in an end-user-oriented manner,
|
||||||
|
such that the calling application can render helpful error or warning messages.
|
||||||
|
The word "diagnostic" is a general term that covers both errors and warnings,
|
||||||
|
where errors are problems that prevent complete processing while warnings are
|
||||||
|
possible concerns that do not block processing.
|
||||||
|
|
||||||
|
HCL deviates from usual Go API practice by returning its own ``hcl.Diagnostics``
|
||||||
|
type, instead of Go's own ``error`` type. This allows functions to return
|
||||||
|
warnings without accompanying errors while not violating the usual expectation
|
||||||
|
that the absense of errors is indicated by a nil ``error``.
|
||||||
|
|
||||||
|
In order to easily accumulate and return multiple diagnostics at once, the
|
||||||
|
usual pattern for functions returning diagnostics is to gather them in a
|
||||||
|
local variable and then return it at the end of the function, or possibly
|
||||||
|
earlier if the function cannot continue due to the problems.
|
||||||
|
|
||||||
|
.. code-block:: go
|
||||||
|
|
||||||
|
func returningDiagnosticsExample() hcl.Diagnostics {
|
||||||
|
var diags hcl.Diagnostics
|
||||||
|
|
||||||
|
// ...
|
||||||
|
|
||||||
|
// Call a function that may itself produce diagnostics.
|
||||||
|
f, moreDiags := parser.LoadHCLFile("example.conf")
|
||||||
|
// always append, in case warnings are present
|
||||||
|
diags = append(diags, moreDiags...)
|
||||||
|
if diags.HasErrors() {
|
||||||
|
// If we can't safely continue in the presence of errors here, we
|
||||||
|
// can optionally return early.
|
||||||
|
return diags
|
||||||
|
}
|
||||||
|
|
||||||
|
// ...
|
||||||
|
|
||||||
|
return diags
|
||||||
|
}
|
||||||
|
|
||||||
|
A common variant of the above pattern is calling another diagnostics-generating
|
||||||
|
function in a loop, using ``continue`` to begin the next iteration when errors
|
||||||
|
are detected, but still completing all iterations and returning the union of
|
||||||
|
all of the problems encountered along the way.
|
||||||
|
|
||||||
|
In :ref:`go-parsing`, we saw that the parser can generate diagnostics which
|
||||||
|
are related to syntax problems within the loaded file. Further steps to decode
|
||||||
|
content from the loaded file can also generate diagnostics related to *semantic*
|
||||||
|
problems within the file, such as invalid expressions or type mismatches, and
|
||||||
|
so a program using HCL will generally need to accumulate diagnostics across
|
||||||
|
these various steps and then render them in the application UI somehow.
|
||||||
|
|
||||||
|
Rendering Diagnostics in the UI
|
||||||
|
-------------------------------
|
||||||
|
|
||||||
|
The best way to render diagnostics to an end-user will depend a lot on the
|
||||||
|
type of application: they might be printed into a terminal, written into a
|
||||||
|
log for later review, or even shown in a GUI.
|
||||||
|
|
||||||
|
HCL leaves the responsibility for rendering diagnostics to the calling
|
||||||
|
application, but since rendering to a terminal is a common case for command-line
|
||||||
|
tools, the `hcl` package contains a default implementation of this in the
|
||||||
|
form of a "diagnostic text writer":
|
||||||
|
|
||||||
|
.. code-block:: go
|
||||||
|
|
||||||
|
wr := hcl.NewDiagnosticTextWriter(
|
||||||
|
os.Stdout, // writer to send messages to
|
||||||
|
parser.Files(), // the parser's file cache, for source snippets
|
||||||
|
78, // wrapping width
|
||||||
|
true, // generate colored/highlighted output
|
||||||
|
)
|
||||||
|
wr.WriteDiagnostics(diags)
|
||||||
|
|
||||||
|
This default implementation of diagnostic rendering includes relevant lines
|
||||||
|
of source code for context, like this:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
Error: Unsupported block type
|
||||||
|
|
||||||
|
on example.tf line 4, in resource "aws_instance" "example":
|
||||||
|
2: provisionr "local-exec" {
|
||||||
|
|
||||||
|
Blocks of type "provisionr" are not expected here. Did you mean "provisioner"?
|
||||||
|
|
||||||
|
If the "color" flag is enabled, the severity will be additionally indicated by
|
||||||
|
a text color and the relevant portion of the source code snippet will be
|
||||||
|
underlined to draw further attention.
|
||||||
|
|
64
guide/go_parsing.rst
Normal file
64
guide/go_parsing.rst
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
.. _go-parsing:
|
||||||
|
|
||||||
|
Parsing HCL Input
|
||||||
|
=================
|
||||||
|
|
||||||
|
The first step in processing HCL input provided by a user is to parse it.
|
||||||
|
Parsing turns the raw bytes from an input file into a higher-level
|
||||||
|
representation of the arguments and blocks, ready to be *decoded* into an
|
||||||
|
application-specific form.
|
||||||
|
|
||||||
|
The main entry point into HCL parsing is :go:pkg:`hclparse`, which provides
|
||||||
|
:go:type:`hclparse.Parser`:
|
||||||
|
|
||||||
|
.. code-block:: go
|
||||||
|
|
||||||
|
parser := hclparse.NewParser()
|
||||||
|
f, diags := parser.ParseHCLFile("server.conf")
|
||||||
|
|
||||||
|
Variable ``f`` is then a pointer to an :go:type:`hcl.File`, which is an
|
||||||
|
opaque abstract representation of the file, ready to be decoded.
|
||||||
|
|
||||||
|
Variable ``diags`` describes any errors or warnings that were encountered
|
||||||
|
during processing; HCL conventionally uses this in place of the usual ``error``
|
||||||
|
return value in Go, to allow returning a mixture of multiple errors and
|
||||||
|
warnings together with enough information to present good error messages to the
|
||||||
|
user. We'll cover this in more detail in the next section,
|
||||||
|
:ref:`go-diagnostics`.
|
||||||
|
|
||||||
|
.. go:package:: hclparse
|
||||||
|
|
||||||
|
Package ``hclparse``
|
||||||
|
--------------------
|
||||||
|
|
||||||
|
.. go:type:: Parser
|
||||||
|
|
||||||
|
.. go:function:: func NewParser() *Parser
|
||||||
|
|
||||||
|
Constructs a new parser object. Each parser contains a cache of files
|
||||||
|
that have already been read, so repeated calls to load the same file
|
||||||
|
will return the same object.
|
||||||
|
|
||||||
|
.. go:function:: func (*Parser) ParseHCL(src []byte, filename string) (*hcl.File, hcl.Diagnostics)
|
||||||
|
|
||||||
|
Parse the given source code as HCL native syntax, saving the result into
|
||||||
|
the parser's file cache under the given filename.
|
||||||
|
|
||||||
|
.. go:function:: func (*Parser) ParseHCLFile(filename string) (*hcl.File, hcl.Diagnostics)
|
||||||
|
|
||||||
|
Parse the contents of the given file as HCL native syntax. This is a
|
||||||
|
convenience wrapper around ParseHCL that first reads the file into memory.
|
||||||
|
|
||||||
|
.. go:function:: func (*Parser) ParseJSON(src []byte, filename string) (*hcl.File, hcl.Diagnostics)
|
||||||
|
|
||||||
|
Parse the given source code as JSON syntax, saving the result into
|
||||||
|
the parser's file cache under the given filename.
|
||||||
|
|
||||||
|
.. go:function:: func (*Parser) ParseJSONFile(filename string) (*hcl.File, hcl.Diagnostics)
|
||||||
|
|
||||||
|
Parse the contents of the given file as JSON syntax. This is a
|
||||||
|
convenience wrapper around ParseJSON that first reads the file into memory.
|
||||||
|
|
||||||
|
The above list just highlights the main functions in this package.
|
||||||
|
For full documentation, see
|
||||||
|
`the hclparse godoc <https://godoc.org/github.com/hashicorp/hcl2/hclparse>`_.
|
34
guide/index.rst
Normal file
34
guide/index.rst
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
HCL Configuration Language
|
||||||
|
==========================
|
||||||
|
|
||||||
|
HCL is a toolkit for creating structured configuration languages that are both
|
||||||
|
human- and machine-friendly, for use with command-line tools, servers, etc.
|
||||||
|
|
||||||
|
HCL has both a native syntax, intended to be pleasant to read and write for
|
||||||
|
humans, and a JSON-based variant that is easier for machines to generate and
|
||||||
|
parse. The native syntax is inspired by libucl_, `nginx configuration`_, and
|
||||||
|
others.
|
||||||
|
|
||||||
|
It includes an expression syntax that allows basic inline computation and, with
|
||||||
|
support from the calling application, use of variables and functions for more
|
||||||
|
dynamic configuration languages.
|
||||||
|
|
||||||
|
HCL provides a set of constructs that can be used by a calling application to
|
||||||
|
construct a configuration language. The application defines which argument
|
||||||
|
names and nested block types are expected, and HCL parses the configuration
|
||||||
|
file, verifies that it conforms to the expected structure, and returns
|
||||||
|
high-level objects that the application can use for further processing.
|
||||||
|
|
||||||
|
At present, HCL is primarily intended for use in applications written in Go_,
|
||||||
|
via its library API.
|
||||||
|
|
||||||
|
.. toctree::
|
||||||
|
:maxdepth: 1
|
||||||
|
:caption: Contents:
|
||||||
|
|
||||||
|
intro
|
||||||
|
go
|
||||||
|
|
||||||
|
.. _libucl: https://github.com/vstakhov/libucl
|
||||||
|
.. _`nginx configuration`: http://nginx.org/en/docs/beginners_guide.html#conf_structure
|
||||||
|
.. _Go: https://golang.org/
|
108
guide/intro.rst
Normal file
108
guide/intro.rst
Normal file
@ -0,0 +1,108 @@
|
|||||||
|
.. _intro:
|
||||||
|
|
||||||
|
Introduction to HCL
|
||||||
|
===================
|
||||||
|
|
||||||
|
HCL-based configuration is built from two main constructs: arguments and
|
||||||
|
blocks. The following is an example of a configuration language for a
|
||||||
|
hypothetical application:
|
||||||
|
|
||||||
|
.. code-block:: hcl
|
||||||
|
|
||||||
|
io_mode = "async"
|
||||||
|
|
||||||
|
service "http" "web_proxy" {
|
||||||
|
listen_addr = "127.0.0.1:8080"
|
||||||
|
|
||||||
|
process "main" {
|
||||||
|
command = ["/usr/local/bin/awesome-app", "server"]
|
||||||
|
}
|
||||||
|
|
||||||
|
process "mgmt" {
|
||||||
|
command = ["/usr/local/bin/awesome-app", "mgmt"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
In the above example, ``io_mode`` is a top-level argument, while ``service``
|
||||||
|
introduces a block. Within the body of a block, further arguments and nested
|
||||||
|
blocks are allowed. A block type may also expect a number of *labels*, which
|
||||||
|
are the quoted names following the ``service`` keyword in the above example.
|
||||||
|
|
||||||
|
The specific keywords ``io_mode``, ``service``, ``process``, etc here are
|
||||||
|
application-defined. HCL provides the general block structure syntax, and
|
||||||
|
can validate and decode configuration based on the application's provided
|
||||||
|
schema.
|
||||||
|
|
||||||
|
HCL is a structured configuration language rather than a data structure
|
||||||
|
serialization language. This means that unlike languages such as JSON, YAML,
|
||||||
|
or TOML, HCL is always decoded using an application-defined schema.
|
||||||
|
|
||||||
|
However, HCL does have a JSON-based alternative syntax, which allows the same
|
||||||
|
structure above to be generated using a standard JSON serializer when users
|
||||||
|
wish to generate configuration programmatically rather than hand-write it:
|
||||||
|
|
||||||
|
.. code-block:: json
|
||||||
|
|
||||||
|
{
|
||||||
|
"io_mode": "async",
|
||||||
|
"service": {
|
||||||
|
"http": {
|
||||||
|
"web_proxy": {
|
||||||
|
"listen_addr": "127.0.0.1:8080",
|
||||||
|
"process": {
|
||||||
|
"main": {
|
||||||
|
"command": ["/usr/local/bin/awesome-app", "server"]
|
||||||
|
},
|
||||||
|
"mgmt": {
|
||||||
|
"command": ["/usr/local/bin/awesome-app", "mgmt"]
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
The calling application can choose which syntaxes to support. JSON syntax may
|
||||||
|
not be important or desirable for certain applications, but it is available for
|
||||||
|
applications that need it. The schema provided by the calling application
|
||||||
|
allows JSON input to be properly decoded even though JSON syntax is ambiguous
|
||||||
|
in various ways, such as whether a JSON object is representing a nested block
|
||||||
|
or an object expression.
|
||||||
|
|
||||||
|
The collection of arguments and blocks at a particular nesting level is called
|
||||||
|
a *body*. A file always has a root body containing the top-level elements,
|
||||||
|
and each block also has its own body representing the elements within it.
|
||||||
|
|
||||||
|
The term "attribute" can also be used to refer to what we've called an
|
||||||
|
"argument" so far. The term "attribute" is also used for the fields of an
|
||||||
|
object value in argument expressions, and so "argument" is used to refer
|
||||||
|
specifically to the type of attribute that appears directly within a body.
|
||||||
|
|
||||||
|
The above examples show the general "texture" of HCL-based configuration. The
|
||||||
|
full details of the syntax are covered in the language specifications.
|
||||||
|
|
||||||
|
.. todo:: Once the language specification documents have settled into a
|
||||||
|
final location, link them from above.
|
||||||
|
|
||||||
|
Argument Expressions
|
||||||
|
--------------------
|
||||||
|
|
||||||
|
The value of an argument can be a literal value shown above, or it may be an
|
||||||
|
expression to allow arithmetic, deriving one value from another, etc.
|
||||||
|
|
||||||
|
.. code-block:: hcl
|
||||||
|
|
||||||
|
listen_addr = env.LISTEN_ADDR
|
||||||
|
|
||||||
|
Built-in arithmetic and comparison operators are automatically available in all
|
||||||
|
HCL-based configuration languages. A calling application may optionally
|
||||||
|
provide variables that users can reference, like ``env`` in the above example,
|
||||||
|
and custom functions to transform values in application-specific ways.
|
||||||
|
|
||||||
|
Full details of the expression syntax are in the HCL native syntax
|
||||||
|
specification. Since JSON does not have an expression syntax, JSON-based
|
||||||
|
configuration files use the native syntax expression language embedded inside
|
||||||
|
JSON strings.
|
||||||
|
|
||||||
|
.. todo:: Once the language specification documents have settled into a
|
||||||
|
final location, link to the native syntax specification from above.
|
36
guide/make.bat
Normal file
36
guide/make.bat
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
@ECHO OFF
|
||||||
|
|
||||||
|
pushd %~dp0
|
||||||
|
|
||||||
|
REM Command file for Sphinx documentation
|
||||||
|
|
||||||
|
if "%SPHINXBUILD%" == "" (
|
||||||
|
set SPHINXBUILD=sphinx-build
|
||||||
|
)
|
||||||
|
set SOURCEDIR=.
|
||||||
|
set BUILDDIR=_build
|
||||||
|
set SPHINXPROJ=HCL
|
||||||
|
|
||||||
|
if "%1" == "" goto help
|
||||||
|
|
||||||
|
%SPHINXBUILD% >NUL 2>NUL
|
||||||
|
if errorlevel 9009 (
|
||||||
|
echo.
|
||||||
|
echo.The 'sphinx-build' command was not found. Make sure you have Sphinx
|
||||||
|
echo.installed, then set the SPHINXBUILD environment variable to point
|
||||||
|
echo.to the full path of the 'sphinx-build' executable. Alternatively you
|
||||||
|
echo.may add the Sphinx directory to PATH.
|
||||||
|
echo.
|
||||||
|
echo.If you don't have Sphinx installed, grab it from
|
||||||
|
echo.http://sphinx-doc.org/
|
||||||
|
exit /b 1
|
||||||
|
)
|
||||||
|
|
||||||
|
%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS%
|
||||||
|
goto end
|
||||||
|
|
||||||
|
:help
|
||||||
|
%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS%
|
||||||
|
|
||||||
|
:end
|
||||||
|
popd
|
3
guide/requirements.txt
Normal file
3
guide/requirements.txt
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
sphinx
|
||||||
|
sphinxcontrib-golangdomain
|
||||||
|
sphinx-autoapi
|
Loading…
Reference in New Issue
Block a user