rename commands : ins -> install, del -> delete, ser -> service, cnf -> set | readme add 'alias' command description
This commit is contained in:
parent
7ceaf81ee5
commit
7d50d2d252
111
README.md
111
README.md
|
@ -15,7 +15,6 @@ author: xdrm-brackets
|
||||||
>Need to automate the setup of your linux server or desktop ? This tool is made for you.
|
>Need to automate the setup of your linux server or desktop ? This tool is made for you.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
[TOC]
|
[TOC]
|
||||||
|
|
||||||
|
|
||||||
|
@ -24,58 +23,72 @@ author: xdrm-brackets
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### I. Build Format
|
### I. Commands
|
||||||
|
|
||||||
Your whole setup remains in 1 only build file. Each line contains one instruction, the list of instructions is listed below.
|
Your whole setup remains in 1 only build file. Each line contains one instruction, the list of instructions is listed below.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#### 1) package management
|
#### 1) Comments
|
||||||
|
|
||||||
|
Each line beginning with one of the following characters : `[`, `#` or `;` is considered a comment and is not interpreted.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#### 2) package management
|
||||||
|
|
||||||
These instructions allow you to interact with the package system available on your system.
|
These instructions allow you to interact with the package system available on your system.
|
||||||
|
|
||||||
```
|
```
|
||||||
ins <packages>
|
install <packages>
|
||||||
```
|
```
|
||||||
Install the listed packages. If more than one, use spaces to separate package names.
|
Install the listed packages. If more than one, use spaces to separate package names.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
```
|
```
|
||||||
del <packages>
|
delete <packages>
|
||||||
```
|
```
|
||||||
Remove the listed packages. If more than one, use spaces to separate package names.
|
Remove the listed packages. If more than one, use spaces to separate package names.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#### 3) update configuration files
|
#### 3) setup configuration
|
||||||
|
|
||||||
This instruction allow you to update configuration files without the need of an editor and in a developer-readable manner.
|
This instruction allow you to set fields of configuration files without the need of an editor and in a developer-readable manner.
|
||||||
|
|
||||||
```
|
```
|
||||||
cnf <expr> <content>
|
set <expr> <content>
|
||||||
```
|
```
|
||||||
Update a configuration file where \<expr\> is a dot-separated human-readable [path expression](#ii-path-expressions) and \<content\> is a string or a file. If a string is given, it will <u>override/add the field</u> ; if a file is given the configuration file will be <u>replaced</u> by it.
|
Update a configuration file where \<expr\> is a dot-separated human-readable [path expression](#ii-path-expressions) and \<content\> is a string or a file. If a string is given, it will <u>override/add the field</u> ; if a file is given the configuration file will be <u>replaced</u> by it.
|
||||||
|
|
||||||
|
|
||||||
```
|
|
||||||
cnf <expr>
|
|
||||||
```
|
|
||||||
Remove a configuration field matching the \<expr\> path.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#### 4) service management
|
#### 4) service management
|
||||||
|
|
||||||
These instructions allow you to interact with the service system (_cf. systemd_).
|
These instructions allow you to interact with the service system (_cf. [systemd](https://github.com/systemd/systemd)_).
|
||||||
|
|
||||||
```
|
```
|
||||||
ser [enable|start|stop|restart|reload] <services>
|
service [enable|start|stop|restart|reload] <services>
|
||||||
```
|
```
|
||||||
Perform the action on services. If more than one, use spaces to separate service names.
|
Perform the action on services. If more than one, use spaces to separate service names.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#### 5) custom scripts
|
#### 5) aliases
|
||||||
|
|
||||||
|
The file format allows you to create aliases to file paths for more readability in the [path expression](#ii-path-expressions) or with the [`run` command](#6-custom-scripts).
|
||||||
|
|
||||||
|
```
|
||||||
|
alias name /path/to.file
|
||||||
|
```
|
||||||
|
|
||||||
|
Create the alias `name` which resolves to the path `/path/to.file`.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#### 6) custom scripts
|
||||||
|
|
||||||
These instructions allow you to use custom scripts for complex operations.
|
These instructions allow you to use custom scripts for complex operations.
|
||||||
|
|
||||||
|
@ -83,7 +96,7 @@ These instructions allow you to use custom scripts for complex operations.
|
||||||
run <script>
|
run <script>
|
||||||
```
|
```
|
||||||
|
|
||||||
Execute the \<script\> file.
|
Execute the executable located at the path \<script\>. If script is an [alias](#5-aliases) it will resolve to its path
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -93,14 +106,14 @@ Execute the \<script\> file.
|
||||||
|
|
||||||
### II. Path Expressions
|
### II. Path Expressions
|
||||||
|
|
||||||
The syntax is pretty fast-forward, it uses 2 levels (file, fields) to find your configuration line : `location/path@field.path`.
|
The syntax is pretty fast-forward, it uses 2 levels (file, fields) to find your configuration line : `location_or_alias@fields`.
|
||||||
|
|
||||||
| Field | Description | Example |
|
| Field | Description | Example |
|
||||||
| --------- | :----------------------------------- | -------------------------- |
|
| --------- | :----------------------------------- | -------------------------- |
|
||||||
| `location/path` | Path to the configuration file to edit. The file will be created if not found. | `/etc/ssh/sshd_config`, `/etc/nginx/nginx.conf`, `/etc/nginx/sites-available/default` |
|
| `location_or_alias` | Path to the configuration file to edit. The file will be created if not found. If the path is an [alias](#5-aliases) created before in the file, it will resolve to the alias value as a filename. | `/etc/nginx/nginx.conf`, `some-alias` |
|
||||||
| `field.path` | Dot-separated chain of strings that match a configuration field. If **omitted**, the \<value\> will just be added at the end of the configuration file. In the same way if the field does not point to a raw field but a parent or group containing fields, the \<value\> will be added to the group. | `/etc/ssh/sshd_config@AllowGroups`, `/etc/nginx/nginx.conf@http.gzip` |
|
| `fields` | Dot-separated chain of strings that match a configuration field. If the field does not point to a raw field but an existing field container, the \<value\> will replace the group with a text value. | `AllowGroups`, `http.gzip` |
|
||||||
|
|
||||||
> When a file is given as \<content\>, the `cnf` command acts as the shell command `mv` (copy).
|
> The `fields` is processed only for known file formats listed in this [section](#file-formats).
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -110,13 +123,10 @@ Configuration files can be written according to some standards or application-sp
|
||||||
|
|
||||||
- [xml](https://fr.wikipedia.org/wiki/Extensible_Markup_Language) and [json](https://json.org/) are read/written using the go standard library (_cf. [json](https://golang.org/pkg/encoding/json/), [xml](https://golang.org/pkg/encoding/xml/)_).
|
- [xml](https://fr.wikipedia.org/wiki/Extensible_Markup_Language) and [json](https://json.org/) are read/written using the go standard library (_cf. [json](https://golang.org/pkg/encoding/json/), [xml](https://golang.org/pkg/encoding/xml/)_).
|
||||||
|
|
||||||
> xml to do ; complex structure the library outputs (attributes vs. content) to understand better
|
> xml is not yet supported ; complex structure the library outputs (attributes vs. content) to understand better
|
||||||
|
|
||||||
- [yaml](https://en.wikipedia.org/wiki/YAML) with [go-yaml/yaml](https://github.com/go-yaml/yaml).
|
- [yaml](https://en.wikipedia.org/wiki/YAML) with [go-yaml/yaml](https://github.com/go-yaml/yaml).
|
||||||
- [ini](https://en.wikipedia.org/wiki/INI_file) with [go-ini/ini](https://github.com/go-ini/ini).
|
- [ini](https://en.wikipedia.org/wiki/INI_file) with [go-ini/ini](https://github.com/go-ini/ini).
|
||||||
- <strike>[toml](https://en.wikipedia.org/wiki/TOML)</strike> with [BurntSushi/toml](https://github.com/BurntSushi/toml).
|
|
||||||
|
|
||||||
> not consistent ; overriding a toml file with this can mess with comments and duplicate sections. Also there is type inference to do (strings are surrounded with `"`, there is `true`, `false`, etc)
|
|
||||||
|
|
||||||
- [nginx configurations](https://docs.nginx.com/nginx/admin-guide/basic-functionality/managing-configuration-files/) with [my own library](https://godoc.org/git.xdrm.io/go/nix-amer/internal/cnf/parser/nginx).
|
- [nginx configurations](https://docs.nginx.com/nginx/admin-guide/basic-functionality/managing-configuration-files/) with [my own library](https://godoc.org/git.xdrm.io/go/nix-amer/internal/cnf/parser/nginx).
|
||||||
- _and more to come..._
|
- _and more to come..._
|
||||||
|
@ -127,34 +137,45 @@ Configuration files can be written according to some standards or application-sp
|
||||||
|
|
||||||
## Example
|
## Example
|
||||||
|
|
||||||
|
Launch the following command to install your server :
|
||||||
|
|
||||||
|
```bash
|
||||||
|
$ nix-amer -p apt-get myserver.build
|
||||||
|
```
|
||||||
|
|
||||||
|
> Replace `apt-get` by your package manager; `nix-amer -help` for available options.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
_myserver.build_
|
_myserver.build_
|
||||||
|
|
||||||
```
|
```
|
||||||
sys name ubuntu # required to choose which
|
[ comment starts with opening brackets '['
|
||||||
sys version 18.4 # package-manager to use
|
|
||||||
|
|
||||||
[install]
|
[aliases]
|
||||||
upd
|
alias sshd /etc/ssh/sshd_config
|
||||||
ins nginx ssh sslh
|
alias nginx /etc/nginx/nginx.conf
|
||||||
|
alias sslh /etc/default/sslh
|
||||||
|
|
||||||
|
[install packages]
|
||||||
|
install nginx ssh
|
||||||
|
install sslh
|
||||||
|
|
||||||
[nginx]
|
[nginx]
|
||||||
cnf /etc/nginx/nginx.conf@http.gzip on
|
set nginx@http.gzip off
|
||||||
cnf /etc/nginx/sites-available/new-site ./localConfFile
|
service enable nginx
|
||||||
ser enable nginx
|
service start nginx
|
||||||
ser start nginx
|
|
||||||
|
|
||||||
[sshd]
|
[sshd]
|
||||||
cnf /etc/ssh/sshd_config@PermitRootLogin no
|
set sshd@PermitRootLogin no
|
||||||
cnf /etc/ssh/sshd_config@PermitEmptyPasswords no
|
set sshd@PermitEmptyPasswords no
|
||||||
cnf /etc/ssh/sshd_config@StrictModes yes
|
service enable sshd
|
||||||
cnf /etc/ssh/sshd_config@Port 22
|
service enable ssh
|
||||||
ser enable sshd
|
|
||||||
ser enable ssh
|
|
||||||
|
|
||||||
[sslh]
|
[sslh]
|
||||||
cnf /etc/default/sslh@RUN yes
|
set sslh@RUN yes
|
||||||
cnf /etc/default/sslh@DEAMON_OPTS "--user sslh --listen 0.0.0.0:443 --ssh 127.0.0.1:22 --ssl 127.0.0.1:44300 --pidfile /var/run/sslh/sslh.pid"
|
set sslh@DEAMON_OPTS "--user sslh --listen 0.0.0.0:443 --ssh 127.0.0.1:22 --ssl 127.0.0.1:44300 --pidfile /var/run/sslh/sslh.pid"
|
||||||
ser enable sslh
|
service enable sslh
|
||||||
ser start sslh
|
service start sslh
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
|
@ -49,7 +49,7 @@ func NewReader(ctx *instruction.ExecutionContext, buildfile io.Reader) (*Reader,
|
||||||
line = strings.Trim(line, " \t\r\n")
|
line = strings.Trim(line, " \t\r\n")
|
||||||
|
|
||||||
// ignore newline & comments
|
// ignore newline & comments
|
||||||
if len(line) < 1 || line[0] == '[' {
|
if len(line) < 1 || strings.ContainsAny(line[0:1], "[#;") {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -33,26 +33,24 @@ func TestInstructionSyntax(t *testing.T) {
|
||||||
Line int
|
Line int
|
||||||
Err error
|
Err error
|
||||||
}{
|
}{
|
||||||
{"ins args\ndel args\n", 0, nil},
|
{"install args\ndelete args\n", 0, nil},
|
||||||
{" ins args\ndel args\n", 0, nil},
|
{" install args\ndelete args\n", 0, nil},
|
||||||
{"\tins args\ndel args\n", 0, nil},
|
{"\tinstall args\ndelete args\n", 0, nil},
|
||||||
{" \t ins args\ndel args\n", 0, nil},
|
{" \t install args\ndelete args\n", 0, nil},
|
||||||
{" \t ins args\ndel args\n", 0, nil},
|
{" \t install args\ndelete args\n", 0, nil},
|
||||||
|
|
||||||
{"cmd args\ncmd args\n", 1, instruction.ErrUnknownInstruction},
|
{"cmd args\ncmd args\n", 1, instruction.ErrUnknownInstruction},
|
||||||
{"ins args\ncmd args\n", 2, instruction.ErrUnknownInstruction},
|
{"install args\ncmd args\n", 2, instruction.ErrUnknownInstruction},
|
||||||
{" cmd args\ncmd args\n", 1, instruction.ErrUnknownInstruction},
|
{" cmd args\ncmd args\n", 1, instruction.ErrUnknownInstruction},
|
||||||
{"\tcmd args\ncmd args\n", 1, instruction.ErrUnknownInstruction},
|
{"\tcmd args\ncmd args\n", 1, instruction.ErrUnknownInstruction},
|
||||||
{" \t cmd args\ncmd args\n", 1, instruction.ErrUnknownInstruction},
|
{" \t cmd args\ncmd args\n", 1, instruction.ErrUnknownInstruction},
|
||||||
{" \t cmd args\ncmd args\n", 1, instruction.ErrUnknownInstruction},
|
{" \t cmd args\ncmd args\n", 1, instruction.ErrUnknownInstruction},
|
||||||
|
|
||||||
{" md args\ncmd args\n", 1, instruction.ErrInvalidSyntax},
|
{"cmd args\ncmd\n", 1, instruction.ErrUnknownInstruction},
|
||||||
{"c d args\ncmd args\n", 1, instruction.ErrInvalidSyntax},
|
{"install\ncmd args\n", 1, instruction.ErrInvalidSyntax},
|
||||||
{"cm args\ncmd args\n", 1, instruction.ErrInvalidSyntax},
|
|
||||||
|
|
||||||
{"ins args\n md args\n", 2, instruction.ErrInvalidSyntax},
|
{"install args\n cmd args\n", 2, instruction.ErrUnknownInstruction},
|
||||||
{"ins args\nc d args\n", 2, instruction.ErrInvalidSyntax},
|
{"install args\ncmd\n", 2, instruction.ErrInvalidSyntax},
|
||||||
{"ins args\ncm args\n", 2, instruction.ErrInvalidSyntax},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx, _ := instruction.CreateContext("apt-get", "")
|
ctx, _ := instruction.CreateContext("apt-get", "")
|
||||||
|
|
|
@ -11,16 +11,17 @@ func TestDecodeEncode(t *testing.T) {
|
||||||
Input string
|
Input string
|
||||||
Output string
|
Output string
|
||||||
}{
|
}{
|
||||||
{"key value;\n", "key value;\n"},
|
{"key\t\tvalue;\n", "key\t\tvalue;\n"},
|
||||||
{"key value;\n", "key value;\n"},
|
{"key value;\n", "key\t\tvalue;\n"},
|
||||||
{"key \t value;\n", "key value;\n"},
|
{"key value;\n", "key\t\tvalue;\n"},
|
||||||
{"key\tvalue;\n", "key value;\n"},
|
{"key \t value;\n", "key\t\tvalue;\n"},
|
||||||
{"ke-y value;\n", "ke-y value;\n"},
|
{"key\tvalue;\n", "key\t\tvalue;\n"},
|
||||||
{"ke_y value;\n", "ke_y value;\n"},
|
{"ke-y value;\n", "ke-y\t\tvalue;\n"},
|
||||||
{"key value; \n", "key value;\n"},
|
{"ke_y value;\n", "ke_y\t\tvalue;\n"},
|
||||||
{"key value;\t\n", "key value;\n"},
|
{"key value; \n", "key\t\tvalue;\n"},
|
||||||
{"\tkey value;\n", "key value;\n"},
|
{"key value;\t\n", "key\t\tvalue;\n"},
|
||||||
{" \t key value;\n", "key value;\n"},
|
{"\tkey value;\n", "key\t\tvalue;\n"},
|
||||||
|
{" \t key value;\n", "key\t\tvalue;\n"},
|
||||||
|
|
||||||
{"include ./file/*.conf;\n", "include ./file/*.conf;\n"},
|
{"include ./file/*.conf;\n", "include ./file/*.conf;\n"},
|
||||||
{"include ./file/*.conf; \n", "include ./file/*.conf;\n"},
|
{"include ./file/*.conf; \n", "include ./file/*.conf;\n"},
|
||||||
|
|
|
@ -8,33 +8,33 @@ import (
|
||||||
func Parse(raw string) (T, error) {
|
func Parse(raw string) (T, error) {
|
||||||
|
|
||||||
// 1. format (trim + split first space)
|
// 1. format (trim + split first space)
|
||||||
cmd := strings.SplitN(raw, " ", 2)
|
split := strings.SplitN(raw, " ", 2)
|
||||||
cmd[0] = strings.Trim(cmd[0], " \t")
|
if len(split) < 2 { // at least 1 command + arguments
|
||||||
|
|
||||||
// 2. fail if invalid base syntax 'cmd args...'
|
|
||||||
// where command is 3 letters
|
|
||||||
if len(cmd) < 2 || len(cmd[0]) < 3 || cmd[0][1] == ' ' {
|
|
||||||
return nil, ErrInvalidSyntax
|
return nil, ErrInvalidSyntax
|
||||||
}
|
}
|
||||||
cmd[1] = strings.Trim(cmd[1], " \t")
|
|
||||||
|
split[0] = strings.Trim(split[0], " \t")
|
||||||
|
|
||||||
|
// 2. fail if invalid base syntax 'cmd args...'
|
||||||
|
split[1] = strings.Trim(split[1], " \t")
|
||||||
|
|
||||||
// 3. Extract instruction type
|
// 3. Extract instruction type
|
||||||
switch cmd[0] {
|
switch split[0] {
|
||||||
case "ins":
|
case "install":
|
||||||
i := &install{}
|
i := &install{}
|
||||||
err := i.Build(cmd[1])
|
err := i.Build(split[1])
|
||||||
return i, err
|
return i, err
|
||||||
case "del":
|
case "delete":
|
||||||
i := &delete{}
|
i := &delete{}
|
||||||
err := i.Build(cmd[1])
|
err := i.Build(split[1])
|
||||||
return i, err
|
return i, err
|
||||||
case "ser":
|
case "service":
|
||||||
i := &service{}
|
i := &service{}
|
||||||
err := i.Build(cmd[1])
|
err := i.Build(split[1])
|
||||||
return i, err
|
return i, err
|
||||||
case "cnf":
|
case "set":
|
||||||
i := &config{}
|
i := &set{}
|
||||||
err := i.Build(cmd[1])
|
err := i.Build(split[1])
|
||||||
return i, err
|
return i, err
|
||||||
default:
|
default:
|
||||||
return nil, ErrUnknownInstruction
|
return nil, ErrUnknownInstruction
|
||||||
|
|
|
@ -11,7 +11,7 @@ import (
|
||||||
// a field
|
// a field
|
||||||
var ErrCannotSet = fmt.Errorf("cannot set the field")
|
var ErrCannotSet = fmt.Errorf("cannot set the field")
|
||||||
|
|
||||||
type config struct {
|
type set struct {
|
||||||
raw string
|
raw string
|
||||||
// File is the path to the file
|
// File is the path to the file
|
||||||
File string
|
File string
|
||||||
|
@ -23,9 +23,9 @@ type config struct {
|
||||||
Format *cnf.ConfigurationFormat
|
Format *cnf.ConfigurationFormat
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *config) Raw() string { return d.raw }
|
func (d *set) Raw() string { return d.raw }
|
||||||
|
|
||||||
func (d *config) Build(_args string) error {
|
func (d *set) Build(_args string) error {
|
||||||
|
|
||||||
// 1. extract action (sub command)
|
// 1. extract action (sub command)
|
||||||
split := strings.Fields(_args)
|
split := strings.Fields(_args)
|
||||||
|
@ -55,7 +55,7 @@ func (d *config) Build(_args string) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d config) Exec(ctx ExecutionContext) ([]byte, error) {
|
func (d set) Exec(ctx ExecutionContext) ([]byte, error) {
|
||||||
|
|
||||||
// 1. try to load format
|
// 1. try to load format
|
||||||
format, err := cnf.Load(d.File)
|
format, err := cnf.Load(d.File)
|
Loading…
Reference in New Issue