View Source SayCheezEx (say_cheez_ex v0.3.6)
This module is used to retrieve assorted pieces of configuration from a release's build environment.
- Which build is this?
- Who built this release?
- When was this built?
- What was the Git SHA for this build?
Usage
Make sure that you capture all elements you need to a module attribute - e.g.
module Foo do
import SayCheezEx, only: [cheez!: 1]
# e.g. "v 0.1.5/d9a87c3 137 on server.local"
@version cheez!("v {:project_version}/{:git_commit_id} {:build_number} on {:build_on}")
...
end
Data gathering must be done at compile time and will simply create a string once and for all that matches your informational need.
This can be done in multiple ways:
- You can call the
cheez!/1
orcheez/1
functions with a format string, as described in their docs - You can call
info/1
andget_env/1
to extract the specific parameters you need.
See info/1
for list of allowed attributes, or all/0
for
a map with all pre-defined attributes.
Graphs
What is better than Elixir's own documentation? adding graphs to it, and having them embedded in your documentation.
To try them, use:
module Foo do
import SayCheezEx, only: [uml: 1, graphviz: 1]
@moduledoc """
Here goes a Graphviz graph:
#{graphviz("digraph { Sup -> GenServ }")}
Here a PlantUML graph:
#{uml("""
Bob -> Alice : I do love UML in documentation
Alice -> Bob : I love it too!
""")}
"""
...
end
See for yourself some examples at:
Graphs are cached under _build/img_cache
so a full
render happens only when they change.
Link to this section Summary
Functions
Dumps a map of all known build/env configuration keys for this environment.
Prints a map of only some elements.
Captures the environment from a definition string.
Captures the environment from a definition string, and prints it out so it is shown in the compile logs.
Creates a date out of an ISO date.
Expands a sequence of tokens into a string.
Given a list of candidates, returs the first that is not unknown.
As the C compiler is formatted differently on Win and Unix, we handle both cases with a related unit test, so we can add (and test) more.
Reads the first env variable that is not empty.
Reads an ISO date from Git.
Runs current Git command.
Runs a local Graphviz command and embeds the resulting SVG.
Reads a hostname.
Gets assorted pieces of system information.
We want to rewrite ELixir module names so we can remove the Elixir prefix.
Runs a command.
When should we print on STDOUT?
Checks whether we should output the results of SayCheezEx on STDOUT.
Tokenizes a string into a list.
Breaks up a list of keywords into tuples.
Runs a command though PlantUml, either local or on-line.
Link to this section Functions
@spec all() :: map()
Dumps a map of all known build/env configuration keys for this environment.
If you want a map of only some elements, see
all/1
.
An example output might be:
%{
build_at: "230411.1528",
build_at_day: "2023-04-11",
build_at_full: "2023-04-11.15:28:47",
build_by: "lenz",
build_number: "87",
build_on: "Lenzs-MacBook-Pro.local",
build_mix_env: "dev",
git_all: "b204919/230411.1509",
git_commit_id: "b204919",
git_commit_id_full: "b2049190312ef810875476398978c2b0387251d3",
git_date: "2023-04-11.15:09:50",
git_date_compact: "230411.1509",
git_last_committer: "Lenz",
project_full_version: "0.2.1/b204919/230411.1509",
project_name: "SayCheezEx",
project_version: "0.2.2",
sysinfo_arch: "aarch64-apple-darwin22.3.0",
sysinfo_beam: "BEAM jit 13.2",
sysinfo_c_compiler: "gnuc 4.2.1",
sysinfo_compat: "25",
sysinfo_driver: "3.3",
sysinfo_nif: "2.16",
sysinfo_ptr: "64bit",
sysinfo_word: "64bit",
system: "1.14.3/OTP25",
system_elixir: "1.14.3",
system_otp: "25",
...
}
but the right place to check all properties and their meaning is info/1
.
@spec all(maybe_improper_list()) :: map()
Prints a map of only some elements.
If you want a map of all elements, see
all/0
.
Captures the environment from a definition string.
Same as cheez!/1
but it does not print the
captured string.
Captures the environment from a definition string, and prints it out so it is shown in the compile logs.
Usage:
> cheez!("v {:project_version}/{:git_commit_id} {:build_number} on {:build_on}")
"v 0.1.5/d9a87c3 137 on server.local"
definition-strings
Definition strings
This function will interpolate attributes set between brackets, with the following rules:
{:project_version}
is an info tag. These is a long list of those - seeall/0
.{$HOST}
is an environment variable - in this case, HOST{=HELLO}
is a default value, in this case the literal string "HELLO"
If multiple attributes are specified in a comma-separated string,
they all are expanded,
and the first one that is defined will be output. So e.g.
{$FOO,$BAR,=BAZ}
will first try to interpolate the variable FOO;
if that is undefined, it will try BAR, and if that too is undefined,
it will output "BAZ" (that is always defined)
As it is quite a common thing to include a module name in the string as it appears in the MODULE attribute, and that will print out the module with an "Elixir" prefix (e.g. module "Foo.Bar" will become "Elixir.Foo.Bar"), the "Elixir" prefix is stripped when found.
controlling-output
Controlling output
In general, on every capture, we would love to print out the current captured variables on STDOUT. This is quite handy for server builds, as in the build log there are the same pieces of information that the build embeds.
This also gets in the way during development and testing, cluttering the output.
So the default is that is printing only happens when building
in the :prod
environment, unless you force it on or off
using the CHEEZ environment variable. So, say....
CHEEZ=1 mix test
Will print captured output (see should_print?/0
for further
details). Of course this only happens when compiling classes,
so when working interactively you may sometimes see the output
and sometimes won't, as the compiler decides what is in
need of being rebuilt.
If you don't want this fuction to print out the captured
environment, just use cheez/1
.
Creates a date out of an ISO date.
We need to do this instead of giving git format options, as date formatting is not supported well by ancient git versions (e.g. Centos7 still has git 1.8).
So we basically break a date of the format 2023-02-15 08:50:19 +0100
into a set of tokens, and reassemble them based on a list of input
tokens or constant strings.
Expands a sequence of tokens into a string.
Given a list of candidates, returs the first that is not unknown.
If all of them are unknown, return the default.
As the C compiler is formatted differently on Win and Unix, we handle both cases with a related unit test, so we can add (and test) more.
@spec get_env(binary() | maybe_improper_list()) :: binary()
Reads the first env variable that is not empty.
Reads an ISO date from Git.
Runs current Git command.
CWD is the root of the repo.
Runs a local Graphviz command and embeds the resulting SVG.
notes
Notes
- Requires GraphViz installed
- You can find full documentation of GraphViz at https://graphviz.org/
- See also
uml/1
.
Reads a hostname.
Gets assorted pieces of system information.
project
Project
- project_name: "SayCheezEx" - the project will be named with an atom
as
:say_cheez_ex
, but we return a camelized string - project_version: "0.1.0-dev",
- project_full_version: "0.1.0-dev/7ea2260/230212.1425",
elixir-erlang
Elixir - Erlang
- system: "1.13.4/OTP25",
- system_elixir: "1.13.4",
- system_otp: "25"
git
Git
- git_all: "7ea2260/230212.1425" - a recap of commit id and date compact
- git_commit_id: "7ea2260" - the short commit-id
- git_commit_id_full: "7ea2260895f35fc46976a2fdbc4d8faeaad09467" - the full commit-id
- git_date: "2023-02-12.14:25:47" - the date if last commit
- git_date_compact: "230212.1425" - the compact date of last commit
- git_last_committer: "Lenz" - the author of last commit
build-information
Build information
- build_at: "230213.1545" - a short date of when the release was built
- build_at_day: "2023-02-13" - the day a release was built
- build_at_full: "2023-02-13.15:45:08" - the exact time a release was built
- build_by: "jenkins" - the user that was running on the build server
- build_on: "intserver03" - the server the release was built on.
First checks
hostname
then the environment variableHOST
build_mix_env
: the mix build environament, as a string (e.g. "dev" or "prod")
jenkins-specific
Jenkins-specific
- build_number: "86" - the value of the
BUILD_NUMBER
attribute
system-environment
System environment
sysinfo_arch
: the system architecture (e.g. "aarch64-apple-darwin22.3.0")sysinfo_beam
: the type of VM, whether it's a JIT or interpreter, and its version (e.g. "BEAM jit 13.2")sysinfo_banner
: the "welcome banner" that the VM prints on startup (e.g. "Erlang/OTP 25 [erts-13.2] [source] [64-bit] [smp:10:10] [ds:10:10:10] [async-threads:1] [jit]")sysinfo_c_compiler
: the system C compiler used to build the VM (e.g. "gnuc 4.2.1")sysinfo_compat
: the Erlang/OTP release that the current emulator has been set to be backward compatible with (e.g. "25")sysinfo_driver
: Erlang driver version used by the runtime system (e.g. "3.3")sysinfo_nif
: version of the Erlang NIF interface (e.g. "2.16")sysinfo_ptr
: the size of Erlang term words in bits (e.g. "64bit")sysinfo_word
: the size of an emulator pointer in bits (e.g. "64bit")
We want to rewrite ELixir module names so we can remove the Elixir prefix.
From
"{:abc,=NONE} Elixir.My.Module {:abc,=NONE}"
To
"{:abc,=NONE} My.Module {:abc,=NONE}"
Runs a command.
Returns the output, only if return code is zero.
Otherwise returns "@unknown_entry"
When should we print on STDOUT?
- in environment
:prod
only (so for final build) - unless environment variable
CHEEZ
is set to 1, that forces printing in all environments - unless environment variable
CHEEZ
is set to 0, that silences printing in all environments
Checks whether we should output the results of SayCheezEx on STDOUT.
In a separate function for ease of testing.
Tokenizes a string into a list.
Breaks up a list of keywords into tuples.
Runs a command though PlantUml, either local or on-line.
This is pretty handy to document, for example, a set of GenServers and how they depend on each other:
Or how multiple GenServers send messages to each other and which responses/replies are used:
And there is way more - only limited by your imagination. For example, this is a mind-map (stolen from https://www.drawio.com/blog/plantuml-mindmaps-from-text) It ain't' half bad, right?
And as all of this is text-based, it plays well with your source files, version control and whatnot.
notes
Notes
- You can find full documentation of PlantUML and the gazillion graphs it produces at https://plantuml.com/
- At the moment, all images are processed through the on-line server
- Nothing stops you from using the module
SayCheezEx.Graphs.Plantuml
to generate SVG images at runtime, not only in documentation. - See also
graphviz/1
.