{"id":17972998,"url":"https://github.com/gi0baro/noir","last_synced_at":"2025-03-25T12:33:13.280Z","repository":{"id":39485956,"uuid":"359276055","full_name":"gi0baro/noir","owner":"gi0baro","description":"A command-line tool for template rendering","archived":false,"fork":false,"pushed_at":"2024-04-15T17:41:19.000Z","size":102,"stargazers_count":8,"open_issues_count":0,"forks_count":1,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-03-20T08:44:53.475Z","etag":null,"topics":["cli","renoir","templating","toml","yaml"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsd-3-clause","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/gi0baro.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null},"funding":{"github":["gi0baro"]}},"created_at":"2021-04-18T23:40:54.000Z","updated_at":"2024-09-20T17:25:28.000Z","dependencies_parsed_at":"2024-10-29T17:03:11.467Z","dependency_job_id":null,"html_url":"https://github.com/gi0baro/noir","commit_stats":null,"previous_names":[],"tags_count":15,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gi0baro%2Fnoir","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gi0baro%2Fnoir/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gi0baro%2Fnoir/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gi0baro%2Fnoir/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/gi0baro","download_url":"https://codeload.github.com/gi0baro/noir/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":245463039,"owners_count":20619601,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cli","renoir","templating","toml","yaml"],"created_at":"2024-10-29T16:26:50.151Z","updated_at":"2025-03-25T12:33:12.916Z","avatar_url":"https://github.com/gi0baro.png","language":"Python","funding_links":["https://github.com/sponsors/gi0baro"],"categories":[],"sub_categories":[],"readme":"# Noir\n\nNoir – /nwɑːr/ – is a template renderer based on [Renoir](https://github.com/emmett-framework/renoir) templating engine.\n\nTypical use case for Noir is generating configuration files and manifests for services and applications.\n\nInspired by [mkolypto/j2cli](https://github.com/kolypto/j2cli)\n\n## Installation\n\nYou can install Noir using [Homebrew](https://brew.sh/):\n\n    brew install gi0baro/tap/noir\n\nor you can manually download the packages from the [releases page](https://github.com/gi0baro/noir/releases).\n\n## Usage\n\n```console\n$ noir --help\nUsage: noir [OPTIONS] SOURCE\n\n  Render a SOURCE template file or string using specified contexts and vars.\n\nArguments:\n  SOURCE  The template file to use.  [required]\n\nOptions:\n  -e, --eval                      Parse source as template string.\n  -v, --var TEXT                  Context variable(s) to apply.\n  -c, --context PATH              Context file(s) to use.\n  -f, --format [env|ini|json|toml|yaml|yml]\n                                  Context file format (default: guess from\n                                  file extension).\n  -o, --output FILENAME           Target output (default: stdout)\n  --delimiters TEXT               Template delimiters  [default: {{,}}]\n  --version                       Show the version and exit.\n  --install-completion [bash|zsh|fish|powershell|pwsh]\n                                  Install completion for the specified shell.\n  --show-completion [bash|zsh|fish|powershell|pwsh]\n                                  Show completion for the specified shell, to\n                                  copy it or customize the installation.\n  --help                          Show this message and exit.\n```\n\nThe `noir` command accepts as the only argument the template file or string to render.\n\nContextual data con be loaded from a file, using the `-c/--context` option, which supports the formats:\n\n- env\n- ini\n- json\n- toml\n- yaml\n\nor directly from the command using the `-v/--var` option.\n\nBoth options support defining a namespace using the `namespace:var` notation.\n\n### Context helpers\n\n#### libraries\n\nThe default context in Noir already imports the following modules from the Python standard library:\n\n- base64\n- datetime\n- hashlib\n- random\n- uuid\n\n\u003e **Note:** additional modules from standard library might be loaded with the `import` statement\n\n#### env\n\nAn object containing environment variables.\n\n```ini\nfoo=\"{{ =env.VAR_FOO }}\"\nbar=\"{{ =env[\"VAR_BAR\"] }}\"\n```\n\n#### Base64 shortcuts\n\nShortcuts for `base64.b64encode` and `base64.b64decode` handling encoding/decoding:\n\n```yaml\nhash: {{ =base64encode(\"foobar\") }}\ndecoded_hash: {{ =base64decode(hash) }}\n```\n\n#### CIDR helpers\n\nFunctions to interact with IPv4/IPv6 objects:\n\n```\ncidr.subnet(prefix, newbits, netnum)\ncidr.host(prefix, hostnum)\ncidr.netmask(prefix)\ncidr.subnets(prefix, *newbits)\n```\n\n#### Pathlib Path\n\n```yaml\ntarget: {{ =Path.cwd() / \"target\" / \"foo.bar\" }}\n```\n\n#### indent\n\nA function to indent a text with the given number of spaces.\n\n```yaml\ndata: |-\n  {{ =indent(multiline_str, 2) }}\n```\n\n#### to_json\n\nA function to render json content. Accepts an optional integer indent parameter.\n\n```json\n{\n    \"key\": \"value\",\n    \"data\": {{ =to_json(data, indent=None) }}\n}\n```\n\n#### to_toml\n\nA function to render TOML content.\n\n```toml\n[data]\nfoo = \"bar\"\n{{ =to_toml(data) }}\n```\n\n#### to_yaml\n\nA function to render YAML content.\n\n```yaml\ndata:\n  {{ =indent(to_yaml(data), 2) }}\n```\n\n## Examples\n\nSuppose you have an nginx configuration file template `nginx.conf.tpl`:\n\n```\nserver {\n  listen 80;\n  server_name {{ =nginx.hostname }};\n\n  root {{ =nginx.webroot }};\n  index index.htm;\n}\n```\n\nand you have a YAML file `nginx.yaml`:\n\n```yaml\nnginx:\n  hostname: localhost\n  webroot: /var/www/project\n```\n\nThen you can render you configuration file as:\n\n```console\n$ noir nginx.conf.tpl -c nginx.yaml \u003e nginx.conf\n```\n\nwhich will produce the following `nginx.conf`:\n\n```\nserver {\n  listen 80;\n  server_name localhost;\n\n  root /var/www/project;\n  index index.htm;\n}\n```\n\nYou can reach the same result passing variables directly, like:\n\n```console\n$ noir nginx.conf.tpl \\\n    -v nginx:hostname=localhost \\\n    -v nginx:webroot=/var/www/project \\\n    \u003e nginx.conf\n```\n\nSince [Renoir](https://github.com/emmett-framework/renoir) supports fully-functional Python code, you can also define structures and import libraries, for example you can produce a `secrets.yaml` manifest for kubernetes using environment variables starting with `K8S_`:\n\n```yaml\n{{ secrets = {k.strip(\"K8S_\"): v for k, v in env.items() if k.startswith(\"K8S_\")} }}\napiVersion: v1\nkind: Secret\ntype: Opaque\nmetadata:\n  name: secret\ndata:\n  {{ for k, v in secrets.items(): }}\n  {{ =k }}: \"{{ =base64.b64encode(v.encode(\"utf-8\")) }}\"\n  {{ pass }}\n```\n\nand render it:\n\n```console\n$ export K8S_VAR1=val1\n$ export K8S_VAR2=val2\n$ noir secrets.yaml\n```\n\nHere are some additional examples:\n\n```console\n$ # use environment variables\n$ noir -e 'Hello, {{ =env.USER }}'\nHello, gi0baro\n\n$ # do some math\n$ noir -e 'the answer is: {{ =6 * 7 }}'\nthe answer is: 42\n\n$ # ranges\n$ noir -e '{{ for i in range(5, 0, -1): }}{{ =f\"{i} \" }}{{ if i == 1: }}{{ =\"blastoff\".upper() }}{{ pass }}{{ pass }}'\n5 4 3 2 1 BLASTOFF\n\n$ # context from curl requests\n$ curl -s https://ipinfo.io | noir -c ip:- -f json -e 'country code: {{ =ip.country }}'\ncountry code: IT\n\n$ # pretty printing from stdin\n$ echo '{\"cities\":[\"London\", \"Rome\", \"New York\"]}' | noir -c - -f json -e '{{ =\", \".join(cities) }}'\nLondon, Rome, New York\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgi0baro%2Fnoir","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgi0baro%2Fnoir","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgi0baro%2Fnoir/lists"}