Welcome to luci’s documentation!¶
luci¶
What luci
is about:
- you add metadata to any type of text file (most likely, but not necessarily, in it’s comments)
- you point
luci
to that file luci
reads the metadataluci
uses that metadata as configuration to (optionally) create a command-line interface for the file in question, and as configuration for a task of your choosingluci
executes that task, letting the user specify additional metadata/configuration values via the dynamically created command-line interface (if applicable)
‘What.. ??’, ‘Those words you just said are weird!!’, ‘English much?!?’ – Yes, sorry. I’m having real trouble coming up with a good and simple explanation for all this. Honestly, I’d be happy to settle for only one of the two!
luci
is the result of one of those situations where I needed a solution for an issue I had (and which would be even more difficult to explain), and where I decided I saw an interesting enough pattern worth trying to implement a generic solution for. I know, I know, typical over-engineered piece of crap solution looking for problems. I don’t care though.
To illustrate the class of problems luci can help with, here are two quick and dirty…
Examples¶
A dynamic text emitter¶
Say you are developing a shell script that processes text via stdin
, and for development purposes (testing regular expressions?) you need to pipe in some (changing, but predictable) text input. This can be achieved quickly in a number of ways, but with luci I think it’s especially straightforward. You create a file (let’s call it dev_input
):
Now, make it executable (chmod +x dev_input
), and put it somewhere into your $PATH
. That’s all, now you’ve got an executable that emits templated text (which can be way more complex than this example, you’d just use some of the more advanced bells and whistles of the jinja2 templating engine) that can be controlled via command-line switches:
Check out the collected examples for more details and options.
Make a file ‘updateable’¶
Say we want to share the file from the last example with our co-workers, and every now and then we update it to add new ‘features’. Of course, we will check it into a git repository. But checking out that repo might or might not be too much overhead for just one file. We could, instead, add the download url to the file’s metadata, and use a luci task to update it. Here’s how the updated file looks like:
Once our co-worker has this file on their machine, and we publish an update, all they need to do is:
❯ luci download /home/markus/.local/bin/dev_input --replace
Again, this is only a very simplistic example to quickly show what luci is about. Check out the full example (and the luci documentation in general) for more details.
luci comes with a few default ‘commands’ (‘lucifiers’ in luci-speak) like the download one. You can easily write your own lucifiers, and that’s where I see luci’s real value, as that let’s you, fairly quickly, create applications and scripts for sorta ‘secondary’ tasks related to the data you commonly work with. In an organized and reproducible way.
Because of it’s generic nature I think examples are best suited to convey the type of problems luci can help solve. Which is why I wrote up some more usage examples.
Obviously, nothing luci does can’t be achieved by writing your own scripts. I honestly have no idea how people feel about embedding task-specific metadata in their files. I think it’s a neat idea in some cases, even if I find it really hard to tell you why I do :-)
Install¶
❯ pip install luci
I’ll leave it as exercise for the reader to decide whether to use sudo
or create a virtualenv or similar for a tidier installation.
Features¶
- generic (to a fault)
- extensible (plugin-architecture, add your own dictlet-finders, dictlet-readers, and lucifiers)
- dynamic command-line interface generation
- includes default task implementations (‘lucifiers’) that help with development/debugging (
debug
,metadata
,cat
) as well as common generic use-cases (template
,download
)
ToDo¶
- look into performance
- add more (input) formats in addition to yaml
- add a few more generic lucifiers
- enable the use of non-text files, directories, urls etc.
- tests
Links¶
- Documentation: https://docs.luci.frkl.io.
License¶
- Free software: GNU General Public License v3
Credits¶
- click
- used to dynamically create the dictlet command-line interface
- jinja2
- does all the templating in the background
- stevedore
- used to manage plugins
- cookiecutter
- was used to create the initial project layout
Installation¶
Stable release¶
To install luci, run this command in your terminal:
$ pip install luci
This is the preferred method to install luci, as it will always install the most recent stable release.
If you don’t have pip installed, this Python installation guide can guide you through the process.
From sources¶
The sources for luci can be downloaded from the Github repo.
You can either clone the public repository:
$ git clone git://github.com/makkus/luci
Or download the tarball:
$ curl -OL https://github.com/makkus/luci/tarball/master
Once you have a copy of the source, you can install it with:
$ python setup.py install
Using inaugurate¶
inaugurate is a generic bootstrap script that can, among other things, install python packages in it’s own conda or virtualenv (in the users home directory):
Using conda¶
$ curl https://inaugurate.sh | NO_EXEC=true bash -s -- luci
Using virtualenv¶
$ curl https://inaugurate.sh | sudo NO_EXEC=true bash -s -- luci
Usage¶
luci’s command-line syntax is based on sub-commands:
❯ luci [luci-opts] LUCIFIER [lucifier-opts] DICTLET [dictlet-opts]
Currently, [luci-opts]
only include the --vars
/-v
option. It is used to specify additional variables to overwrite dictlet defaults (but which can be overwritten by user-provided input).
lucifiers¶
Lucifiers are Python classes that describe tasks. Those tasks are configured by the metadata luci parses and assembles. One of the design goals of luci is to make it easy to write and add additional Lucifiers, to find out more about that please follow this link.
lucifier options¶
lucifiers can be configured with their own set of options. Those are generally very high level, and independent of the dictlet (see below) they use. Usually they would be things like whether you want to use a pager for output, or which format it’s output should be. A lucifiers options can be queried like so:
❯ luci LUCIFIER --help
Default lucifiers¶
That being said, luci comes with a couple of generic lucifiers which should cover a few main use-cases. If you think there’s an obvious one that’s missing, let me know! Here’s a list of currently available ones:
debug
¶
Overview¶
Command-line interface¶
(Autogenerated) cli help
Lucifier to be used when debugging dictlets.
It let’s you print debug information of both metadata and content of a dictlet to stdout.
luci debug [OPTIONS] DICTLET
Options
-
-l
,
--all-lines
¶
display all line-related information (‘content’, ‘content_filtered’, ‘metadata’)
-
-la
,
--lines-all
¶
display all lines of a template
-
-mu
,
--metadata-user
¶
display user-input arguments
-
-lm
,
--lines-metadata
¶
display all lines of a template that were processed by luci
-
-a
,
--all
¶
display all available information
-
-ma
,
--all-metadata
¶
display all available metadata information
-
-md
,
--metadata-defaults
¶
display default vars
-
-lc
,
--lines-content
¶
display all lines of a template that were skipped by luci processing and will be used as content
-
-mt
,
--metadata-dictlet
¶
display processed dictlet metadata
-
-ml
,
--metadata-luci
¶
display luci-related metadata
-
-f
,
--format
<__dictlet__.output_type>
¶ the output type
-
-m
,
--metadata
¶
display the merged metadata)
-
-p
,
--pager
¶
whether to use a pager for display
-
-lf
,
--lines-filtered
¶
display all lines of a template that were skipped by luci processing and are pre-filtered
Metadata requirements¶
Examples¶
download
¶
Overview¶
Command-line interface¶
(Autogenerated) cli help
Lucifier that can update a template by downloading and replacing it on filesystem.
The dictlet needs to contain a metadata key ‘url’ with a child key ‘default’ and the remote url to download as value. It can also, optionally, contain a child key ‘version’ and a templated string like ‘https://dl.com/dictlet-{{ version }}.yml’ as value. The latter will be used if the ‘–version’ option is specified (as described below).
This lucifier adds a few command-line options to the dictlet-part of the command (not the lucifier part, as is normal – mostly because I like it better that way in this case):
- target (‘–target’, ‘-t’): a target file
- replace (‘–replace’, ‘-r’): whether to replace an existing file
- version (‘–version): whether to download a specific version of the file
By default, this lucifier will print out the content of the remote file. If the ‘–replace’ option is specified, the template itself will be replaced with the remote file. If the ‘–target’ option is specified, the remote file will be downloaded to it’s value instead.
luci download [OPTIONS] DICTLET
Options
-
-p
,
--pager
¶
whether to use a pager for display
Metadata requirements¶
Examples¶
metadata
¶
Overview¶
command-line interface¶
(Autogenerated) cli help
Lucifier that extracts metadata out of a dictlet and prints it to stdout.
- Args:
- luci_metadata (bool): whether to also display ‘luci’-specific metadata output_type (str): the format of the output. Available: ‘raw’, ‘json’, ‘yaml’ pager (bool): whether to use a pager or not
luci metadata [OPTIONS] DICTLET
Options
-
-l
,
--luci-metadata
¶
whether to print internal metadata (mostly useful for debugging purposes)
-
-f
,
--format
<__dictlet__.output_type>
¶ the output type
-
-p
,
--pager
¶
whether to use a pager for display
Metadata requirements¶
Examples¶
template
¶
Overview¶
Command-line interface¶
(Autogenerated) cli help
Lucifier that uses the dictlet metadata as variables to replace strings in the dictlet content.
luci template [OPTIONS] DICTLET
Options
-
-p
,
--pager
¶
whether to use a pager for display
-
-f
,
--format
<__user__.output_type>
¶ the output type
-
-a
,
--all
¶
whether to include parts that were being used by luci to extract metadata in the output
Metadata requirements¶
Examples¶
Custom lucifiers¶
luci supports custom build, specialized lucifiers. For those to be picked up, the Python packages they come with need to be installed in the current PYTHONPATH
(for example, the same virtualenv) and be registered with a name in the ‘luci.lucifiers’ namespace (using the stevedore plugin system). For more details on how this works, please check out the lucifier module documentation.
dictlets¶
Dictlet is the name I chose to describe a file that contains metadata luci can parse. Dictlets are text files of any sort (bash scripts, yaml files, etc.) that, usually as comments, contain one or several dictionaries in a format luci has a dictlet reader for. In most cases, you can think of a dictlet as a script within a script, that can be ‘activated’ by luci. A template can have it’s own set of command-line arguments which can be either inherited by the lucifier that is used to run it, or which are contained within the metadata of the dictlet. More information on the format of this metadata can be found here, but as a quick example, here’s how it looks to create an option that uses the --name
flag, which accepts a string as input, and which stores the user input in the name
key, which is a child of the person
(root) key:
vars:
person.name:
meta:
alias: 'name'
type: str
Those command-line options can be described in more detail, if necessary. To query the options of a dictlet, you issue:
❯ luci LUCIFIER DICTLET --help
Dictlets¶
The most generic definition of dictlet is: an item that can be queried for metadata. For all practical intends and purposes this definition is silly though, as currently luci only supports dictlets that are text files. I’ll leave that generic definition here to indicate that, in theory, every thing could theoretically be a dictlet: a folder, a url, a jpeg…
But, for now, let’s just assume a dictlet is a text file that is enriched with some metadata that is not necessary for it’s primary purpose.
Development¶
Adding metadata¶
‘Developing’ a dictlet means adding structured metadata to it, in a way that doesn’t affect it’s original function. Practically that means adding comments that luci can read and interpret as a dictionary. luci uses so-called dictlet readers to extract relevant metadata. The only implemented reader at the moment is the YamlDictletReader
, which inherits most of it’s logic from the base class TextFileDictletReader
.
This reader checks a text file for certain marker string, and then extracts the metadata according to a set of rules:
- check if the file contains the
lucify
keyword. if it does not:- if the file doesn’t contain the
lucify
keyword, check if it contains the default ‘root’ key for the lucifier that is used at the moment (most often that keyword is__luci__
, but for example theDownloadLucifier
usesurl
– check the source code of the lucifier in question for details)
- if the file doesn’t contain the
- if neither the
lucify
keyword is found, nor the lucifier specific keyword, luci will read the whole file - now, the file is read in this way:
- store the characters that precede the keyword (on the line that contains it) as prefix (if any)
- read all lines below that keyword into a buffer, removing the prefix for each line (usually those are comment indicators)
- ignore all lines that do not start with the prefix
- stop once the end of the file is reached, or a line contains the two keywords
lucify
andstop
- hand the content of the buffer to the right reader sub-class, which parses the text into a dictionary
So, let’s say we have a csv file (people.csv
) with the following content:
# lucify
# author: Markus Binsteiner
# date: "2018-03-03"
# tags:
# - luci
# - example
date,subject,result
2018-01-01,alice,okish
2018-01-02,tom,gone crazy
Using the luci metadata
lucifier, we would extract the following metadata:
❯ luci metadata text_file_metadata_example.csv
author: Markus Binsteiner
date: '2018-03-03'
tags:
- luci
- example
The reader stops reading, once it doesn’t find a line starting with #
anymore. We can make it stop beforehand though, if we want:
# lucify
# author: Markus Binsteiner
# date: "2018-03-03"
# lucify: stop
# tags:
# - luci
# - example
This would stop after the date key. The ‘:’ character after lucify
is optional.
We can also split up our metadata into two blocks if we want to, getting the same result as above:
# lucify
# author: Markus Binsteiner
# date: "2018-03-03"
date,subject,result
2018-01-01,alice,okish
2018-01-02,tom,gone crazy
# tags:
# - luci
# - example
To control luci behavior like the adding of a command-line interface, we put the metadata relevant to this under the special __luci__
key. Like so:
#! /usr/bin/env luci
#
# __luci__:
# __default_lucifier__: template
# vars:
# - he
# - she
#
What he said: {{ he }}
Then, she said: {{ she }}
The __default_lucifier__
key is optional, but handy if you use the luci she-bang (#! /usr/bin/env luci
) as it tells luci which lucifier to use in this case (unfortunately, it’s not possible to specify more than one argument in a she-bang line). Everything under var
determines how the command-line interface for the dictlet is rendered. As this behavior can be controlled quite detailed, check out the section below and/or the relevant help page.
Debugging¶
Until you get familiar with dictlets, it’s quite likely you get the formatting wrong, miss a whitespace, or use the wrong key-word. In order to help with those issues, you can use both the metadata
and debug
lucifiers.
Let’s assume we have a (very weird) dictlet (called debug_example
) like this:
# lucify: start
#
# defaults:
# default1: value1
# default2: value2
# help_string: "{{:: defaults.default2 ::}} help string"
# user_default: 42
#
# __luci__:
# defaults_luci:
# luci1: "{{:: defaults.default1 ::}}"
# doc:
# help: "{{:: defaults.help_string ::}} for dictlet"
# short_help: "dictlet short help example"
# epilog: "dictlet epilog example"
# vars:
# __user_input__.arg1:
# meta:
# alias: number
# type: list
# required: false
# doc:
# help: {{:: defaults.help_string ::}}
# short_help: {{:: __luci__.defaults_luci ::}}
# cli:
# enabled: true
# option:
# type: int
# multiple: false
# default: {{:: defaults.user_default ::}}
# lucify: stop
And the user said: "{{ __user_input__.arg1 }}"
We can get the resulting metadata, with and without user input using the metadata
lucifier:
❯ luci metadata debug_example
__user_input__:
arg1: 42
defaults:
default1: value1
default2: value2
help_string: value2 help string
user_default: 42
❯ luci metadata debug_example --number 12
__user_input__:
arg1: 12
defaults:
default1: value1
default2: value2
help_string: value2 help string
user_default: 42
This gives us the ‘useable’ metadata we could use for example when doing template
-ing:
❯ luci template debug_example
And the user said: "42"
❯ luci template debug_example --number 12
And the user said: "12"
If we need more information, about what goes on internally, we can use the debug
lucifier. This lucifier comes with a lot of options to control the values to display (``luci debug –help``_). Here’s how to display the variables resulting from user input:
❯ luci debug -mu debug_example --number 12
metadata: user vars:
__user_input__:
arg1: 12
Command-line interface basics¶
Getting a dictlet (called minimal_arg
) to create a command-line interface can be as easy as adding:
# __luci__:
# vars:
# - arg1
# - arg2
This adds two command-line options, named arg1
and arg2
, which both are optional. This is what it looks like when called with the metadata
lucifier:
❯ luci metadata minimal_arg --help
Usage: luci metadata minimal_arg [OPTIONS]
Options:
--arg1 TEXT n/a
--arg2 TEXT n/a
--help Show this message and exit.
User input will go into the keys with the same name:
❯ luci metadata minimal_arg --arg1 value1
arg1: value1
Now we can make one of the arguments mandatory, like so:
# __luci__:
# vars:
# - arg1
# - arg2:
# meta:
# required: true
We use the meta
key to provide generic information about the option. There is another key, cli
which is used for more command-line specific properties of a cli parameter. Let’s call the above dictlet without the required option:
❯ luci metadata minimal_arg --arg1 value1
Usage: luci metadata minimal_arg [OPTIONS]
Error: Missing option "--arg2".
And we can give the other argument a default value:
# __luci__:
# vars:
# arg1:
# meta:
# default: VALUE_1
# arg2:
# meta:
# required: true
Notice how the value of the var
key is a dict now, instead of a list. luci doesn’t really care which you use. Let’s try to call the command again, providing arg2
for a change:
❯ luci metadata minimal_arg --arg2 value2
arg1: VALUE_1
arg2: value2
If you need more fine-grained control, check out the cli specific help page.
Examples¶
As luci
is designed to help with a fairly generic (and weird) pattern, I find it quite hard to describe what problems it can help you with. I figured, showcasing examples might make more sense. Even if – as you’ll probably discover – some of those examples might seem a bit far-fetched…
Metadata¶
Extract metadata from any textfile¶
(…as long as the file’s format allows for comments)
Say, you’ve got a bunch of csv files that you use for your research project. Now, the all contain ‘raw’ data, but you might want to ‘tag’ them with certain metadata fields to be able to process them in groups, or for whatever else reason. You can of course use the filename and a certain folder structure to organize them (which you should do in either case). But that can be fairly limited if there are overlapping categories.
So, why not add metadata directly into the data files (provided the file-format you use allows for comments or similar)? In that case luci
can help you extract it. Of course, you could do that anyway and write your own script to get the metadata out. But why would you, now that luci
exists, right?
Here’s how the csv file (let’s call it data.csv
) could look (to be honest, I have no idea how to add comments to csv files, but let’s just assume we can use ‘#’ line-prefixes):
# lucify: start
# author: Markus Binsteiner
# date: "2018-03-03"
# tags:
# - luci
# - example
date,subject,result
2018-01-01,alice,okish
2018-01-02,tom,gone crazy
And here’s how to get the metadata out, using ‘json
’ as output format:
❯ luci metadata --format json data.csv
{
"author": "Markus Binsteiner",
"date": "2018-03-03",
"tags": [
"luci",
"example"
]
}
You could use that output in a pipeline, possibly with jq_
or in a script.
Templating¶
Super-basic example¶
Say, we have a file containing:
# __luci__:
# vars:
# - he
# - she
What he said: {{ he }}
Then, she said: {{ she }}
Save that to a file named ‘who_said_what
’. Users of luci
can query this dictlet (this is what we call files that are consumed by luci
) now for it’s interface:
❯ luci template who_said_what --help
Usage: luci template who_said_what [OPTIONS]
Options:
--he TEXT n/a
--she TEXT n/a
--help Show this message and exit.
And, to do the actual templating, we do something like:
❯ luci template who_said_what --he "I don't care" --she "I don't care either"
What he said: I don't care
Then, what she said then: I don't care either
This of course is not really useful, but those dictlets can become much more complex (using loops, conditional statements, etc.), as luci
uses the powerful jinja2 as it’s templating engine.
Using default value for user arg¶
In the previous example we used the most basic user input options, 2 strings. luci supports much more specific options though. For example, say we want to add an optional name for the 2nd person saying stuff. We’d change the dictlet like so:
# __luci__:
# vars:
# - he
# - she
# - name:
# default: she
What he said: {{ he }}
Then, {{ name }} said: {{ she }}
Now, the --help
options gives us:
❯ luci template who_said_what --help
Usage: luci template who_said_what_name
[OPTIONS]
Options:
--he TEXT n/a
--she TEXT n/a
--name TEXT
--help Show this message and exit.
And we can run it like:
❯ luci template who_said_what --he "Wha?" --she "Ya!" --name "Lola"
What he said: Wha?
Then, Lola said: Ya!
As luci uses the click Python library to dynamically create command-line linterfaces, we can use all of Click’s option features to control the created interface. More details on how to create a cli with luci can be found here.
Add boilerplate to a project¶
When developing, often you need to add boilerplate code to a file or project, with just a few strings different between each instance. Perfect use-case for templating. Let’s use luci
itself as an example. luci
uses what is called a lucifier to implement different types of tasks that use dictlet metadata and content as input. Those all inherit from a base class, and need to contain a few attributes and functions. We can easily use a template, combined with user input, to either attach source code describing such a class to a file (or just create a new file). Here’s how that particular ‘add-lucifier’ dictlet looks like:
#! /usr/bin/env luci
#
# __lucify__:
# __default_lucifier__: template
# vars:
# lucifier.name:
# meta:
# type: str
# required: true
# doc:
# help: the name of the lucifier (without the 'Lucifier'-postfix)
# cli:
# option:
# nargs: 1
# required: true
# param_decls: ["--name", "-n"]
# lucifier.help:
# meta:
# type: str
# required: false
# alias: lucifier-help
# doc:
# help: help string for this lucifier
# lucifier.short_help:
# meta:
# type: str
# required: false
# alias: lucifier-short-help
# doc:
# help: short help string for this lucifier
# lucifier.epilog:
# meta:
# type: str
# required: false
# alias: lucifier-epilog
# doc:
# help: epilog string for this lucifier
# lucifier.var_names:
# meta:
# type: list
# required: false
# doc:
# help: names of cli variable names
# cli:
# option:
# param_decls: ["--var-names", "-v"]
# multiple: true
# type: str
class {{ lucifier.name | capitalize }}Lucifer(Lucifier):
"""{{ lucifier.help }}
"""
LUCI_{{ lucifier.name | upper }} = {
"doc": {
"short_help": "{{ lucifier.short_help }}",
# "epilog": "{{ lucifier.epilog }}"
},
"vars": {
{% for var_name in lucifier.var_names %}"__{{ lucifier.name | lower }}__.{{ var_name }}": {
"type": str,
"required": False,
"default": False,
"doc": {
"help": "<var help for {{ var_name }}>"
},
"click": {
# check http://click.pocoo.org/6/api/#parameters for details and available keys
"option": {
"param_decls": ["--{{ var_name }}"],
"type": str,
# potential other options ...
},
# "argument": {
# "param_decls": '{{ var_name }}',
# "nargs": 1
}
}
},
{% endfor -%}
# if you want the following two parameters, you need a: from luci import utils somewhere in this file
# "pager": utils.create_pager_var(),
# "output_type": lucifiers.create_output_type_var()
}
}
def __init__(self, **kwargs):
super({{ lucifier.name | capitalize }}, self). __init__(**kwargs)
def get_default_metadata(self):
return {{ lucifier.name | capitalize }}Lucifier.LUCI_{{ lucifier.name | upper }}
def process_dictlet(self, metadata, dictlet_details):
utils.output(metadata, format="raw", pager=False)
Note how we use click - specific parameters param_decls
and multiple
for the lucifier.var_names
variable:
# lucifier.var_names:
# meta:
# type: list
# required: false
# doc:
# help: names of cli variable names
# cli:
# option:
# param_decls: ["--var-names", "-v"]
# multiple: true
# type: str
To output the assembled boilerplate template to stdout, all we need to do is:
❯ luci template add-lucifier --help
Usage: luci template add-lucifier [OPTIONS]
Options:
-n, --name TEXT the name of the lucifier (without the
'Lucifier'-postfix) [required]
--lucifier-help TEXT help string for this lucifier
--lucifier-short-help TEXT short help string for this lucifier
--lucifier-epilog TEXT epilog string for this lucifier
-v, --var-names TEXT names of cli variable names
--help Show this message and exit.
❯ luci template add-lucifier --name example --lucifier-short-help "An example lucifier" --lucifier-help "An example lucifier" -v input_var_1 -v input_var_2
class ExampleLucifer(Lucifier):
"""An example lucifier
"""
LUCI_EXAMPLE = {
"doc": {
"short_help": "An example lucifier",
# "epilog": ""
},
"vars": {
"__example__.input_var_1": {
"type": str,
"required": False,
"default": False,
"doc": {
"help": "<var help for input_var_1>"
},
...
... <more boilerplate>
...
Download¶
Include update information into a shell script¶
Say, we wrote a cool bash-script we are really proud of:
#!/usr/bin/bash
#
# Copyright Markus Binsteiner, 2018
# version 0.1
echo "Awesome!"
Now, somebody found a bug in the script. So, we fix that bug, and we release a new version. How do we get that new version to our users easily, given that it’s only a shell script, not packaged. And a git checkout of a whole repository doesn’t make all that much sense for only one file either?
With luci
, we can add the remote url of the script in a commented section somewhere, like:
#!/usr/bin/env bash
#
# lucify: start
#
# url:
# default: https://raw.githubusercontent.com/makkus/luci-examples/master/download/awesome/awesome.sh
# version: https://raw.githubusercontent.com/makkus/luci-examples/{{ version }}/download/awesome/awesome.sh
#
# lucify: stop
#
# Copyright Markus Binsteiner, 2018
# version 0.2
echo "Super awesome!"
Then, if one wanted to update the script itself, they’d issue:
❯ luci download awesome.sh --replace
Downloading: https://raw.githubusercontent.com/makkus/luci-examples/master/download/awesome/awesome.sh
Saving file: /home/markus/.local/bin/awesome.sh
Done.
The --replace
option is necessary, as otherwise the download
command would only print out the content of the remote file. To see all the available options for a particular task, we can use the --help
flag:
❯ luci download awesome.sh --help
Usage: luci download awesome.sh [OPTIONS]
Options:
-r, --replace if set, the target file will be overwritten
-t, --target PATH if specified, the url content will be saved into the specified file,
otherwise the dictlet itself will be replaced
--version VERSION the version of the dictlet to download (optional)
--help Show this message and exit.
Of course, this example only makes limited sense, as we’d have to ask our users to install a Python package (luci) just to update a single bash script. Let’s ignore that though, shall we?
Scripting¶
Executable dictlets¶
You can make every dictlet (that is not a script by itself in the first place) executable by setting luci as it’s interpreter in the she-bang line, and adding the __default_lucifier__
key in the __luci__
metadata:
#! /usr/bin/env luci
#
# __luci__:
# __default_lucifier__: template
# vars:
# - he
# - she
What he said: {{ he }}
Then, what she said: {{ she }}
Make this file executable (chmod +x who_said_what
), put it somewhere in your $PATH
and you’ve got a dynamic text emitter script:
❯ who_said_what --help
Usage: luci dev_input [OPTIONS]
Options:
--he TEXT n/a
--she TEXT n/a
--help Show this message and exit.
❯ who_said_what --he Right --she Ok
What he said: Right
Then, what she said: Ok
Authors¶
Written by¶
- Markus Binsteiner <makkus@posteo.de>
Contributors¶
None yet. Why not be the first?