Compare commits

..

7 Commits

54 changed files with 1812 additions and 85 deletions

12
.env Normal file
View File

@ -0,0 +1,12 @@
# General
NAME_OF_APP="ads"
REQUIREMENTS_PY="code/python/requirements"
REQUIREMENTS_GO="code/golang/requirements"
TEST_TIMEOUT="10s"
# Logging
CONSOLE_OUT=/dev/stdout
CONSOLE_ERR=/dev/stderr
CONSOLE_VERBOSE=/dev/null
CONSOLE_PATH_LOGS=logs
CONSOLE_FILENAME_LOGS_DEBUG=debug.log

17
.gitignore vendored
View File

@ -5,6 +5,7 @@
# MAIN FOLDER
################################################################
!/.env
!/README.md
################################################################
@ -19,11 +20,23 @@
!/protocol/README.md
!/protocol/woche*.md
!/scripts
!/scripts/*.sh
!/code
!/code/**/
!/code/**/*.py
!/code/requirements
!/code/python/**/*.py
!/code/golang/**/*.go
!/code/golang/go.mod
!/code/*/requirements
!/code/config.yml
## nicht synchronisieren:
/code/golang/go.sum
/code/python/build
/code/python/build/**
!/dist
!/dist/VERSION
################################################################
# ARTEFACTS

View File

@ -25,16 +25,49 @@ In diesem Repository findet man:
## Code ##
Im Unterordner [`code`](./code) kann man ein Python-Projekt finden,
in dem verschiedene Algorithmen implementiert werden
(siehe insbes. [`code/algorithms`](./code/algorithms)).
Im Unterordner [`code`](./code) kann man Codeprojekte in Python und Golang finden, in denen verschiedene Algorithmen implementiert werden
(siehe insbes. [`code/python/src/algorithms`](./code/python//src/algorithms)
und [`code/golang/pkg/algorithms`](./code/golang/pkg/algorithms)).
Man kann gerne den Code benutzen, in einer eigenen Repository verändern,
und mit den in dem Kurs präsentierten Algorithmen herumexperimentieren.
### Systemvoraussetzungen ###
#### Bashscripts ####
Im Ordner [`scripts`](./scripts) sind mehrere Workflows als Bashscripts kodiert. (Man kann natürlich ohne sie arbeiten, insbesondere dann, wenn man einen guten IDE hat.)
Zunächst braucht man einen Bashterminal. Das kommt mit OSX (Terminal) und Linux. Für Windows-User braucht man [git-for-windows](https://gitforwindows.org) zu installieren, was auch bash mit installiert. (Und für diejenigen, die VSCode oder andere IDEs benutzen, lässt sich bash als integrierten Terminal im IDE selbst verwenden.)
Den Bashscripts benötigen Ausfuhrrechte. Hierfür führe man
```bash
chmod +x scripts/*.sh;
```
aus. Das muss danach nie wiederholt werden.
Jetzt können wir von dem Hauptordner des Repositorys Befehle wie
```bash
./scripts/build.sh
./scripts/build.sh ---mode setup
```
usw. in der Bash-Console ausführen.
#### Für das Golang-Projekt ####
Man braucht [go](https://golang.org/dl/) Version **1.17.x**. (Man kann bestimmt bei späteren Releases höhere Versionen benutzen. Man muss lediglich dann in [`./code/golang/go.mod`](./code/golang/go.mod) die Version hochstellen und die Requirements nochmals installieren lassen.) Und einige Packages werden benötigen. Letztere lassen sich mittels
```bash
./scripts/build.sh --lang go --mode setup
```
installieren.
#### Für das Python-Projekt ####
Python version 3.x.x (idealerweise zumindest 3.9.5) plus einige Module (siehe [code/requirements](./code/requirements)). Letztere lassen sich mittels
```bash
./scripts/build.sh --lang python --mode setup
## mit virtuellem Env:
./scripts/build.sh --lang python --venv true --mode setup
## alternative:
python3 -m pip install -r code/requirements; # linux, osx
py -3 -m pip install -r code/requirements; # Windows
```
@ -42,17 +75,35 @@ installieren.
### Ausführung ###
Um den Python Code auszuführen, bspw. im Bash:
#### Für das Golang-Projekt ####
Zuerst den Artefakt kompilieren:
```bash
./scripts/build.sh --lang go --mode dist;
## oder:
go build -o "dist/ads" "code/golang/main.go";
```
und dann mit dem gebauten Artefakt arbeiten:
```bash
./dist/ads1 help; # zeigt Hilfsanleitung
./dist/ads1 version; # zeigt Version
./dist/ads1 run [--debug]; # führt code aus
```
#### Für das Python-Projekt ####
```bash
pushd code/python/src; ## <- auf Pfad mit main.py wechseln
## Anzeigen der Hilfsanleitung:
python3 code/main.py -h; # linux, OSX
py -3 code/main.py -h; # Windows
python3 main.py -h; # linux, OSX
py -3 main.py -h; # Windows
## Ausführung der Testfälle in code/config.yml:
python3 code/main.py all; # linux, OSX
py -3 code/main.py all; # Windows
## Mit Infos über Schritte:
python3 code/main.py --debug all; # linux, OSX
py -3 code/main.py --debug all; # Windows
python3 main.py run [--debug]; # linux, OSX
py -3 main.py run [--debug]; # Windows
## --debug Option benutzen, um Infos über Schritte zu zeigen.
popd; ## <- zum vorherigen Pfad zurückwechseln
```
Oder man erstelle einen bash Skript wie `run.sh`, trage die Befehle da ein und führe
```bash

View File

@ -1,16 +0,0 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# EXPORTS
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
from code.algorithms.search.sequential import SequentialSearch;
from code.algorithms.search.binary import BinarySearch;
from code.algorithms.search.interpol import InterpolationSearch;
from code.algorithms.search.jump import JumpSearchLinear;
from code.algorithms.search.jump import JumpSearchExponentiell;
from code.algorithms.search.ith_smallest import FindIthSmallest;
from code.algorithms.search.ith_smallest import FindIthSmallestDC;
from code.algorithms.search.poison import FindPoison;
from code.algorithms.search.poison import FindPoisonFast;

15
code/golang/go.mod Normal file
View File

@ -0,0 +1,15 @@
module ads
go 1.17
require (
github.com/akamensky/argparse v1.3.1
github.com/davecgh/go-spew v1.1.1
github.com/lithammer/dedent v1.1.0
github.com/pmezard/go-difflib v1.0.0
github.com/slongfield/pyfmt v0.0.0-20180124071345-020a7cb18bca
github.com/stretchr/objx v0.1.0
github.com/stretchr/testify v1.7.0
golang.org/x/tools v0.1.7
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b
)

View File

@ -0,0 +1,116 @@
package logging
/* ---------------------------------------------------------------- *
* IMPORTS
* ---------------------------------------------------------------- */
import (
"fmt"
"os"
"ads/internal/core/utils"
)
/* ---------------------------------------------------------------- *
* GLOBAL VARIABLES
* ---------------------------------------------------------------- */
var quietmode bool = false
var debugmode bool = false
var ansimode bool = true
var loggingPrefix string = ""
var force bool = false
var tagAll bool = false
func GetQuietMode() bool {
return quietmode
}
func SetQuietMode(mode bool) {
quietmode = mode
}
func GetDebugMode() bool {
return debugmode
}
func SetDebugMode(mode bool) {
debugmode = mode
}
func GetAnsiMode() bool {
return ansimode
}
func SetAnsiMode(mode bool) {
ansimode = mode
}
func GetForce() bool {
return force
}
func SetForce(mode bool) {
force = mode
}
func SetTagAll(mode bool) {
tagAll = mode
}
/* ---------------------------------------------------------------- *
* METHOD logging
* ---------------------------------------------------------------- */
func logGeneric(tag string, lines ...interface{}) {
if !force && quietmode {
return
}
if !(tag == "") {
tag = tag + " "
}
for _, line := range lines {
_line := fmt.Sprintf("%[1]s%[2]s%[3]v", loggingPrefix, tag, line)
if !ansimode {
_line = utils.StripAnsi(_line)
}
fmt.Println(_line)
if !tagAll {
tag = ""
}
}
}
func LogPlain(lines ...interface{}) {
SetTagAll(false)
logGeneric("", lines...)
}
func LogInfo(lines ...interface{}) {
SetTagAll(true)
logGeneric("[\033[94;1mINFO\033[0m]", lines...)
}
func LogDebug(lines ...interface{}) {
if !debugmode {
return
}
SetTagAll(true)
logGeneric("[\033[96;1mDEBUG\033[0m]", lines...)
}
func LogWarn(lines ...interface{}) {
SetTagAll(false)
logGeneric("[\033[93;1mWARNING\033[0m]", lines...)
}
func LogError(lines ...interface{}) {
SetTagAll(false)
logGeneric("[\033[91;1mERROR\033[0m]", lines...)
}
func LogFatal(lines ...interface{}) {
SetTagAll(false)
logGeneric("[\033[91;1mFATAL\033[0m]", lines...)
os.Exit(1)
}

View File

@ -0,0 +1,85 @@
package utils
/* ---------------------------------------------------------------- *
* IMPORTS
* ---------------------------------------------------------------- */
import (
"reflect"
)
/* ---------------------------------------------------------------- *
* METHOD array contains
* ---------------------------------------------------------------- */
func ArrayContains(x interface{}, elem interface{}) bool {
xAsArray := reflect.ValueOf(x)
if xAsArray.Kind() == reflect.Slice {
for i := 0; i < xAsArray.Len(); i++ {
if xAsArray.Index(i).Interface() == elem {
return true
}
}
}
return false
}
// func ListComprehension(x interface{}, cond (interface{}) bool) bool {
// xAsArray := reflect.ValueOf(x)
// if xAsArray.Kind() == reflect.Slice {
// for i := 0; i < xAsArray.Len(); i++ {
// if xAsArray.Index(i).Interface() == elem {
// return true
// }
// }
// }
// return false
// }
/* ---------------------------------------------------------------- *
* METHOD array contains
* ---------------------------------------------------------------- */
func UniqueListOfStrings(X []string) []string {
var ok bool
m := map[string]bool{}
X_unique := []string{}
for _, x := range X {
if _, ok = m[x]; !ok {
X_unique = append(X_unique, x)
}
}
return X_unique
}
/* ---------------------------------------------------------------- *
* METHOD get value from array of unknown length
* ---------------------------------------------------------------- */
func GetArrayStringValue(arr *[]string, index int, Default string) string {
if arr != nil && len(*arr) > index {
return (*arr)[index]
}
return Default
}
func GetArrayBoolValue(arr *[]bool, index int, Default bool) bool {
if arr != nil && len(*arr) > index {
return (*arr)[index]
}
return Default
}
func GetArrayIntValue(arr *[]int, index int, Default int) int {
if arr != nil && len(*arr) > index {
return (*arr)[index]
}
return Default
}
func GetArrayInterfaceValue(arr *[](interface{}), index int, Default interface{}) interface{} {
if arr != nil && len(*arr) > index {
return (*arr)[index]
}
return Default
}

View File

@ -0,0 +1,96 @@
package utils
/* ---------------------------------------------------------------- *
* IMPORTS
* ---------------------------------------------------------------- */
import (
"fmt"
"log"
"reflect"
"strconv"
"strings"
"github.com/lithammer/dedent"
"github.com/slongfield/pyfmt"
"ads/pkg/re"
)
/* ---------------------------------------------------------------- *
* METHOD format strings with dictionary substitution
* ---------------------------------------------------------------- */
func FormatPythonString(text string, arguments map[string]interface{}) string {
var (
err error
key string
value interface{}
kind reflect.Kind
refValue reflect.Value
)
// force compatibility of expressions with python
for key, value = range arguments {
kind = reflect.TypeOf(value).Kind()
switch kind {
case reflect.Ptr:
refValue = reflect.ValueOf(value)
if refValue.IsNil() {
arguments[key] = "None"
}
case reflect.Bool:
arguments[key] = strings.Title(fmt.Sprintf(`%v`, value))
}
}
text, err = pyfmt.Fmt(text, arguments)
if err != nil {
log.Fatal(err)
}
return text
}
/* ---------------------------------------------------------------- *
* METHOD dedent textblock and expand escaped symbols
* ---------------------------------------------------------------- */
func DedentIgnoreEmptyLines(text string) string {
return dedent.Dedent(text)
}
func DedentIgnoreFirstAndLast(text string) string {
text = re.Sub(`^\s*[\n\r]|[\n\r]\s*$`, ``, text)
return DedentIgnoreEmptyLines(text)
}
func DedentAndExpand(text string) string {
var err error
var result []string
result = []string{}
text = dedent.Dedent(text)
lines := strings.Split(text, "\n")
for _, line := range lines {
line = fmt.Sprintf(`"%s"`, line)
line, err = strconv.Unquote(line)
if err != nil {
log.Fatal(err)
}
result = append(result, line)
}
return strings.Join(result, "\n")
}
func FormatTextBlockAsList(text string, options ...bool) []string {
var unindent bool = GetArrayBoolValue(&options, 0, true)
if unindent {
text = DedentIgnoreFirstAndLast(text)
}
return re.Split(`\n`, text)
}
/* ---------------------------------------------------------------- *
* METHODS ansi
* ---------------------------------------------------------------- */
func StripAnsi(text string) string {
return re.Sub(`\x1b[^m]*m`, ``, text)
}

View File

@ -0,0 +1,34 @@
package endpoints
/* ---------------------------------------------------------------- *
* IMPORTS
* ---------------------------------------------------------------- */
import (
"ads/internal/core/logging"
"ads/internal/setup"
)
/* ---------------------------------------------------------------- *
* ENDPOINT version
* ---------------------------------------------------------------- */
func Version() {
logging.SetForce(true)
logging.LogPlain(setup.Version())
}
/* ---------------------------------------------------------------- *
* ENDPOINT help
* ---------------------------------------------------------------- */
func Help() {
logging.SetForce(true)
logging.LogPlain(
"",
setup.Logo(),
// cli.Parser.Usage(nil),
setup.Help(),
"",
)
}

View File

@ -0,0 +1,20 @@
package endpoints
/* ---------------------------------------------------------------- *
* IMPORTS
* ---------------------------------------------------------------- */
import (
"ads/internal/core/logging"
"ads/internal/setup"
)
/* ---------------------------------------------------------------- *
* ENDPOINT run
* ---------------------------------------------------------------- */
func Run(fnameConfig string) error {
logging.LogPlain(setup.Logo())
logging.LogWarn("Die Go-Implementierung ist noch unter Arbeit.")
return nil
}

View File

@ -0,0 +1,66 @@
package cli
/* ---------------------------------------------------------------- *
* IMPORTS
* ---------------------------------------------------------------- */
import (
"github.com/akamensky/argparse"
"ads/internal/types"
)
/* ---------------------------------------------------------------- *
* GLOBAL VARIABLES
* ---------------------------------------------------------------- */
var Parser *argparse.Parser
/* ---------------------------------------------------------------- *
* LOCAL VARIABLES / CONSTANTS
* ---------------------------------------------------------------- */
var optionsQuiet = argparse.Options{
Help: "Blendet alle Konsole-Messages aus.",
Required: false,
Default: false,
}
var optionsDebug = argparse.Options{
Help: "Blendet die Debugging-Befehle ein.",
Required: false,
Default: false,
}
var optionsColour = argparse.Options{
Help: "Ob Logging färblich angezeigt wird (default=true).",
Required: false,
// NOTE: no `Boolean` option available!
Default: "true",
}
var optionsConfigFile = argparse.Options{
Help: "Pfad zur Configdatei (nur für run Endpunkt).",
Required: false,
Default: "code/config.yml",
}
/* ---------------------------------------------------------------- *
* METHODS parse cli
* ---------------------------------------------------------------- */
func ParseCli(args []string) (*types.CliArguments, error) {
var err error
Parser = argparse.NewParser("cli parser", "Liest Optionen + Flags von Kommandozeile.")
arguments := types.CliArguments{
Help: Parser.NewCommand("help", ""),
Version: Parser.NewCommand("version", "Ruft Endpunkt auf, der die Version anzeigt."),
Run: Parser.NewCommand("run", "Ruft Endpunkt auf, der die Algorithmen laufen lässt."),
Quiet: Parser.Flag("q", "quiet", &optionsQuiet),
Debug: Parser.Flag("", "debug", &optionsDebug),
Colour: Parser.String("", "colour", &optionsColour),
ConfigFile: Parser.String("", "config", &optionsConfigFile),
}
err = Parser.Parse(args)
return &arguments, err
}

View File

@ -0,0 +1,56 @@
package setup
/* ---------------------------------------------------------------- *
* IMPORTS
* ---------------------------------------------------------------- */
import (
"embed"
"fmt"
"log"
"strings"
"ads/internal/core/utils"
)
/* ---------------------------------------------------------------- *
* GLOBAL VARIABLES
* ---------------------------------------------------------------- */
var Res embed.FS
var Assets map[string]string
/* ---------------------------------------------------------------- *
* METHOD read assets
* ---------------------------------------------------------------- */
func ReadAsset(key string) string {
var found bool
if _, found = Assets[key]; !found {
log.Fatal(fmt.Sprintf("Key \033[1m%s\033[0m not found in dictionary!", key))
}
data, err := Res.ReadFile(Assets[key])
if err != nil {
log.Fatal(err)
}
text := string(data)
return text
}
/* ---------------------------------------------------------------- *
* METHODS templates
* ---------------------------------------------------------------- */
func Help() string {
contents := ReadAsset("help")
return utils.DedentAndExpand(contents)
}
func Logo() string {
contents := ReadAsset("logo")
return utils.DedentAndExpand(contents)
}
func Version() string {
return strings.Trim(ReadAsset("version"), "\n")
}

View File

@ -0,0 +1,45 @@
package types
/* ---------------------------------------------------------------- *
* IMPORTS
* ---------------------------------------------------------------- */
import (
"strings"
"github.com/akamensky/argparse"
"ads/pkg/re"
)
/* ---------------------------------------------------------------- *
* TYPES
* ---------------------------------------------------------------- */
type CliArguments struct {
Help *argparse.Command
Version *argparse.Command
Run *argparse.Command
Quiet *bool
Debug *bool
Colour *string
ConfigFile *string
}
/* ---------------------------------------------------------------- *
* METHODS convert string option to boolean
* ---------------------------------------------------------------- */
func IsTrue(text string) bool {
text = strings.TrimSpace(text)
return re.Matches(`(?i)(^(true|t|yes|y|1|\+|\+1)$)`, text)
}
func IsFalse(text string) bool {
text = strings.TrimSpace(text)
return re.Matches(`(?i)(^(false|f|no|n|0|-|-1)$)`, text)
}
func (arguments *CliArguments) ShowColour() bool {
return !IsFalse(*arguments.Colour)
}

68
code/golang/main.go Normal file
View File

@ -0,0 +1,68 @@
package main
/* ---------------------------------------------------------------- *
* IMPORTS
* ---------------------------------------------------------------- */
import (
"embed"
"os"
"ads/internal/core/logging"
"ads/internal/endpoints"
"ads/internal/setup"
"ads/internal/setup/cli"
"ads/internal/types"
)
/* ---------------------------------------------------------------- *
* GLOBAL VARIABLES
* ---------------------------------------------------------------- */
var (
// !!! NOTE: do not remove the following "comment", as it is a preprocessing instruction !!!
//go:embed assets/*
res embed.FS
assets = map[string]string{
"version": "assets/VERSION",
"logo": "assets/LOGO",
"help": "assets/HELP",
}
)
/* ---------------------------------------------------------------- *
* METHOD main
* ---------------------------------------------------------------- */
func main() {
var err error
var arguments *types.CliArguments
// set assets
setup.Res = res
setup.Assets = assets
// parse cli arguments
arguments, err = cli.ParseCli(os.Args)
// initialise logging options
if err == nil {
logging.SetQuietMode(*arguments.Quiet)
logging.SetDebugMode(*arguments.Debug)
logging.SetAnsiMode(arguments.ShowColour())
}
if err == nil {
if arguments.Version.Happened() {
endpoints.Version()
} else if arguments.Run.Happened() {
err = endpoints.Run(*arguments.ConfigFile)
} else { // } else if arguments.Help.Happened() {
endpoints.Help()
}
}
if err != nil {
logging.LogFatal(err)
}
}

62
code/golang/pkg/re/re.go Normal file
View File

@ -0,0 +1,62 @@
package re
/* ---------------------------------------------------------------- *
* IMPORTS
* ---------------------------------------------------------------- */
import (
"regexp"
)
/* ---------------------------------------------------------------- *
* GLOBAL VARIABLES
* ---------------------------------------------------------------- */
type Reader struct {
regex *regexp.Regexp
lastpattern *string
}
var defaultReader Reader = Reader{}
/* ---------------------------------------------------------------- *
* METHODS
* ---------------------------------------------------------------- */
func Matches(pattern string, text string) bool {
return defaultReader.Matches(pattern, text)
}
func Sub(pattern string, substitute string, text string) string {
return defaultReader.Sub(pattern, substitute, text)
}
func Split(pattern string, text string) []string {
return defaultReader.Split(pattern, text)
}
func (r *Reader) Matches(pattern string, text string) bool {
r.setReader(pattern)
return r.regex.MatchString(text)
}
func (r *Reader) Sub(pattern string, substitute string, text string) string {
r.setReader(pattern)
return r.regex.ReplaceAllString(text, substitute)
}
func (r *Reader) Split(pattern string, text string) []string {
r.setReader(pattern)
return r.regex.Split(text, -1)
}
/* ---------------------------------------------------------------- *
* PRIVATE MEHODS
* ---------------------------------------------------------------- */
func (r *Reader) setReader(pattern string) {
if r.regex == nil || r.lastpattern == nil || *r.lastpattern != pattern {
r.lastpattern = &pattern
r.regex = regexp.MustCompile(pattern)
}
}

6
code/golang/requirements Normal file
View File

@ -0,0 +1,6 @@
github.com/akamensky/argparse@v1.3.1
github.com/lithammer/dedent@v1.1.0
github.com/slongfield/pyfmt@v0.0.0-20180124071345-020a7cb18bca
github.com/stretchr/testify@v1.7.0
golang.org/x/tools
gopkg.in/yaml.v3@v3.0.0-20210107192922-496545a6307b

View File

@ -1,3 +1,4 @@
pip>=21.3.1
argparse>=1.4.0
pyyaml>=5.4.1
typing>=3.7.4.3

View File

@ -5,5 +5,5 @@
# EXPORTS
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
from code.algorithms.search.exports import *;
from code.algorithms.sum.exports import *;
from src.algorithms.search.exports import *;
from src.algorithms.sum.exports import *;

View File

@ -7,8 +7,8 @@
import functools;
from code.core.log import *;
from code.setup.display import *;
from src.core.log import *;
from src.setup.display import *;
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# CLASSES

View File

@ -5,11 +5,11 @@
# IMPORTS
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
from local.maths import *;
from local.typing import *;
from src.local.maths import *;
from src.local.typing import *;
from code.core.log import *;
from code.algorithms.methods import *;
from src.core.log import *;
from src.algorithms.methods import *;
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# GLOBAL VARIABLES/CONSTANTS

View File

@ -0,0 +1,16 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# EXPORTS
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
from src.algorithms.search.sequential import SequentialSearch;
from src.algorithms.search.binary import BinarySearch;
from src.algorithms.search.interpol import InterpolationSearch;
from src.algorithms.search.jump import JumpSearchLinear;
from src.algorithms.search.jump import JumpSearchExponentiell;
from src.algorithms.search.ith_smallest import FindIthSmallest;
from src.algorithms.search.ith_smallest import FindIthSmallestDC;
from src.algorithms.search.poison import FindPoison;
from src.algorithms.search.poison import FindPoisonFast;

View File

@ -5,11 +5,11 @@
# IMPORTS
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
from local.maths import *;
from local.typing import *;
from src.local.maths import *;
from src.local.typing import *;
from code.core.log import *;
from code.algorithms.methods import *;
from src.core.log import *;
from src.algorithms.methods import *;
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# GLOBAL VARIABLES/CONSTANTS

View File

@ -5,12 +5,12 @@
# IMPORTS
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
from local.maths import *;
from local.typing import *;
from src.local.maths import *;
from src.local.typing import *;
from code.core.log import *;
from code.algorithms.search.sequential import SequentialSearch;
from code.algorithms.methods import *;
from src.core.log import *;
from src.algorithms.search.sequential import SequentialSearch;
from src.algorithms.methods import *;
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# GLOBAL VARIABLES/CONSTANTS

View File

@ -5,12 +5,12 @@
# IMPORTS
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
from local.maths import *;
from local.typing import *;
from src.local.maths import *;
from src.local.typing import *;
from code.core.log import *;
from code.algorithms.search.sequential import SequentialSearch;
from code.algorithms.methods import *;
from src.core.log import *;
from src.algorithms.search.sequential import SequentialSearch;
from src.algorithms.methods import *;
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# GLOBAL VARIABLES/CONSTANTS

View File

@ -5,11 +5,11 @@
# IMPORTS
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
from local.maths import *;
from local.typing import *;
from src.local.maths import *;
from src.local.typing import *;
from code.core.log import *;
from code.algorithms.methods import *;
from src.core.log import *;
from src.algorithms.methods import *;
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# GLOBAL VARIABLES/CONSTANTS

View File

@ -5,11 +5,11 @@
# IMPORTS
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
from local.maths import *;
from local.typing import *;
from src.local.maths import *;
from src.local.typing import *;
from code.core.log import *;
from code.algorithms.methods import *;
from src.core.log import *;
from src.algorithms.methods import *;
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# GLOBAL VARIABLES/CONSTANTS

View File

@ -5,5 +5,5 @@
# EXPORTS
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
from code.algorithms.sum.maxsubsum import MaxSubSum;
from code.algorithms.sum.maxsubsum import MaxSubSumDC;
from src.algorithms.sum.maxsubsum import MaxSubSum;
from src.algorithms.sum.maxsubsum import MaxSubSumDC;

View File

@ -5,11 +5,11 @@
# IMPORTS
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
from local.maths import *;
from local.typing import *;
from src.local.maths import *;
from src.local.typing import *;
from code.core.log import *;
from code.algorithms.methods import *;
from src.core.log import *;
from src.algorithms.methods import *;
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# GLOBAL VARIABLES/CONSTANTS

View File

@ -5,8 +5,8 @@
# IMPORTS
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
from code.local.typing import *;
from code.local.config import *;
from src.local.typing import *;
from src.local.config import *;
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# GLOBAL VARIABLES

View File

@ -5,14 +5,14 @@
# IMPORTS
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
from code.local.io import *;
from code.local.misc import *;
from code.local.system import *;
from code.local.typing import *;
from src.local.io import *;
from src.local.misc import *;
from src.local.system import *;
from src.local.typing import *;
from datetime import timedelta;
from code.core.metrics import *;
from src.core.metrics import *;
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# GLOBAL VARIABLES

View File

@ -8,13 +8,14 @@
import os;
import sys;
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))));
sys.path.insert(0, os.path.abspath(os.path.join(os.path.abspath(__file__), '..', '..')));
os.chdir(os.path.abspath(os.path.join(os.path.abspath(__file__), '..', '..', '..', '..')));
from code.core.log import *;
from code.core.config import *;
from code.setup.display import *;
from code.setup.cli import *;
from code.algorithms.exports import *;
from src.core.log import *;
from src.core.config import *;
from src.setup.display import *;
from src.setup.cli import *;
from src.algorithms.exports import *;
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# GLOBAL VARIABLES/CONSTANTS
@ -30,7 +31,7 @@ def enter(quiet: bool, debug: bool, mode: str, path: Any, **_):
SetQuietMode(quiet);
SetDebugMode(debug);
configpath = path if isinstance(path, str) else PATH_TO_CONFIG;
if mode == 'all':
if mode in 'run':
LoopThroughCases(path=configpath);
else:
DisplayHelpMessage();

View File

@ -5,9 +5,9 @@
# IMPORTS
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
from code.local.typing import *;
from src.local.typing import *;
from code.core.log import *;
from src.core.log import *;
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# GLOBAL VARIABLES
@ -30,7 +30,7 @@ def GetArgumentParser() -> argparse.ArgumentParser:
'''),
formatter_class=argparse.RawTextHelpFormatter,
);
parser.add_argument('mode', nargs=1, choices=['all'], help='all = Führt alle Testfälle in der config.yml Datei durch.');
parser.add_argument('mode', nargs=1, choices=['run'], help='run = Führt alle Testfälle in der config.yml Datei durch.');
parser.add_argument('--path', nargs=1, type=str, help='Pfad zur alternativen Configdatei.');
parser.add_argument('--debug', action='store_true', help='Debugging Messages stummschalten.')
parser.add_argument('-q', '--quiet', action='store_true', help='Alle console-messages bis auf Errors stummschalten.')

View File

@ -5,10 +5,10 @@
# IMPORTS
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
from code.local.typing import *;
from src.local.typing import *;
from code.core.log import *;
from code.setup.cli import GetArgumentParser;
from src.core.log import *;
from src.setup.cli import GetArgumentParser;
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# METHODS display help

1
dist/VERSION vendored Normal file
View File

@ -0,0 +1 @@
0.0.0

51
scripts/.lib.globals.sh Normal file
View File

@ -0,0 +1,51 @@
#!/bin/bash
##############################################################################
# DESCRIPTION: Library for extraction of global vars from environment.
##############################################################################
##############################################################################
# MAIN METHODS: .env
##############################################################################
function env_value() {
[ -f "$1" ] && source "$1" && echo "${!2}";
}
function env_required() {
! [ -f "$1" ] && echo -e "[\033[91mERROR\033[0m] Could not find environment file \033[1m$1\033[0m!" >> /dev/stderr && exit 1;
source "$1";
local value="${!2}";
[ "$value" == "" ] && echo -e "[\033[91mERROR\033[0m] Argument \033[93;1m$2\033[0m not found in \033[1m$1\033[0m!" >> /dev/stderr && exit 1;
echo "$value";
}
function env_from() {
local arguments=( "$@" );
local path="${arguments[0]}";
local key_from="${arguments[2]}";
local key_to="${key_from}";
( echo "${arguments[3]}" | grep -Eiq "^as$" ) && key_to="${arguments[4]}";
! ( echo "$key_to" | grep -Eiq "^([[:alpha:]]|_)([[:alpha:]]|_|[[:digit:]])*$" ) && echo -e "[\033[91mERROR\033[0m] Key argument \"\033[1m$key_to\033[0m\" not a valid name for a variable!" >> /dev/stderr && exit 1;
local value="$( env_required "$path" "$key_from" )";
[ "$value" == "" ] && exit 1;
export $key_to="$value";
}
##############################################################################
# GLOBAL VARIABLES:
##############################################################################
# NOTE: do not use /bin/bash. Results in error under Windows. Use \/bin\/bash, bash, sh -c bash, or sh.
export CMD_EXPLORE="bash";
# periodic waiting time to check a process;
export WAIT_PERIOD_IN_SECONDS=1;
export PENDING_SYMBOL="#";
env_from ".env" import CONSOLE_OUT as OUT;
env_from ".env" import CONSOLE_ERR as ERR;
env_from ".env" import CONSOLE_VERBOSE as VERBOSE;
env_from ".env" import CONSOLE_PATH_LOGS as PATH_LOGS;
env_from ".env" import CONSOLE_FILENAME_LOGS_DEBUG as FILENAME_LOGS_DEBUG;
export LOGGINGPREFIX="";

291
scripts/.lib.sh Normal file
View File

@ -0,0 +1,291 @@
#!/usr/bin/env bash
##############################################################################
# DESCRIPTION: Library of methods specifically for the project.
# Include using source .whales/.lib.sh
##############################################################################
source scripts/.lib.globals.sh;
source scripts/.lib.utils.sh;
##############################################################################
# GLOBAL VARIABLES
##############################################################################
env_from ".env" import REQUIREMENTS_GO as PATH_REQ_GO;
env_from ".env" import REQUIREMENTS_PY as PATH_REQ_PY;
env_from ".env" import NAME_OF_APP;
env_from ".env" import TEST_TIMEOUT;
export CONFIGENV="data/.env";
export PATH_PROJECT_PY="code/python";
export PATH_PROJECT_GO="code/golang";
export PATH_GO_ASSETS_GRAMMAR="assets/grammars";
export PATH_GO_INTERNAL_GRAMMAR="internal/tokenisers/grammars";
export PYTHON_APP_PREFIX=\
'''#!/usr/bin/env python3
# -*- coding: utf-8 -*-'''
export USE_VENV=false;
export UNITTEST_SCHEMA_PY="test_*.py";
##############################################################################
# AUXILIARY METHODS: Go
##############################################################################
function call_go() {
go $@;
}
function install_requirements_go() {
local path="$1";
local cwd="$PWD";
local has_problems=false;
local problem_packages=();
pushd $PATH_PROJECT_GO >> $VERBOSE;
# go mod tidy; # <- use to detect unused packages in project
remove_file "go.sum";
_log_info "Add go requirements";
dos_to_unix "$cwd/$path";
local line;
while read line; do
line="$( _trim_trailing_comments "$line" )";
[ "$line" == "" ] && continue;
_log_info "Run \033[92;1mGO GET\033[0m to install \033[93;1m$line\033[0m.";
( call_go get "$line" 2> $VERBOSE ) && continue;
has_problems=true;
problem_packages+=( "$line" );
done <<< "$( cat "$cwd/$path" )";
popd >> $VERBOSE
( $has_problems ) && _log_fail "Something went wrong whilst using \033[92;1mGO\033[0m to install: {\033[93;1m${problem_packages[*]}\033[0m}.";
}
function compile_go() {
local force="$1";
local path="$2";
local cwd="$PWD";
_log_info "Compile \033[1mmain.go\033[0m with \033[1mgolang\033[0m";
remove_file "dist/$NAME_OF_APP";
pushd "$path" >> $VERBOSE;
call_go build -o "$cwd/dist/$NAME_OF_APP" "main.go";
popd >> $VERBOSE;
! [ -f "dist/$NAME_OF_APP" ] && return 1;
return 0;
}
##############################################################################
# AUXILIARY METHODS: Python
##############################################################################
function use_python_venv_true() { USE_VENV=true; }
function use_python_venv_false() { USE_VENV=false; }
function create_python_venv() {
! ( $USE_VENV ) && return;
_log_info "Create VENV";
! [ -d build ] && mkdir build;
pushd build >> $VERBOSE;
call_python -m venv env;
popd >> $VERBOSE;
}
function activate_python_venv() {
! ( $USE_VENV ) && return;
if ( is_linux ); then
source build/env/bin/activate;
else
source build/env/Scripts/activate;
fi
}
function deactivate_python_venv() {
! ( $USE_VENV ) && return;
if ( is_linux ); then
source build/env/bin/deactivate;
else
source build/env/Scripts/deactivate;
fi
}
function call_python() {
if ( is_linux ); then
python3 $@;
else
py -3 $@;
fi
}
function call_v_python() { activate_python_venv && call_python $@; }
function call_utest() { call_python -m unittest discover $@; }
function call_v_utest() { activate_python_venv && call_utest $@; }
function call_pipinstall() {
# Do not use --user flag with venv
DISPLAY= && call_python -m pip install $@;
}
function install_requirements_python() {
local path="$1";
local has_problems=false;
local problem_packages=();
dos_to_unix "$path";
local line;
while read line; do
line="$( _trim_trailing_comments "$line" )";
[ "$line" == "" ] && continue;
_log_info "Run \033[92;1mPIP\033[0m to install \033[93;1m$line\033[0m.";
( call_pipinstall "$line" >> $VERBOSE ) && continue;
has_problems=true;
problem_packages+=( "$line" );
done <<< "$( cat "$path" )";
( $has_problems ) && _log_fail "Something went wrong whilst using \033[92;1mPIP\033[0m to install: {\033[93;1m${problem_packages[*]}\033[0m}.";
}
function install_requirements_v_python() { activate_python_venv && install_requirements_python $@; }
##############################################################################
# AUXILIARY METHODS: CLEANING
##############################################################################
function garbage_collection_misc() {
clean_all_folders_of_pattern ".DS_Store";
}
function garbage_collection_python() {
clean_folder_contents "$PATH_PROJECT_PY/build";
local path;
for path in "$PATH_PROJECT_PY"; do
pushd "$path" >> $VERBOSE;
# clean_all_files_of_pattern "*\.pyo";
clean_all_folders_of_pattern "__pycache__";
popd >> $VERBOSE;
done
}
function garbage_collection_go {
_log_info "(There are no go files to clean.)";
}
function garbage_collection_dist() {
remove_file "dist/$NAME_OF_APP";
}
##############################################################################
# MAIN METHODS: PROCESSES
##############################################################################
function run_setup() {
_log_info "RUN SETUP";
local current_dir="$PWD";
pushd $PATH_PROJECT_PY >> $VERBOSE;
create_python_venv;
_log_info "Check and install missing requirements";
install_requirements_v_python "$current_dir/$PATH_REQ_PY";
popd >> $VERBOSE;
}
function run_setup_go() {
install_requirements_go "$PATH_REQ_GO";
}
function run_create_artefact() {
local current_dir="$PWD";
local success;
## create temp artefacts:
local _temp="$( create_temporary_dir "dist" )";
mkdir "$_temp/src"
cp -r "$PATH_PROJECT_PY/src/." "$_temp/src";
copy_file file="VERSION" from="dist" to="${_temp}/src/setup";
mv "${_temp}/src/__main__.py" "$_temp";
## zip source files to single file and make executable:
pushd "$_temp" >> $VERBOSE;
( create_zip_archive -o "$current_dir/dist/app.zip" * -x '*__pycache__/*' -x '*.DS_Store' );
success=$?
popd >> $VERBOSE;
if [ $success -eq 0 ]; then
echo "$PYTHON_APP_PREFIX" | cat - dist/app.zip > dist/$NAME_OF_APP;
chmod +x "dist/$NAME_OF_APP";
fi
## remove temp artefacts:
remove_dir "$_temp";
remove_file "dist/app.zip";
! [ $success -eq 0 ] && return 1;
_log_info "Python artefact successfully created.";
return 0;
}
function run_create_artefact_go() {
local current_dir="$PWD";
local success;
## create temp artefacts:
local _temp="$( create_temporary_dir "dist" )";
cp -r "$PATH_PROJECT_GO/." "$_temp";
copy_file file="VERSION" from="dist" to="${_temp}/assets";
( compile_go true "$_temp" );
success=$?;
## remove temp artefacts:
remove_dir "$_temp";
! [ $success -eq 0 ] && return 1;
return 0;
}
function run_main() {
pushd $PATH_PROJECT_PY >> $VERBOSE;
call_v_python src/main.py $@;
popd >> $VERBOSE;
}
function run_main_go() {
compile_go false "$PATH_PROJECT_GO";
./dist/$NAME_OF_APP $@;
}
function run_test_unit() {
local asverbose=$1;
local verboseoption="-v";
local success=0;
! ( $asverbose ) && verboseoption="";
_log_info "RUN UNITTESTS";
pushd $PATH_PROJECT_PY >> $VERBOSE;
( call_v_utest \
$verboseoption \
--top-level-directory "test" \
--start-directory "test" \
--pattern "${UNITTEST_SCHEMA_PY}" 2>&1 \
);
success=$?;
popd >> $VERBOSE;
[ $success -eq 1 ] && _log_fail "Unit tests failed!";
_log_info "Unit tests successful!";
return 0;
}
function run_test_unit_go() {
local asverbose="$1";
local verboseoption="-v";
local success;
_log_info "RUN UNITTESTS";
! ( $asverbose ) && verboseoption=""
pushd $PATH_PROJECT_GO >> $VERBOSE;
( call_go test $verboseoption -timeout $TEST_TIMEOUT -count 1 -run "^Test[A-Z].*" "$NAME_OF_APP" "./..." );
success=$?;
popd >> $VERBOSE
[ $success -eq 1 ] && _log_fail "Unit tests failed!";
_log_info "Unit tests successful!";
return 0;
}
function run_clean_artefacts() {
_log_info "CLEAN ARTEFACTS";
garbage_collection_misc;
garbage_collection_python;
garbage_collection_go;
garbage_collection_dist;
}

504
scripts/.lib.utils.sh Normal file
View File

@ -0,0 +1,504 @@
#!/bin/bash
##############################################################################
# DESCRIPTION: Library of common utility functions.
##############################################################################
##############################################################################
# FOR OS SENSITIVE COMMANDS
##############################################################################
function is_linux() {
[ "$OSTYPE" == "msys" ] && return 1 || return 0;
}
function dos_to_unix() {
( dos2unix --version 2> $VERBOSE >> $VERBOSE ) && dos2unix -q $1 && return;
_log_fail "Install \033[1mdos2unix\033[0m for your system and ensure the command can be called in bash before proceeding. Cf. https://command-not-found.com/dos2unix, https://chocolatey.org/packages/dos2unix, etc.";
}
function clean_scripts_dos2unix() {
local setup_path="$1";
local path;
while read path; do
[ "$path" == "" ] && continue;
dos_to_unix "$path";
done <<< "$( ls -a {,$setup_path/}{,.}*.sh 2> $VERBOSE )";
}
function check_jq_exists() {
( jq --version 2> $VERBOSE >> $VERBOSE ) && return 0 || return 1;
}
##############################################################################
# AUXILIARY METHODS: READING CLI ARGUMENTS
##############################################################################
function has_arg() {
echo "$1" | grep -Eq "(^.*[[:space:]]|^)$2([[:space:]].*$|$)" && return 0 || return 1;
}
function get_kwarg() {
local value="$(echo "$1" | grep -Eq "(^.*\s|^)$2=" && echo "$1" | sed -E "s/(^.*[[:space:]]|^)$2=(\"([^\"]*)\"|\'([^\']*)\'|([^[:space:]]*)).*$/\3\4\5/g" || echo "")";
echo $value | grep -Eq "[^[:space:]]" && echo "$value" || echo "$3";
}
function get_all_kwargs() {
local arguments="$1";
local key="$2";
local get_one=$3;
local default="$4"; # only used if $get_one == true
local pattern="(^.*[[:space:]]|^)$key(\"([^\"]*)\"|\'([^\']*)\'|([^[:space:]]*)).*$";
while ! [[ "$arguments" == "" ]]; do
if ! ( echo "$arguments" | grep -Eq "$pattern" ); then
arguments="";
break;
fi
local value="$(echo "$arguments" | sed -E "s/$pattern/\3\4\5/g" || echo "")";
arguments="$(echo "$arguments" | sed -E "s/$pattern/\1/g" || echo "")";
echo "$value";
( $get_one ) && return 0;
done
( $get_one ) && echo "$default";
}
function get_one_kwarg() {
get_all_kwargs "$1" "$2" true "$3";
}
function get_one_kwarg_space() {
local value="$( get_all_kwargs "$1" "$2[[:space:]]+" true "$3" )";
( echo "$value" | grep -Eq "^-+" ) && value="$3";
echo "$value";
}
##############################################################################
# AUXILIARY METHODS: LOGGING AND CLI-INPUTS
##############################################################################
function check_answer() {
echo "$1" | grep -q -E -i "^(y|yes|j|ja|1)$";
}
function _cli_ask() {
echo -ne "$1" >> $OUT;
}
export CLI_ANSWER="";
function _cli_ask_expected_answer() {
local msg="$1";
local answerpattern="$2";
local read_break_char;
local symb;
CLI_ANSWER="";
while ( true ); do
echo -ne "$msg" >> $OUT;
## read in CLI_ANSWER character by character:
CLI_ANSWER="";
read_break_char=false;
while IFS= read -rn 1 symb; do
case "$symb" in
$'\04') read_break_char=true ;;
$'\n') break ;;
*) CLI_ANSWER="$CLI_ANSWER$symb" ;;
esac
done
( $read_break_char ) && echo -e "" >> $OUT && exit 1;
( echo "$CLI_ANSWER" | grep -Eq "$2" ) && break;
done
}
function _cli_ask_expected_answer_secure() {
local msg="$1";
local answerpattern="$2";
local mask="$3";
local read_break_char;
local symb;
CLI_ANSWER="";
while ( true ); do
echo -ne "$msg" >> $OUT;
stty -echo;
## read in CLI_ANSWER character by character:
CLI_ANSWER="";
read_break_char=false;
while IFS= read -rN 1 symb; do
case "$symb" in
$'\04') read_break_char=true ;;
$'\n') break ;;
*) CLI_ANSWER="$CLI_ANSWER$symb" ;;
esac
done
stty echo;
( $read_break_char ) && echo -e "" >> $OUT && exit 1;
[[ "$mask" == "true" ]] && echo -e "$( echo $CLI_ANSWER | sed -r 's/./\*/g' )" || echo -e "$mask";
( echo "$CLI_ANSWER" | grep -Eq "$2" ) && break;
done
}
function _cli_trailing_message() {
echo -ne "$1" >> $OUT;
}
function _cli_message() {
if [ "$2" == "true" ]; then
_cli_trailing_message "$1";
else
echo -e "$1" >> $OUT;
fi
}
function _log_info() {
_cli_message "${LOGGINGPREFIX}[\033[94;1mINFO\033[0m] $1" $2;
}
function _log_debug() {
_cli_message "${LOGGINGPREFIX}[\033[95;1mDEBUG\033[0m] $1" $2;
if ! [ -f "$PATH_LOGS/$FILENAME_LOGS_DEBUG" ]; then
mkdir "$PATH_LOGS" 2> $VERBOSE;
touch "$PATH_LOGS/$FILENAME_LOGS_DEBUG";
fi
echo "$1" >> "$PATH_LOGS/$FILENAME_LOGS_DEBUG";
}
function _log_warn() {
_cli_message "${LOGGINGPREFIX}[\033[93;1mWARNING\033[0m] $1" $2;
}
function _log_error() {
if [ "$2" == "true" ]; then
echo -ne "${LOGGINGPREFIX}[\033[91;1mERROR\033[0m] $1" >> $ERR;
else
echo -e "${LOGGINGPREFIX}[\033[91;1mERROR\033[0m] $1" >> $ERR;
fi
}
function _log_fail() {
_log_error "$1" $2;
exit 1;
}
##############################################################################
# AUXILIARY METHODS: HELP
##############################################################################
function _help_cli_key_values() {
local arguments=( "$@" );
local key="${arguments[0]}";
local indent="${arguments[1]}";
local values="";
for arg in "${arguments[@]:2}"; do
if ! [ "$values" == "" ]; then values="$values|"; fi
values="$values\033[92;1m$arg\033[0m";
done
local cmd="\033[93;1m$key\033[0m$indent$values";
echo "$cmd";
}
function _help_cli_key_description() {
local arguments=( "$@" );
local key="${arguments[0]}";
local indent="${arguments[1]}";
local descr="${arguments[@]:2}";
local cmd="\033[93;1m$key\033[0m$indent\033[2;3m$descr\033[0m";
echo "$cmd";
}
function _help_cli_values() {
local arguments=( "$@" );
local cmd="";
for arg in "${arguments[@]}"; do
! [ "$cmd" == "" ] && cmd="$cmd|";
cmd="$cmd\033[92;1m$arg\033[0m";
done
echo "$cmd";
}
##############################################################################
# AUXILIARY METHODS: PROGRESSBAR
##############################################################################
function show_progressbar() {
local pid=$1 # Process Id of the previous running command
function shutdown() {
tput cnorm; # reset cursor
}
function cursorBack() {
echo -en "\033[$1D";
}
trap shutdown EXIT;
local displayed=false;
# tput civis; # cursor invisible
while kill -0 $pid 2> $VERBOSE; do
if [ "$displayed" == "false" ]; then
_log_info "pending... $PENDING_SYMBOL" "true";
displayed=true;
else
_cli_trailing_message "$PENDING_SYMBOL";
fi
sleep $WAIT_PERIOD_IN_SECONDS;
done
# tput cnorm; # cursor visible
wait $pid;
local success=$?;
[ "$displayed" == "true" ] && _cli_trailing_message "\n";
return $success;
}
##############################################################################
# AUXILIARY METHODS: STRINGS
##############################################################################
function _trim() {
_trim_trailing_spaces "$( _trim_leading_spaces "$1" )";
}
function _trim_leading_spaces() {
echo "$1" | sed -E "s/^[[:space:]]+(.*)$/\1/g"
}
function _trim_trailing_spaces() {
echo "$1" | sed -E "s/(^.*[^[:space:]]+|^)[[:space:]]+$/\1/g"
}
function to_lower() {
echo "$(echo "$1" |tr '[:upper:]' '[:lower:]')";
}
function to_upper() {
echo "$(echo "$1" |tr '[:lower:]' '[:upper:]')";
}
function is_comment() {
echo "$1" | grep -Eq "^\s*\#" && return 0 || return 1;
}
function _trim_trailing_comments() {
echo "$1" | sed -E "s/(^[^\#]*)\#.*$/\1/g" | sed -E "s/(^.*[^[:space:]]+|^)[[:space:]]+$/\1/g";
}
## Replaces all occurrences of ~ with $HOME.
## NOTE: use / to replace first, // to replace all.
function expand_path() {
echo "${1//\~/$HOME}";
}
##############################################################################
# AUXILIARY METHODS: JSON
##############################################################################
function json_dictionary_kwargs_jq() {
! ( check_jq_exists ) && _log_fail "You need to install \033[1mjq\033[0m to use this method.";
local json="$1";
local format=".key + \" \" + (.value|tostring)";
echo "$json" | jq -r "to_entries | map($format) | .[]";
}
# Only for json dictionaries of type Dict[str,(str|number|bool)],
function json_dictionary_kwargs() {
local json="$1";
# Remove outer braces:
json="$( echo "$json" | sed -E "s/^\{|\}$//g" )";
# Recursively extract keys and values from right-to-left:
local keypattern="[a-zA-Z0-9\.-_]";
local pattern="((^.*),|(^))\"($keypattern*)\":(\"(.*)\"|(.*))$";
function json_dictionary_kwargs_recursive() {
local json="$1";
[ "$json" == "" ] && return;
! ( echo "$json" | grep -Eq "$pattern" ) && return;
local key="$( echo "$json" | sed -E "s/$pattern/\4/g" )";
local value="$( echo "$json" | sed -E "s/$pattern/\6\7/g" )";
json="$( echo "$json" | sed -E "s/$pattern/\2\3/g" )";
json_dictionary_kwargs_recursive "$json";
echo "$key $value";
}
json_dictionary_kwargs_recursive "$json";
}
##############################################################################
# AUXILIARY METHODS: YAML CONFIG FILES
##############################################################################
function has_config_key() {
local config="$1";
local key="$2";
! [ -f $file ] && _log_fail "Config file \033[1m$config\033[0m not found!";
echo "( cat $config )" | grep -Eq "^\s*$key:" && return 0 || return 1;
}
function json_parse() {
local args=( "$@" );
! ( jq --version 2> $VERBOSE >> $VERBOSE ) && _log_fail "Install \033[1mjq\033[0m for your system and ensure the command can be called in bash before proceeding. Cf. https://command-not-found.com/jq, https://chocolatey.org/packages/jq, etc.";
echo "${args[0]}" | jq ${args[@]:1};
}
function yaml_parse() {
local args=( "$@" );
! ( yq --version 2> $VERBOSE >> $VERBOSE ) && _log_fail "Install \033[1myq\033[0m for your system and ensure the command can be called in bash before proceeding. Cf. https://command-not-found.com/yq, https://chocolatey.org/packages/yq, etc.";
local lines="$( yq eval --tojson "${args[0]}" )";
json_parse "$lines" ${args[@]:1};
}
function get_config_key_value_simpleversion() {
local config="$1";
local key="$2";
local default="$3";
! [ -f $config ] && _log_fail "Config file \033[1m$config\033[0m not found!";
## use sed -n .... /p to delete all non-matching lines
## store matches in an array
local lines=( $(echo "( cat $config )" | sed -n -E "s/^[[:space:]]*$key:(.*)$/\1/p") );
## extract the 0th entry, if it exists, otherwise return default.
echo "$([ ${#lines[@]} -gt 0 ] && echo "$(_trim "${lines[0]}")" || echo "$default")";
}
function get_config_key_value() {
local config="$1";
local key="$2";
local default="$3";
! [ -f $config ] && _log_fail "Config file \033[1m$config\033[0m not found!";
local value="$( yaml_parse "$config" --raw-output ".$key" 2> $VERBOSE || echo "$default" )";
[ "$value" == "null" ] && value="$default";
echo "$value";
}
function get_config_boolean() {
local config="$1";
local key="$2";
local default="$3";
local value="$( get_config_key_value "$config" "$key" "$default" )";
[ "$value" == "true" ] && return 0 || return 1;
}
##############################################################################
# AUXILIARY METHODS: FILES AND FOLDERS
##############################################################################
function copy_file() {
local args="$@"
local file="$( get_kwarg "$args" "file" "" )";
local folder_from_formatted="$( get_kwarg "$args" "from" "" )";
local folder_to_formatted="$( get_kwarg "$args" "to" "" )";
local rename="$( get_kwarg "$args" "rename" "" )";
local folder_from="$( expand_path "$folder_from_formatted" )";
local folder_to="$( expand_path "$folder_to_formatted" )";
if ! [ -d "$folder_from" ]; then
_log_error "For copy-file command: source folder \033[1m$folder_from_formatted\033[0m does not exist!";
return;
fi
if ! [ -d "$folder_to" ]; then
_log_error "For copy-file command: destination folder \033[1m$folder_to_formatted\033[0m does not exist!";
return;
fi
if ! [ -f "$folder_from/$file" ]; then
_log_error "For copy-file command: file \033[1m$folder_from_formatted/$file\033[0m could not be found!";
return;
fi
[ "$rename" == "" ] && rename="$file";
cp "$folder_from/$file" "$folder_to/$rename" && _log_info "Copied \033[1m$folder_from_formatted/$file\033[0m to \033[1m$folder_to_formatted/$rename\033[0m." || _log_fail "Copy-file command failed.";
}
function copy_dir() {
local args="$@"
local dir="$( get_kwarg "$args" "dir" "" )";
local folder_from_formatted="$( get_kwarg "$args" "from" "" )";
local folder_to_formatted="$( get_kwarg "$args" "to" "" )";
local folder_from="$( expand_path "$folder_from_formatted" )";
local folder_to="$( expand_path "$folder_to_formatted" )";
if ! [ -d "$folder_from" ]; then
_log_error "For copy-dir command: source folder \033[1m$folder_from_formatted\033[0m does not exist!";
return;
fi
if ! [ -d "$folder_to" ]; then
_log_error "For copy-dir command: destination folder \033[1m$folder_to_formatted\033[0m does not exist!";
return;
fi
if ! [ -d "$folder_from/$dir" ]; then
_log_error "For copy-dir command: directory \033[1m$folder_from_formatted/$dir\033[0m could not be found!";
return;
fi
cp -r "$folder_from/$dir" "$folder_to" && _log_info "Copied \033[1m$folder_from_formatted/$dir\033[0m to \033[1m$folder_to_formatted/$rename\033[0m." || _log_fail "Copy-dir command failed.";
}
function remove_file() {
local fname="$1";
[ -f "$fname" ] && rm -f "$fname" && _log_info "Removed file \033[1m$fname.\033[0m" || _log_info "Nothing to remove: the file \033[1m$fname\033[0m does not exist.";
}
function remove_dir() {
local path="$1";
[ -d "$path" ] && rm -r "$path" && _log_info "Removed directory \033[1m$path.\033[0m" || _log_info "Nothing to remove: the directory \033[1m$path\033[0m does not exist.";
}
function remove_dir_force() {
local path="$1";
[ -d "$path" ] && rm -rf "$path" && _log_info "Removed directory \033[1m$path.\033[0m" || _log_info "Nothing to remove: the directory \033[1m$path\033[0m does not exist.";
}
function create_temporary_dir() {
local current_dir="$1";
local name="tmp";
local path;
local k=0;
pushd "$current_dir" >> $VERBOSE;
while [[ -d "${name}_${k}" ]] || [[ -f "${name}_${k}" ]]; do k=$(( $k + 1 )); done;
path="${name}_${k}";
mkdir "${path}";
popd >> $VERBOSE;
echo "${current_dir}/${path}";
}
##############################################################################
# AUXILIARY METHODS: CLEANING
##############################################################################
function clean_by_pattern() {
local path="$1";
local pattern="$2"
local force=$3;
! ( ls $path | grep -q -E "$pattern" ) && return;
_log_info "Files to be removed:";
ls $path | grep -E "$pattern" | awk -v PATH=$path '{print " \033[94m" PATH "/" $1 "\033[0m"}' >> $OUT;
if ! ( $force ); then
_cli_ask_expected_answer " Do you wish to proceed? (y/n) " "^(y|n)$";
! [[ "$CLI_ANSWER" == "y" ]] && _log_info "skipped." && return;
fi
ls $path | grep -E "$pattern" | awk -v PATH=$path '{print PATH "/" $1}' | xargs rm -r;
_log_info "deleted.";
}
function clean_folder_contents() {
local folder="$1";
local path;
while read path; do
[ "$path" == "" ] && continue;
[ -f "$path" ] && remove_file "$path" >> $VERBOSE && continue;
[ -d "$path" ] && rm -rf "$path" && continue;
done <<< $( find "$folder" -mindepth 1 2> $VERBOSE );
_log_info "(\033[91mforce removed\033[0m) contents of \033[94m$folder/\033[0m";
}
function clean_all_folders_of_pattern() {
local pattern="$1";
local objects=( $( find * -type d -name ${pattern} ) );
local n=${#objects[@]};
[[ $n -gt 0 ]] && find * -type d -name ${pattern} | awk '{print $1}' | xargs rm -rf;
_log_info " (\033[91mforce removed\033[0m) $n x \033[94m${pattern}\033[0m folders";
}
function clean_all_files_of_pattern() {
local pattern="$1";
local objects=( $( find * -type f -name ${pattern} ) );
local n=${#objects[@]};
[[ $n -gt 0 ]] && find * -type f -name ${pattern} | awk '{print $1}' | xargs rm -rf;
_log_info " (\033[91mforce removed\033[0m) $n x \033[94m${pattern}\033[0m files";
}

60
scripts/build.sh Executable file
View File

@ -0,0 +1,60 @@
#!/usr/bin/env bash
##############################################################################
# DESCRIPTION: Script for build-processes.
#
# Usage:
# ~~~~~~
# ./build.sh [options]
##############################################################################
SCRIPTARGS="$@";
FLAGS=( $@ );
ME="scripts/build.sh";
SERVICE="prod-service";
source scripts/.lib.sh;
mode="$( get_one_kwarg_space "$SCRIPTARGS" "-+mode" "" )";
lang="$( get_one_kwarg_space "$SCRIPTARGS" "-+lang" "python" )";
options="$( get_one_kwarg_space "$SCRIPTARGS" "-+options" "" )";
option_venv="$( get_one_kwarg_space "$SCRIPTARGS" "-+venv" "false" )";
( $option_venv ) && use_python_venv_true || use_python_venv_false;
if [ "$mode" == "setup" ]; then
if [ "$lang" == "go" ]; then
run_setup_go;
else #elif [ "$lang" == "python" ]; then
run_setup;
fi
elif [ "$mode" == "dist" ]; then
if [ "$lang" == "go" ]; then
run_create_artefact_go;
else
run_create_artefact;
fi
elif [ "$mode" == "run" ]; then
if [ "$lang" == "go" ]; then
run_main_go $options;
else #elif [ "$lang" == "python" ]; then
echo "options=$options;$SCRIPTARGS."
run_main $options;
fi
else
_log_error "Invalid cli argument.";
_cli_message "";
_cli_message " Call \033[1m./build.sh\033[0m with one of the commands";
_cli_message " $( _help_cli_key_values "--mode" " " "setup" "dist" "run" )";
_cli_message " $( _help_cli_key_values "[--lang]" " " "go" "python" )";
_cli_message "";
_cli_message " $( _help_cli_key_description "--lang python" " " "(default) runs option for the python source code" )";
_cli_message " $( _help_cli_key_description "--lang go" " " "runs option for the go source code" )";
_cli_message "";
_cli_message " $( _help_cli_key_description "--mode setup" " " "compiles programme" )";
_cli_message " $( _help_cli_key_description "--mode dist" " " "creates distribution artefact" )";
_cli_message " $( _help_cli_key_description "--mode run" " " "runs the programme" )";
_cli_message "";
exit 1;
fi
exit 0;

19
scripts/clean.sh Executable file
View File

@ -0,0 +1,19 @@
#!/usr/bin/env bash
##############################################################################
# DESCRIPTION: Script for cleaning-processes.
#
# Usage:
# ~~~~~~
# ./clean.sh [options]
##############################################################################
SCRIPTARGS="$@";
FLAGS=( $@ );
ME="scripts/clean.sh";
source scripts/.lib.sh;
run_clean_artefacts;
exit 0;

54
scripts/test.sh Executable file
View File

@ -0,0 +1,54 @@
#!/usr/bin/env bash
##############################################################################
# DESCRIPTION: Script for test-processes.
#
# Usage:
# ~~~~~~
# ./test.sh [options]
##############################################################################
SCRIPTARGS="$@";
FLAGS=( $@ );
ME="scripts/test.sh";
SERVICE="test-service";
source scripts/.lib.sh;
mode="$( get_one_kwarg_space "$SCRIPTARGS" "-+mode" "")";
lang="$( get_one_kwarg_space "$SCRIPTARGS" "-+lang" "python" )";
options="$( get_one_kwarg_space "$SCRIPTARGS" "-+options" "" )";
option_venv="$( get_one_kwarg_space "$SCRIPTARGS" "-+venv" "false" )";
( $option_venv ) && use_python_venv_true || use_python_venv_false;
if [ "$mode" == "setup" ]; then
if [ "$lang" == "go" ]; then
run_setup_go;
else #elif [ "$lang" == "python" ]; then
run_setup;
fi
elif [ "$mode" == "unit" ]; then
if [ "$lang" == "go" ]; then
run_test_unit_go $options;
else #elif [ "$lang" == "python" ]; then
run_test_unit $options;
fi
elif [ "$mode" == "explore" ]; then
run_explore_console;
else
_log_error "Invalid cli argument.";
_cli_message "";
_cli_message " Call \033[1m./test.sh\033[0m with one of the commands";
_cli_message " $( _help_cli_key_values "--mode" " " "setup" "unit" )";
_cli_message " $( _help_cli_key_values "[--lang]" " " "go" "python" )";
_cli_message "";
_cli_message " $( _help_cli_key_description "--lang python" " " "(default) runs option for the python source code" )";
_cli_message " $( _help_cli_key_description "--lang go" " " "runs option for the go source code" )";
_cli_message "";
_cli_message " $( _help_cli_key_description "--mode setup" " " "compiles programme with test configuration" )";
_cli_message " $( _help_cli_key_description "--mode unit" " " "runs unit test" )";
_cli_message "";
exit 1;
fi
exit 0;