Merge branch 'development_kristof10' of https://github.com/freeflowuniverse/herolib into development_kristof10
This commit is contained in:
4
.github/workflows/documentation.yml
vendored
4
.github/workflows/documentation.yml
vendored
@@ -2,9 +2,9 @@ name: Deploy Documentation to Pages
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: ["main"]
|
||||
branches: ["development"]
|
||||
workflow_dispatch:
|
||||
branches: ["main"]
|
||||
branches: ["development"]
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
80
.github/workflows/hero_build_all.yml
vendored
Normal file
80
.github/workflows/hero_build_all.yml
vendored
Normal file
@@ -0,0 +1,80 @@
|
||||
name: Build Hero on Linux & Run tests
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: ["main","development"]
|
||||
workflow_dispatch:
|
||||
branches: ["main","development"]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
strategy:
|
||||
matrix:
|
||||
include:
|
||||
- target: x86_64-unknown-linux-musl
|
||||
os: ubuntu-latest
|
||||
short-name: linux-i64
|
||||
- target: aarch64-unknown-linux-musl
|
||||
os: ubuntu-latest
|
||||
short-name: linux-arm64
|
||||
- target: aarch64-apple-darwin
|
||||
os: macos-latest
|
||||
short-name: macos-arm64
|
||||
- target: x86_64-apple-darwin
|
||||
os: macos-13
|
||||
short-name: macos-i64
|
||||
runs-on: ${{ matrix.os }}
|
||||
steps:
|
||||
- run: echo "🎉 The job was automatically triggered by a ${{ github.event_name }} event."
|
||||
- run: echo "🐧 This job is now running on a ${{ runner.os }} server hosted by GitHub!"
|
||||
- run: echo "🔎 The name of your branch is ${{ github.ref_name }} and your repository is ${{ github.repository }}."
|
||||
|
||||
- name: Check out repository code
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Setup V & Herolib
|
||||
run: ./install_v.sh --herolib
|
||||
|
||||
- name: Do all the basic tests
|
||||
run: ./test_basic.vsh
|
||||
|
||||
- name: Build Hero
|
||||
run: |
|
||||
v -w -d use_openssl -enable-globals cli/hero.v -o cli/hero-${{ matrix.target }}
|
||||
|
||||
- name: Upload
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: hero-${{ matrix.target }}
|
||||
path: cli/hero-${{ matrix.target }}
|
||||
|
||||
release_hero:
|
||||
needs: upload
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: write
|
||||
|
||||
steps:
|
||||
- name: Check out repository code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Download Artifacts
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
path: cli/bins
|
||||
merge-multiple: true
|
||||
|
||||
- name: Release
|
||||
uses: softprops/action-gh-release@v1
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
tag_name: ${{ github.ref }}
|
||||
name: Release ${{ github.ref_name }}
|
||||
draft: false
|
||||
fail_on_unmatched_files: true
|
||||
# body: ${{ steps.changelog.outputs.changelog }}
|
||||
files: cli/bins/*
|
||||
73
.github/workflows/hero_build_linux.yml
vendored
73
.github/workflows/hero_build_linux.yml
vendored
@@ -15,15 +15,6 @@ jobs:
|
||||
- target: x86_64-unknown-linux-musl
|
||||
os: ubuntu-latest
|
||||
short-name: linux-i64
|
||||
# - target: aarch64-unknown-linux-musl
|
||||
# os: ubuntu-latest
|
||||
# short-name: linux-arm64
|
||||
# - target: aarch64-apple-darwin
|
||||
# os: macos-latest
|
||||
# short-name: macos-arm64
|
||||
# - target: x86_64-apple-darwin
|
||||
# os: macos-13
|
||||
# short-name: macos-i64
|
||||
runs-on: ${{ matrix.os }}
|
||||
steps:
|
||||
- run: echo "🎉 The job was automatically triggered by a ${{ github.event_name }} event."
|
||||
@@ -33,65 +24,9 @@ jobs:
|
||||
- name: Check out repository code
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Setup Vlang
|
||||
run: |
|
||||
git clone --depth=1 https://github.com/vlang/v
|
||||
cd v
|
||||
make
|
||||
sudo ./v symlink
|
||||
cd ..
|
||||
|
||||
- name: Setup Herolib
|
||||
run: |
|
||||
mkdir -p ~/.vmodules/freeflowuniverse
|
||||
ln -s $GITHUB_WORKSPACE/lib ~/.vmodules/freeflowuniverse/herolib
|
||||
|
||||
echo "Installing secp256k1..."
|
||||
# Install build dependencies
|
||||
sudo apt-get install -y build-essential wget autoconf libtool
|
||||
|
||||
# Download and extract secp256k1
|
||||
cd /tmp
|
||||
wget https://github.com/bitcoin-core/secp256k1/archive/refs/tags/v0.3.2.tar.gz
|
||||
tar -xvf v0.3.2.tar.gz
|
||||
|
||||
# Build and install
|
||||
cd secp256k1-0.3.2/
|
||||
./autogen.sh
|
||||
./configure
|
||||
make -j 5
|
||||
sudo make install
|
||||
|
||||
# Cleanup
|
||||
rm -rf secp256k1-0.3.2 v0.3.2.tar.gz
|
||||
|
||||
echo "secp256k1 installation complete!"
|
||||
|
||||
- name: Install and Start Redis
|
||||
run: |
|
||||
# Import Redis GPG key
|
||||
curl -fsSL https://packages.redis.io/gpg | sudo gpg --dearmor -o /usr/share/keyrings/redis-archive-keyring.gpg
|
||||
# Add Redis repository
|
||||
echo "deb [signed-by=/usr/share/keyrings/redis-archive-keyring.gpg] https://packages.redis.io/deb $(lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/redis.list
|
||||
# Install Redis
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y redis
|
||||
|
||||
# Start Redis
|
||||
redis-server --daemonize yes
|
||||
|
||||
# Print versions
|
||||
redis-cli --version
|
||||
redis-server --version
|
||||
|
||||
- name: Build Hero
|
||||
run: |
|
||||
v -cg -enable-globals -w -n cli/hero.v
|
||||
- name: Setup V & Herolib
|
||||
run: ./install_v.sh --herolib
|
||||
|
||||
- name: Do all the basic tests
|
||||
run: |
|
||||
./test_basic.vsh
|
||||
env:
|
||||
LIVEKIT_API_KEY: ${{secrets.LIVEKIT_API_KEY}}
|
||||
LIVEKIT_API_SECRET: ${{secrets.LIVEKIT_API_SECRET}}
|
||||
LIVEKIT_URL: ${{secrets.LIVEKIT_URL}}
|
||||
run: ./test_basic.vsh
|
||||
|
||||
|
||||
@@ -31,7 +31,7 @@ fn do() ! {
|
||||
mut cmd := Command{
|
||||
name: 'hero'
|
||||
description: 'Your HERO toolset.'
|
||||
version: '2.0.5'
|
||||
version: '2.0.6'
|
||||
}
|
||||
|
||||
// herocmds.cmd_run_add_flags(mut cmd)
|
||||
|
||||
24
examples/clients/mail.vsh
Executable file
24
examples/clients/mail.vsh
Executable file
@@ -0,0 +1,24 @@
|
||||
#!/usr/bin/env -S v -n -w -gc none -cc tcc -d use_openssl -enable-globals run
|
||||
|
||||
|
||||
import freeflowuniverse.herolib.clients. mailclient
|
||||
|
||||
|
||||
//remove the previous one, otherwise the env variables are not read
|
||||
mailclient.config_delete(name:"test")!
|
||||
|
||||
// env variables which need to be set are:
|
||||
// - MAIL_FROM=...
|
||||
// - MAIL_PASSWORD=...
|
||||
// - MAIL_PORT=465
|
||||
// - MAIL_SERVER=...
|
||||
// - MAIL_USERNAME=...
|
||||
|
||||
|
||||
mut client:= mailclient.get(name:"test")!
|
||||
|
||||
println(client)
|
||||
|
||||
client.send(subject:'this is a test',to:'kristof@incubaid.com',body:'
|
||||
this is my email content
|
||||
')!
|
||||
45
examples/clients/psql.vsh
Executable file
45
examples/clients/psql.vsh
Executable file
@@ -0,0 +1,45 @@
|
||||
#!/usr/bin/env -S v -n -w -gc none -cc tcc -d use_openssl -enable-globals run
|
||||
|
||||
import freeflowuniverse.herolib.core
|
||||
import freeflowuniverse.herolib.clients.postgresql_client
|
||||
|
||||
|
||||
// Configure PostgreSQL client
|
||||
heroscript := "
|
||||
!!postgresql_client.configure
|
||||
name:'test'
|
||||
user: 'postgres'
|
||||
port: 5432
|
||||
host: 'localhost'
|
||||
password: '1234'
|
||||
dbname: 'postgres'
|
||||
"
|
||||
|
||||
// Process the heroscript configuration
|
||||
postgresql_client.play(heroscript: heroscript)!
|
||||
|
||||
// Get the configured client
|
||||
mut db_client := postgresql_client.get(name: "test")!
|
||||
|
||||
// Check if test database exists, create if not
|
||||
if !db_client.db_exists('test')! {
|
||||
println('Creating database test...')
|
||||
db_client.db_create('test')!
|
||||
}
|
||||
|
||||
// Switch to test database
|
||||
db_client.dbname = 'test'
|
||||
|
||||
// Create table if not exists
|
||||
create_table_sql := "CREATE TABLE IF NOT EXISTS users (
|
||||
id SERIAL PRIMARY KEY,
|
||||
name VARCHAR(100) NOT NULL,
|
||||
email VARCHAR(255) UNIQUE NOT NULL,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
)"
|
||||
|
||||
println('Creating table users if not exists...')
|
||||
db_client.exec(create_table_sql)!
|
||||
|
||||
println('Database and table setup completed successfully!')
|
||||
|
||||
1
examples/data/.gitignore
vendored
Normal file
1
examples/data/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
cache
|
||||
Binary file not shown.
30
examples/data/heroencoder_simple.vsh
Executable file
30
examples/data/heroencoder_simple.vsh
Executable file
@@ -0,0 +1,30 @@
|
||||
#!/usr/bin/env -S v -n -w -gc none -cc tcc -d use_openssl -enable-globals run
|
||||
|
||||
import freeflowuniverse.herolib.data.encoderhero
|
||||
import freeflowuniverse.herolib.core.base
|
||||
import time
|
||||
|
||||
struct Person {
|
||||
mut:
|
||||
name string
|
||||
age int = 20
|
||||
birthday time.Time
|
||||
}
|
||||
|
||||
mut person := Person{
|
||||
name: 'Bob'
|
||||
birthday: time.now()
|
||||
}
|
||||
heroscript := encoderhero.encode[Person](person)!
|
||||
|
||||
println(heroscript)
|
||||
|
||||
person2 := encoderhero.decode[Person](heroscript)!
|
||||
println(person2)
|
||||
|
||||
//show that it doesn't matter which action & method is used
|
||||
heroscript2:="!!a.b name:Bob age:20 birthday:'2025-02-06 09:57:30'"
|
||||
person3 := encoderhero.decode[Person](heroscript)!
|
||||
|
||||
println(person3)
|
||||
|
||||
37
examples/data/jsonexample.vsh
Executable file
37
examples/data/jsonexample.vsh
Executable file
@@ -0,0 +1,37 @@
|
||||
#!/usr/bin/env -S v -n -w -gc none -cc tcc -d use_openssl -enable-globals run
|
||||
|
||||
|
||||
import json
|
||||
|
||||
enum JobTitle {
|
||||
manager
|
||||
executive
|
||||
worker
|
||||
}
|
||||
|
||||
struct Employee {
|
||||
mut:
|
||||
name string
|
||||
family string @[json: '-'] // this field will be skipped
|
||||
age int
|
||||
salary f32
|
||||
title JobTitle @[json: 'ETitle'] // the key for this field will be 'ETitle', not 'title'
|
||||
notes string @[omitempty] // the JSON property is not created if the string is equal to '' (an empty string).
|
||||
// TODO: document @[raw]
|
||||
}
|
||||
|
||||
x := Employee{'Peter', 'Begins', 28, 95000.5, .worker, ''}
|
||||
println(x)
|
||||
s := json.encode(x)
|
||||
println('JSON encoding of employee x: ${s}')
|
||||
assert s == '{"name":"Peter","age":28,"salary":95000.5,"ETitle":"worker"}'
|
||||
mut y := json.decode(Employee, s)!
|
||||
assert y != x
|
||||
assert y.family == ''
|
||||
y.family = 'Begins'
|
||||
assert y == x
|
||||
println(y)
|
||||
ss := json.encode(y)
|
||||
println('JSON encoding of employee y: ${ss}')
|
||||
assert ss == s
|
||||
|
||||
@@ -1,9 +1,28 @@
|
||||
#!/usr/bin/env -S v -n -w -cg -d use_openssl -enable-globals run
|
||||
|
||||
import freeflowuniverse.herolib.clients.postgresql_client
|
||||
import freeflowuniverse.herolib.data.location
|
||||
|
||||
// Configure PostgreSQL client
|
||||
heroscript := "
|
||||
!!postgresql_client.configure
|
||||
name:'test'
|
||||
user: 'postgres'
|
||||
port: 5432
|
||||
host: 'localhost'
|
||||
password: '1234'
|
||||
dbname: 'postgres'
|
||||
"
|
||||
|
||||
// Process the heroscript configuration
|
||||
postgresql_client.play(heroscript: heroscript)!
|
||||
|
||||
// Get the configured client
|
||||
mut db_client := postgresql_client.get(name: "test")!
|
||||
|
||||
|
||||
// Create a new location instance
|
||||
mut loc := location.new(false) or { panic(err) }
|
||||
mut loc := location.new(mut db_client, false) or { panic(err) }
|
||||
println('Location database initialized')
|
||||
|
||||
// Initialize the database (downloads and imports data)
|
||||
|
||||
@@ -1,10 +1,28 @@
|
||||
#!/usr/bin/env -S v -n -w -gc none -cc tcc -d use_openssl -enable-globals run
|
||||
|
||||
|
||||
import freeflowuniverse.herolib.clients.postgresql_client
|
||||
import freeflowuniverse.herolib.data.location
|
||||
|
||||
// Configure PostgreSQL client
|
||||
heroscript := "
|
||||
!!postgresql_client.configure
|
||||
name:'test'
|
||||
user: 'postgres'
|
||||
port: 5432
|
||||
host: 'localhost'
|
||||
password: '1234'
|
||||
dbname: 'postgres'
|
||||
"
|
||||
|
||||
// Process the heroscript configuration
|
||||
postgresql_client.play(heroscript: heroscript)!
|
||||
|
||||
// Get the configured client
|
||||
mut db_client := postgresql_client.get(name: "test")!
|
||||
|
||||
|
||||
// Create a new location instance
|
||||
mut loc := location.new(false) or { panic(err) }
|
||||
mut loc := location.new(mut db_client, false) or { panic(err) }
|
||||
println('Location database initialized')
|
||||
|
||||
// Initialize the database (downloads and imports data)
|
||||
|
||||
@@ -2,33 +2,14 @@
|
||||
|
||||
import freeflowuniverse.herolib.installers.infra.gitea as gitea_installer
|
||||
|
||||
// First of all, we need to set the gitea configuration
|
||||
// heroscript := "
|
||||
// !!gitea.configure
|
||||
// name:'default'
|
||||
// version:'1.22.6'
|
||||
// path: '/var/lib/git'
|
||||
// passwd: '12345678'
|
||||
// postgresql_name: 'default'
|
||||
// mail_from: 'git@meet.tf'
|
||||
// smtp_addr: 'smtp-relay.brevo.com'
|
||||
// smtp_login: 'admin'
|
||||
// smtp_port: 587
|
||||
// smtp_passwd: '12345678'
|
||||
// domain: 'meet.tf'
|
||||
// jwt_secret: ''
|
||||
// lfs_jwt_secret: ''
|
||||
// internal_token: ''
|
||||
// secret_key: ''
|
||||
// "
|
||||
|
||||
// gitea_installer.play(
|
||||
// name: 'default'
|
||||
// heroscript: heroscript
|
||||
// )!
|
||||
mut installer:= gitea_installer.get(name:'test')!
|
||||
|
||||
// Then we need to get an instace of the installer and call the install
|
||||
mut gitea := gitea_installer.get()!
|
||||
// println('gitea configs: ${gitea}')
|
||||
gitea.install()!
|
||||
gitea.start()!
|
||||
//if you want to configure using heroscript
|
||||
gitea_installer.play(heroscript:"
|
||||
!!gitea.configure name:test
|
||||
passwd:'something'
|
||||
domain: 'docs.info.com'
|
||||
")!
|
||||
|
||||
installer.start()!
|
||||
|
||||
@@ -4,7 +4,7 @@ import freeflowuniverse.herolib.osal.notifier
|
||||
import os
|
||||
import time
|
||||
|
||||
fn on_file_change(event notifier.NotifyEvent, path string) {
|
||||
fn on_file_change(event notifier.NotifyEvent, path string, args map[string]string) {
|
||||
match event {
|
||||
.create { println('File created: ${path}') }
|
||||
.modify { println('File modified: ${path}') }
|
||||
|
||||
@@ -17,6 +17,20 @@ else
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Check for existing hero installations
|
||||
existing_hero=$(which hero 2>/dev/null || true)
|
||||
if [ ! -z "$existing_hero" ]; then
|
||||
echo "Found existing hero installation at: $existing_hero"
|
||||
if [ -w "$(dirname "$existing_hero")" ]; then
|
||||
echo "Removing existing hero installation..."
|
||||
rm "$existing_hero" || { echo "Error: Failed to remove existing hero binary at $existing_hero"; exit 1; }
|
||||
else
|
||||
echo "Error: Cannot remove existing hero installation at $existing_hero (permission denied)"
|
||||
echo "Please remove it manually with sudo and run this script again"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
if [[ "${OSNAME}" == "darwin"* ]]; then
|
||||
# Check if /usr/local/bin/hero exists and remove it
|
||||
if [ -f /usr/local/bin/hero ]; then
|
||||
|
||||
206
install_v.sh
206
install_v.sh
@@ -1,4 +1,3 @@
|
||||
|
||||
#!/bin/bash -e
|
||||
|
||||
# Help function
|
||||
@@ -93,7 +92,12 @@ function package_check_install {
|
||||
function package_install {
|
||||
local command_name="$1"
|
||||
if [[ "${OSNAME}" == "ubuntu" ]]; then
|
||||
apt -o Dpkg::Options::="--force-confold" -o Dpkg::Options::="--force-confdef" install $1 -q -y --allow-downgrades --allow-remove-essential
|
||||
if is_github_actions; then
|
||||
sudo apt -o Dpkg::Options::="--force-confold" -o Dpkg::Options::="--force-confdef" install $1 -q -y --allow-downgrades --allow-remove-essential
|
||||
else
|
||||
apt -o Dpkg::Options::="--force-confold" -o Dpkg::Options::="--force-confdef" install $1 -q -y --allow-downgrades --allow-remove-essential
|
||||
fi
|
||||
|
||||
elif [[ "${OSNAME}" == "darwin"* ]]; then
|
||||
brew install $command_name
|
||||
elif [[ "${OSNAME}" == "alpine"* ]]; then
|
||||
@@ -107,7 +111,15 @@ function package_install {
|
||||
}
|
||||
|
||||
is_github_actions() {
|
||||
[ -d "/home/runner" ] || [ -d "$HOME/runner" ]
|
||||
# echo "Checking GitHub Actions environment..."
|
||||
# echo "GITHUB_ACTIONS=${GITHUB_ACTIONS:-not set}"
|
||||
if [ -n "$GITHUB_ACTIONS" ] && [ "$GITHUB_ACTIONS" = "true" ]; then
|
||||
echo "Running in GitHub Actions: true"
|
||||
return 0
|
||||
else
|
||||
echo "Running in GitHub Actions: false"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
|
||||
@@ -155,12 +167,12 @@ function os_update {
|
||||
fi
|
||||
export TERM=xterm
|
||||
export DEBIAN_FRONTEND=noninteractive
|
||||
dpkg --configure -a
|
||||
apt update -y
|
||||
sudo dpkg --configure -a
|
||||
sudo apt update -y
|
||||
if is_github_actions; then
|
||||
echo "** IN GITHUB ACTIONS, DON'T DO UPDATE"
|
||||
else
|
||||
set +e
|
||||
else
|
||||
set +e
|
||||
echo "** UPDATE"
|
||||
apt-mark hold grub-efi-amd64-signed
|
||||
set -e
|
||||
@@ -198,9 +210,9 @@ function os_update {
|
||||
echo 'builduser ALL=(ALL) NOPASSWD: ALL' | tee /etc/sudoers.d/builduser
|
||||
fi
|
||||
|
||||
if [[ -n "${DEBUG}" ]]; then
|
||||
execute_with_marker "paru_install" paru_install
|
||||
fi
|
||||
# if [[ -n "${DEBUG}" ]]; then
|
||||
# execute_with_marker "paru_install" paru_install
|
||||
# fi
|
||||
fi
|
||||
echo ' - os update done'
|
||||
}
|
||||
@@ -235,7 +247,7 @@ function install_secp256k1 {
|
||||
brew install secp256k1
|
||||
elif [[ "${OSNAME}" == "ubuntu" ]]; then
|
||||
# Install build dependencies
|
||||
apt-get install -y build-essential wget autoconf libtool
|
||||
package_install "build-essential wget autoconf libtool"
|
||||
|
||||
# Download and extract secp256k1
|
||||
cd "${DIR_BUILD}"
|
||||
@@ -247,8 +259,12 @@ function install_secp256k1 {
|
||||
./autogen.sh
|
||||
./configure
|
||||
make -j 5
|
||||
make install
|
||||
|
||||
if is_github_actions; then
|
||||
sudo make install
|
||||
else
|
||||
make install
|
||||
fi
|
||||
|
||||
# Cleanup
|
||||
cd ..
|
||||
rm -rf secp256k1-0.3.2 v0.3.2.tar.gz
|
||||
@@ -300,10 +316,33 @@ remove_all() {
|
||||
|
||||
# Function to check if a service is running and start it if needed
|
||||
check_and_start_redis() {
|
||||
|
||||
|
||||
|
||||
# Normal service management for non-container environments
|
||||
if [[ "${OSNAME}" == "ubuntu" ]] || [[ "${OSNAME}" == "debian" ]]; then
|
||||
|
||||
# Handle Redis installation for GitHub Actions environment
|
||||
if is_github_actions; then
|
||||
|
||||
# Import Redis GPG key
|
||||
curl -fsSL https://packages.redis.io/gpg | sudo gpg --dearmor -o /usr/share/keyrings/redis-archive-keyring.gpg
|
||||
# Add Redis repository
|
||||
echo "deb [signed-by=/usr/share/keyrings/redis-archive-keyring.gpg] https://packages.redis.io/deb $(lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/redis.list
|
||||
# Install Redis
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y redis
|
||||
|
||||
# Start Redis
|
||||
redis-server --daemonize yes
|
||||
|
||||
# Print versions
|
||||
redis-cli --version
|
||||
redis-server --version
|
||||
|
||||
return
|
||||
fi
|
||||
|
||||
# Check if running inside a container
|
||||
if grep -q "/docker/" /proc/1/cgroup || [ ! -d "/run/systemd/system" ]; then
|
||||
echo "Running inside a container. Starting redis directly."
|
||||
@@ -362,6 +401,74 @@ check_and_start_redis() {
|
||||
fi
|
||||
}
|
||||
|
||||
v-install() {
|
||||
|
||||
# Only clone and install if directory doesn't exist
|
||||
if [ ! -d ~/code/v ]; then
|
||||
echo "Installing V..."
|
||||
mkdir -p ~/_code
|
||||
cd ~/_code
|
||||
git clone --depth=1 https://github.com/vlang/v
|
||||
cd v
|
||||
make
|
||||
sudo ./v symlink
|
||||
fi
|
||||
|
||||
# Verify v is in path
|
||||
if ! command_exists v; then
|
||||
echo "Error: V installation failed or not in PATH"
|
||||
echo "Please ensure ~/code/v is in your PATH"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "V installation successful!"
|
||||
|
||||
}
|
||||
|
||||
|
||||
v-analyzer() {
|
||||
|
||||
# Install v-analyzer if requested
|
||||
if [ "$INSTALL_ANALYZER" = true ]; then
|
||||
echo "Installing v-analyzer..."
|
||||
v download -RD https://raw.githubusercontent.com/vlang/v-analyzer/main/install.vsh
|
||||
|
||||
# Check if v-analyzer bin directory exists
|
||||
if [ ! -d "$HOME/.config/v-analyzer/bin" ]; then
|
||||
echo "Error: v-analyzer bin directory not found at $HOME/.config/v-analyzer/bin"
|
||||
echo "Please ensure v-analyzer was installed correctly"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "v-analyzer installation successful!"
|
||||
fi
|
||||
|
||||
# Add v-analyzer to PATH if installed
|
||||
if [ -d "$HOME/.config/v-analyzer/bin" ]; then
|
||||
V_ANALYZER_PATH='export PATH="$PATH:$HOME/.config/v-analyzer/bin"'
|
||||
|
||||
# Function to add path to rc file if not present
|
||||
add_to_rc() {
|
||||
local RC_FILE="$1"
|
||||
if [ -f "$RC_FILE" ]; then
|
||||
if ! grep -q "v-analyzer/bin" "$RC_FILE"; then
|
||||
echo "" >> "$RC_FILE"
|
||||
echo "$V_ANALYZER_PATH" >> "$RC_FILE"
|
||||
echo "Added v-analyzer to $RC_FILE"
|
||||
else
|
||||
echo "v-analyzer path already exists in $RC_FILE"
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
# Add to both .zshrc and .bashrc if they exist
|
||||
add_to_rc ~/.zshrc
|
||||
if [ "$(uname)" = "Darwin" ] && [ -f ~/.bashrc ]; then
|
||||
add_to_rc ~/.bashrc
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
|
||||
|
||||
# Handle remove if requested
|
||||
@@ -390,72 +497,15 @@ if [ "$RESET" = true ] || ! command_exists v; then
|
||||
# Install secp256k1
|
||||
install_secp256k1
|
||||
|
||||
# Only clone and install if directory doesn't exist
|
||||
if [ ! -d ~/code/v ]; then
|
||||
echo "Installing V..."
|
||||
mkdir -p ~/_code
|
||||
cd ~/_code
|
||||
git clone --depth=1 https://github.com/vlang/v
|
||||
cd v
|
||||
make
|
||||
sudo ./v symlink
|
||||
v-install
|
||||
|
||||
# Only install v-analyzer if not in GitHub Actions environment
|
||||
if ! is_github_actions; then
|
||||
v-analyzer
|
||||
fi
|
||||
|
||||
# Verify v is in path
|
||||
if ! command_exists v; then
|
||||
echo "Error: V installation failed or not in PATH"
|
||||
echo "Please ensure ~/code/v is in your PATH"
|
||||
exit 1
|
||||
fi
|
||||
echo "V installation successful!"
|
||||
fi
|
||||
|
||||
# Install v-analyzer if requested
|
||||
if [ "$INSTALL_ANALYZER" = true ]; then
|
||||
echo "Installing v-analyzer..."
|
||||
v download -RD https://raw.githubusercontent.com/vlang/v-analyzer/main/install.vsh
|
||||
|
||||
# Check if v-analyzer bin directory exists
|
||||
if [ ! -d "$HOME/.config/v-analyzer/bin" ]; then
|
||||
echo "Error: v-analyzer bin directory not found at $HOME/.config/v-analyzer/bin"
|
||||
echo "Please ensure v-analyzer was installed correctly"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "v-analyzer installation successful!"
|
||||
fi
|
||||
|
||||
# Add v-analyzer to PATH if installed
|
||||
if [ -d "$HOME/.config/v-analyzer/bin" ]; then
|
||||
V_ANALYZER_PATH='export PATH="$PATH:$HOME/.config/v-analyzer/bin"'
|
||||
|
||||
# Function to add path to rc file if not present
|
||||
add_to_rc() {
|
||||
local RC_FILE="$1"
|
||||
if [ -f "$RC_FILE" ]; then
|
||||
if ! grep -q "v-analyzer/bin" "$RC_FILE"; then
|
||||
echo "" >> "$RC_FILE"
|
||||
echo "$V_ANALYZER_PATH" >> "$RC_FILE"
|
||||
echo "Added v-analyzer to $RC_FILE"
|
||||
else
|
||||
echo "v-analyzer path already exists in $RC_FILE"
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
# Add to both .zshrc and .bashrc if they exist
|
||||
add_to_rc ~/.zshrc
|
||||
if [ "$(uname)" = "Darwin" ] && [ -f ~/.bashrc ]; then
|
||||
add_to_rc ~/.bashrc
|
||||
fi
|
||||
fi
|
||||
|
||||
# Final verification
|
||||
if ! command_exists v; then
|
||||
echo "Error: V is not accessible in PATH"
|
||||
echo "Please add ~/code/v to your PATH and try again"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
check_and_start_redis
|
||||
|
||||
@@ -465,9 +515,9 @@ if [ "$HEROLIB" = true ]; then
|
||||
fi
|
||||
|
||||
|
||||
# if [ "$INSTALL_ANALYZER" = true ]; then
|
||||
# echo "Run 'source ~/.bashrc' or 'source ~/.zshrc' to update PATH for v-analyzer"
|
||||
# fi
|
||||
if [ "$INSTALL_ANALYZER" = true ]; then
|
||||
echo "Run 'source ~/.bashrc' or 'source ~/.zshrc' to update PATH for v-analyzer"
|
||||
fi
|
||||
|
||||
|
||||
echo "Installation complete!"
|
||||
|
||||
@@ -1,107 +0,0 @@
|
||||
module mailclient
|
||||
|
||||
import freeflowuniverse.herolib.core.base
|
||||
// import freeflowuniverse.herolib.core.playbook
|
||||
|
||||
// __global (
|
||||
// mailclient_global map[string]&MailClient
|
||||
// mailclient_default string
|
||||
// )
|
||||
|
||||
// /////////FACTORY
|
||||
|
||||
// @[params]
|
||||
// pub struct ArgsGet {
|
||||
// pub mut:
|
||||
// name string = 'default'
|
||||
// }
|
||||
|
||||
// fn args_get(args_ ArgsGet) ArgsGet {
|
||||
// mut args := args_
|
||||
// if args.name == '' {
|
||||
// args.name = mailclient_default
|
||||
// }
|
||||
// if args.name == '' {
|
||||
// args.name = 'default'
|
||||
// }
|
||||
// return args
|
||||
// }
|
||||
|
||||
// pub fn get(args_ ArgsGet) !&MailClient {
|
||||
// mut args := args_get(args_)
|
||||
// if args.name !in mailclient_global {
|
||||
// if !config_exists() {
|
||||
// if default {
|
||||
// config_save()!
|
||||
// }
|
||||
// }
|
||||
// config_load()!
|
||||
// }
|
||||
// return mailclient_global[args.name] or { panic('bug') }
|
||||
// }
|
||||
|
||||
// // switch instance to be used for mailclient
|
||||
// pub fn switch(name string) {
|
||||
// mailclient_default = name
|
||||
// }
|
||||
|
||||
fn config_exists(args_ ArgsGet) bool {
|
||||
mut args := args_get(args_)
|
||||
mut context := base.context() or { panic('bug') }
|
||||
return context.hero_config_exists('mailclient', args.name)
|
||||
}
|
||||
|
||||
// fn config_load(args_ ArgsGet) ! {
|
||||
// mut args := args_get(args_)
|
||||
// mut context := base.context()!
|
||||
// mut heroscript := context.hero_config_get('mailclient', args.name)!
|
||||
// play(heroscript: heroscript)!
|
||||
// }
|
||||
|
||||
// fn config_save(args_ ArgsGet) ! {
|
||||
// mut args := args_get(args_)
|
||||
// mut context := base.context()!
|
||||
// context.hero_config_set('mailclient', args.name, heroscript_default())!
|
||||
// }
|
||||
|
||||
// fn set(o MailClient) ! {
|
||||
// mut o2 := obj_init(o)!
|
||||
// mailclient_global['default'] = &o2
|
||||
// }
|
||||
|
||||
// @[params]
|
||||
// pub struct InstallPlayArgs {
|
||||
// pub mut:
|
||||
// name string = 'default'
|
||||
// heroscript string // if filled in then plbook will be made out of it
|
||||
// plbook ?playbook.PlayBook
|
||||
// reset bool
|
||||
// start bool
|
||||
// stop bool
|
||||
// restart bool
|
||||
// delete bool
|
||||
// configure bool // make sure there is at least one installed
|
||||
// }
|
||||
|
||||
// pub fn play(args_ InstallPlayArgs) ! {
|
||||
// mut args := args_
|
||||
// println('debguzo1')
|
||||
// mut plbook := args.plbook or {
|
||||
// println('debguzo2')
|
||||
// heroscript := if args.heroscript == '' {
|
||||
// heroscript_default()
|
||||
// } else {
|
||||
// args.heroscript
|
||||
// }
|
||||
// playbook.new(text: heroscript)!
|
||||
// }
|
||||
|
||||
// mut install_actions := plbook.find(filter: 'mailclient.configure')!
|
||||
// println('debguzo3 ${install_actions}')
|
||||
// if install_actions.len > 0 {
|
||||
// for install_action in install_actions {
|
||||
// mut p := install_action.params
|
||||
// cfg_play(p)!
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
@@ -1,103 +1,127 @@
|
||||
|
||||
module mailclient
|
||||
|
||||
import freeflowuniverse.herolib.core.base
|
||||
import freeflowuniverse.herolib.core.playbook
|
||||
import freeflowuniverse.herolib.ui.console
|
||||
import freeflowuniverse.herolib.data.encoderhero
|
||||
|
||||
|
||||
__global (
|
||||
mailclient_global map[string]&MailClient
|
||||
mailclient_default string
|
||||
mailclient_global map[string]&MailClient
|
||||
mailclient_default string
|
||||
)
|
||||
|
||||
/////////FACTORY
|
||||
|
||||
@[params]
|
||||
pub struct ArgsGet {
|
||||
pub struct ArgsGet{
|
||||
pub mut:
|
||||
name string
|
||||
name string
|
||||
}
|
||||
|
||||
fn args_get(args_ ArgsGet) ArgsGet {
|
||||
mut model := args_
|
||||
if model.name == '' {
|
||||
model.name = mailclient_default
|
||||
}
|
||||
if model.name == '' {
|
||||
model.name = 'default'
|
||||
}
|
||||
return model
|
||||
fn args_get (args_ ArgsGet) ArgsGet {
|
||||
mut args:=args_
|
||||
if args.name == ""{
|
||||
args.name = mailclient_default
|
||||
}
|
||||
if args.name == ""{
|
||||
args.name = "default"
|
||||
}
|
||||
return args
|
||||
}
|
||||
|
||||
pub fn get(args_ ArgsGet) !&MailClient {
|
||||
mut args := args_get(args_)
|
||||
if args.name !in mailclient_global {
|
||||
if args.name == 'default' {
|
||||
if !config_exists(args) {
|
||||
if default {
|
||||
mut context := base.context() or { panic('bug') }
|
||||
context.hero_config_set('mailclient', args.name, heroscript_default())!
|
||||
}
|
||||
}
|
||||
load(args)!
|
||||
}
|
||||
}
|
||||
return mailclient_global[args.name] or {
|
||||
println(mailclient_global)
|
||||
panic('could not get config for ${args.name} with name:${args.name}')
|
||||
}
|
||||
pub fn get(args_ ArgsGet) !&MailClient {
|
||||
mut args := args_get(args_)
|
||||
if !(args.name in mailclient_global) {
|
||||
if ! config_exists(args){
|
||||
config_save(args)!
|
||||
}
|
||||
config_load(args)!
|
||||
}
|
||||
return mailclient_global[args.name] or {
|
||||
println(mailclient_global)
|
||||
//bug if we get here because should be in globals
|
||||
panic("could not get config for mailclient with name, is bug:${args.name}")
|
||||
}
|
||||
}
|
||||
|
||||
// set the model in mem and the config on the filesystem
|
||||
pub fn set(o MailClient) ! {
|
||||
mut o2 := obj_init(o)!
|
||||
mailclient_global[o.name] = &o2
|
||||
mailclient_default = o.name
|
||||
|
||||
|
||||
pub fn config_exists(args_ ArgsGet) bool {
|
||||
mut args := args_get(args_)
|
||||
mut context:=base.context() or { panic("bug") }
|
||||
return context.hero_config_exists("mailclient",args.name)
|
||||
}
|
||||
|
||||
// check we find the config on the filesystem
|
||||
pub fn exists(args_ ArgsGet) bool {
|
||||
mut model := args_get(args_)
|
||||
mut context := base.context() or { panic('bug') }
|
||||
return context.hero_config_exists('mailclient', model.name)
|
||||
pub fn config_load(args_ ArgsGet) ! {
|
||||
mut args := args_get(args_)
|
||||
mut context:=base.context()!
|
||||
mut heroscript := context.hero_config_get("mailclient",args.name)!
|
||||
play(heroscript:heroscript)!
|
||||
}
|
||||
|
||||
// load the config error if it doesn't exist
|
||||
pub fn load(args_ ArgsGet) ! {
|
||||
mut model := args_get(args_)
|
||||
mut context := base.context()!
|
||||
mut heroscript := context.hero_config_get('mailclient', model.name)!
|
||||
play(heroscript: heroscript)!
|
||||
pub fn config_save(args_ ArgsGet) ! {
|
||||
mut args := args_get(args_)
|
||||
mut context:=base.context()!
|
||||
context.hero_config_set("mailclient",args.name,heroscript_default(instance:args.name)!)!
|
||||
}
|
||||
|
||||
|
||||
pub fn config_delete(args_ ArgsGet) ! {
|
||||
mut args := args_get(args_)
|
||||
mut context:=base.context()!
|
||||
context.hero_config_delete("mailclient",args.name)!
|
||||
}
|
||||
|
||||
fn set(o MailClient)! {
|
||||
mut o2:=obj_init(o)!
|
||||
mailclient_global[o.name] = &o2
|
||||
mailclient_default = o.name
|
||||
}
|
||||
|
||||
// // save the config to the filesystem in the context
|
||||
// pub fn save(o MailClient) ! {
|
||||
// mut context := base.context()!
|
||||
// heroscript := encoderhero.encode[MailClient](o)!
|
||||
// context.hero_config_set('mailclient', model.name, heroscript)!
|
||||
// }
|
||||
|
||||
@[params]
|
||||
pub struct PlayArgs {
|
||||
pub mut:
|
||||
heroscript string // if filled in then plbook will be made out of it
|
||||
plbook ?playbook.PlayBook
|
||||
reset bool
|
||||
heroscript string //if filled in then plbook will be made out of it
|
||||
plbook ?playbook.PlayBook
|
||||
reset bool
|
||||
}
|
||||
|
||||
pub fn play(args_ PlayArgs) ! {
|
||||
mut model := args_
|
||||
|
||||
mut args:=args_
|
||||
|
||||
if args.heroscript == "" {
|
||||
args.heroscript = heroscript_default()!
|
||||
}
|
||||
mut plbook := args.plbook or {
|
||||
playbook.new(text: args.heroscript)!
|
||||
}
|
||||
|
||||
mut install_actions := plbook.find(filter: 'mailclient.configure')!
|
||||
if install_actions.len > 0 {
|
||||
for install_action in install_actions {
|
||||
mut p := install_action.params
|
||||
cfg_play(p)!
|
||||
}
|
||||
}
|
||||
|
||||
if model.heroscript == '' {
|
||||
model.heroscript = heroscript_default()
|
||||
}
|
||||
mut plbook := model.plbook or { playbook.new(text: model.heroscript)! }
|
||||
|
||||
mut configure_actions := plbook.find(filter: 'mailclient.configure')!
|
||||
if configure_actions.len > 0 {
|
||||
for config_action in configure_actions {
|
||||
mut p := config_action.params
|
||||
cfg_play(p)!
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
//switch instance to be used for mailclient
|
||||
pub fn switch(name string) {
|
||||
mailclient_default = name
|
||||
}
|
||||
|
||||
|
||||
//helpers
|
||||
|
||||
@[params]
|
||||
pub struct DefaultConfigArgs{
|
||||
instance string = 'default'
|
||||
}
|
||||
|
||||
@@ -1,21 +1,21 @@
|
||||
module mailclient
|
||||
|
||||
import freeflowuniverse.herolib.data.paramsparser
|
||||
import os
|
||||
|
||||
pub const version = '1.0.0'
|
||||
pub const version = '0.0.0'
|
||||
const singleton = false
|
||||
const default = true
|
||||
|
||||
pub fn heroscript_default() string {
|
||||
|
||||
pub fn heroscript_default(args DefaultConfigArgs) !string {
|
||||
mail_from := os.getenv_opt('MAIL_FROM') or { 'info@example.com' }
|
||||
mail_password := os.getenv_opt('MAIL_PASSWORD') or { 'secretpassword' }
|
||||
mail_port := (os.getenv_opt('MAIL_PORT') or { '465' }).int()
|
||||
mail_server := os.getenv_opt('MAIL_SERVER') or { 'smtp-relay.brevo.com' }
|
||||
mail_username := os.getenv_opt('MAIL_USERNAME') or { 'kristof@incubaid.com' }
|
||||
mail_username := os.getenv_opt('MAIL_USERNAME') or { 'mail@incubaid.com' }
|
||||
|
||||
heroscript := "
|
||||
!!mailclient.configure name:'default'
|
||||
!!mailclient.configure name:'${args.instance}'
|
||||
mail_from: '${mail_from}'
|
||||
mail_password: '${mail_password}'
|
||||
mail_port: ${mail_port}
|
||||
@@ -23,9 +23,10 @@ pub fn heroscript_default() string {
|
||||
mail_username: '${mail_username}'
|
||||
"
|
||||
|
||||
return heroscript
|
||||
return heroscript
|
||||
}
|
||||
|
||||
@[heap]
|
||||
pub struct MailClient {
|
||||
pub mut:
|
||||
name string = 'default'
|
||||
@@ -39,31 +40,22 @@ pub mut:
|
||||
}
|
||||
|
||||
fn cfg_play(p paramsparser.Params) ! {
|
||||
mut mycfg := MailClient{
|
||||
mut mycfg := MailClient{
|
||||
name: p.get_default('name', 'default')!
|
||||
mail_from: p.get('mail_from')!
|
||||
mail_password: p.get('mail_password')!
|
||||
mail_port: p.get_int_default('mail_port', 465)!
|
||||
mail_server: p.get('mail_server')!
|
||||
mail_username: p.get('mail_username')!
|
||||
}
|
||||
set(mycfg)!
|
||||
}
|
||||
set(mycfg)!
|
||||
}
|
||||
|
||||
|
||||
fn obj_init(obj_ MailClient)!MailClient{
|
||||
mut obj:=obj_
|
||||
return obj
|
||||
}
|
||||
|
||||
fn obj_init(obj_ MailClient) !MailClient {
|
||||
// never call get here, only thing we can do here is work on object itself
|
||||
mut obj := obj_
|
||||
return obj
|
||||
}
|
||||
|
||||
// user needs to us switch to make sure we get the right object
|
||||
pub fn configure(config MailClient) !MailClient {
|
||||
client := MailClient{
|
||||
...config
|
||||
}
|
||||
set(client)!
|
||||
return client
|
||||
// THIS IS EXAMPLE CODE AND NEEDS TO BE CHANGED
|
||||
|
||||
// implement if steps need to be done for configuration
|
||||
}
|
||||
|
||||
@@ -1,16 +1,29 @@
|
||||
# mailclient
|
||||
|
||||
|
||||
|
||||
To get started
|
||||
|
||||
```vlang
|
||||
|
||||
import freeflowuniverse.herolib.clients. mailclient
|
||||
import freeflowuniverse.herolib.clients.mailclient
|
||||
|
||||
mut client:= mailclient.get()!
|
||||
|
||||
client.send(subject:'this is a test',to:'kds@something.com,kds2@else.com',body:'
|
||||
//remove the previous one, otherwise the env variables are not read
|
||||
mailclient.config_delete(name:"test")!
|
||||
|
||||
// env variables which need to be set are:
|
||||
// - MAIL_FROM=...
|
||||
// - MAIL_PASSWORD=...
|
||||
// - MAIL_PORT=465
|
||||
// - MAIL_SERVER=...
|
||||
// - MAIL_USERNAME=...
|
||||
|
||||
|
||||
mut client:= mailclient.get(name:"test")!
|
||||
|
||||
println(client)
|
||||
|
||||
client.send(subject:'this is a test',to:'kristof@incubaid.com',body:'
|
||||
this is my email content
|
||||
')!
|
||||
|
||||
|
||||
@@ -1,56 +0,0 @@
|
||||
module postgresql_client
|
||||
|
||||
import freeflowuniverse.herolib.core.base
|
||||
import db.pg
|
||||
import freeflowuniverse.herolib.core.texttools
|
||||
import freeflowuniverse.herolib.ui.console
|
||||
|
||||
// pub struct PostgresClient {
|
||||
// base.BaseConfig
|
||||
// pub mut:
|
||||
// config Config
|
||||
// db pg.DB
|
||||
// }
|
||||
|
||||
// @[params]
|
||||
// pub struct ClientArgs {
|
||||
// pub mut:
|
||||
// instance string @[required]
|
||||
// // playargs ?play.PlayArgs
|
||||
// }
|
||||
|
||||
// pub fn get(clientargs ClientArgs) !PostgresClient {
|
||||
// // mut plargs := clientargs.playargs or {
|
||||
// // // play.PlayArgs
|
||||
// // // {
|
||||
// // // }
|
||||
// // }
|
||||
|
||||
// // mut cfg := configurator(clientargs.instance, plargs)!
|
||||
// // mut args := cfg.get()!
|
||||
|
||||
// args.instance = texttools.name_fix(args.instance)
|
||||
// if args.instance == '' {
|
||||
// args.instance = 'default'
|
||||
// }
|
||||
// // console.print_debug(args)
|
||||
// mut db := pg.connect(
|
||||
// host: args.host
|
||||
// user: args.user
|
||||
// port: args.port
|
||||
// password: args.password
|
||||
// dbname: args.dbname
|
||||
// )!
|
||||
// // console.print_debug(postgres_client)
|
||||
// return PostgresClient{
|
||||
// instance: args.instance
|
||||
// db: db
|
||||
// config: args
|
||||
// }
|
||||
// }
|
||||
|
||||
// struct LocalConfig {
|
||||
// name string
|
||||
// path string
|
||||
// passwd string
|
||||
// }
|
||||
@@ -55,7 +55,7 @@ fn obj_init(obj_ PostgresClient) !PostgresClient {
|
||||
return obj
|
||||
}
|
||||
|
||||
fn (mut self PostgresClient) db() !pg.DB {
|
||||
pub fn (mut self PostgresClient) db() !pg.DB {
|
||||
// console.print_debug(args)
|
||||
mut db := self.db_ or {
|
||||
mut db_ := pg.connect(
|
||||
|
||||
@@ -12,26 +12,49 @@ The PostgreSQL client can be configured using HeroScript. Configuration settings
|
||||
#!/usr/bin/env -S v -n -w -gc none -cc tcc -d use_openssl -enable-globals run
|
||||
|
||||
import freeflowuniverse.herolib.core
|
||||
import os
|
||||
import freeflowuniverse.herolib.clients.postgresql_client
|
||||
|
||||
|
||||
// Configure PostgreSQL client
|
||||
heroscript := "
|
||||
!!postgresql_client.configure
|
||||
name:'test'
|
||||
user: 'root'
|
||||
port: 5432
|
||||
host: 'localhost'
|
||||
password: '1234'
|
||||
dbname: 'postgres'
|
||||
name:'test'
|
||||
user: 'postgres'
|
||||
port: 5432
|
||||
host: 'localhost'
|
||||
password: '1234'
|
||||
dbname: 'postgres'
|
||||
"
|
||||
|
||||
// Process the heroscript
|
||||
postgresql_client.play(heroscript:heroscript)!
|
||||
// Process the heroscript configuration
|
||||
postgresql_client.play(heroscript: heroscript)!
|
||||
|
||||
// Get the configured client
|
||||
mut db_client := postgresql_client.get(name:"test")!
|
||||
mut db_client := postgresql_client.get(name: "test")!
|
||||
|
||||
// Check if test database exists, create if not
|
||||
if !db_client.db_exists('test')! {
|
||||
println('Creating database test...')
|
||||
db_client.db_create('test')!
|
||||
}
|
||||
|
||||
// Switch to test database
|
||||
db_client.dbname = 'test'
|
||||
|
||||
// Create table if not exists
|
||||
create_table_sql := "CREATE TABLE IF NOT EXISTS users (
|
||||
id SERIAL PRIMARY KEY,
|
||||
name VARCHAR(100) NOT NULL,
|
||||
email VARCHAR(255) UNIQUE NOT NULL,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
)"
|
||||
|
||||
println('Creating table users if not exists...')
|
||||
db_client.exec(create_table_sql)!
|
||||
|
||||
println('Database and table setup completed successfully!')
|
||||
|
||||
|
||||
println(db_client)
|
||||
```
|
||||
|
||||
### Configuration Parameters
|
||||
@@ -94,20 +117,3 @@ db_client.backup(dest: '/path/to/backup/dir')!
|
||||
|
||||
Backups are created in custom PostgreSQL format (.bak files) which can be restored using pg_restore.
|
||||
|
||||
## Default Configuration
|
||||
|
||||
If no configuration is provided, the client uses these default settings:
|
||||
|
||||
```v
|
||||
heroscript := "
|
||||
!!postgresql_client.configure
|
||||
name:'default'
|
||||
user: 'root'
|
||||
port: 5432
|
||||
host: 'localhost'
|
||||
password: ''
|
||||
dbname: 'postgres'
|
||||
"
|
||||
```
|
||||
|
||||
You can override these defaults by providing your own configuration using the HeroScript configure command.
|
||||
|
||||
@@ -138,6 +138,13 @@ pub fn (mut self Context) hero_config_set(cat string, name string, content_ stri
|
||||
config_file.write(content)!
|
||||
}
|
||||
|
||||
pub fn (mut self Context) hero_config_delete(cat string, name string) ! {
|
||||
path := '${self.path()!.path}/${cat}__${name}.yaml'
|
||||
mut config_file := pathlib.get_file(path: path)!
|
||||
config_file.delete()!
|
||||
}
|
||||
|
||||
|
||||
pub fn (mut self Context) hero_config_exists(cat string, name string) bool {
|
||||
path := '${os.home_dir()}/hero/context/${self.config.name}/${cat}__${name}.yaml'
|
||||
return os.exists(path)
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
|
||||
module ${args.name}
|
||||
|
||||
import freeflowuniverse.herolib.core.base
|
||||
import freeflowuniverse.herolib.core.playbook
|
||||
import freeflowuniverse.herolib.ui.console
|
||||
import freeflowuniverse.herolib.data.paramsparser
|
||||
|
||||
@if args.cat == .installer
|
||||
import freeflowuniverse.herolib.sysadmin.startupmanager
|
||||
@@ -27,9 +27,6 @@ pub mut:
|
||||
@if args.hasconfig
|
||||
fn args_get (args_ ArgsGet) ArgsGet {
|
||||
mut args:=args_
|
||||
if args.name == ""{
|
||||
args.name = ${args.name}_default
|
||||
}
|
||||
if args.name == ""{
|
||||
args.name = "default"
|
||||
}
|
||||
@@ -37,23 +34,55 @@ fn args_get (args_ ArgsGet) ArgsGet {
|
||||
}
|
||||
|
||||
pub fn get(args_ ArgsGet) !&${args.classname} {
|
||||
mut context:=base.context()!
|
||||
mut args := args_get(args_)
|
||||
mut obj := ${args.classname}{}
|
||||
if !(args.name in ${args.name}_global) {
|
||||
if args.name=="default"{
|
||||
if ! config_exists(args){
|
||||
if default{
|
||||
config_save(args)!
|
||||
}
|
||||
}
|
||||
config_load(args)!
|
||||
}
|
||||
if ! exists(args)!{
|
||||
set(obj)!
|
||||
}else{
|
||||
heroscript := context.hero_config_get("${args.name}",args.name)!
|
||||
mut obj:=heroscript_loads(heroscript)!
|
||||
set_in_mem(obj)!
|
||||
}
|
||||
}
|
||||
return ${args.name}_global[args.name] or {
|
||||
return ${args.name}_global[args.name] or {
|
||||
println(${args.name}_global)
|
||||
panic("could not get config for ${args.name} with name:??{args.name}")
|
||||
//bug if we get here because should be in globals
|
||||
panic("could not get config for ${args.name} with name, is bug:??{args.name}")
|
||||
}
|
||||
}
|
||||
|
||||
//register the config for the future
|
||||
pub fn set(o ${args.classname})! {
|
||||
set_in_mem(o)!
|
||||
mut context := base.context()!
|
||||
heroscript := heroscript_dumps(o)!
|
||||
context.hero_config_set("gitea", o.name, heroscript)!
|
||||
}
|
||||
|
||||
//does the config exists?
|
||||
pub fn exists(args_ ArgsGet)! {
|
||||
mut context := base.context()!
|
||||
mut args := args_get(args_)
|
||||
return context.hero_config_exists("gitea", args.name)
|
||||
}
|
||||
|
||||
pub fn delete(args_ ArgsGet)! {
|
||||
mut args := args_get(args_)
|
||||
mut context:=base.context()!
|
||||
context.hero_config_delete("${args.name}",args.name)!
|
||||
if args.name in ${args.name}_global {
|
||||
//del ${args.name}_global[args.name]
|
||||
}
|
||||
}
|
||||
|
||||
//only sets in mem, does not set as config
|
||||
fn set_in_mem(o ${args.classname})! {
|
||||
mut o2:=obj_init(o)!
|
||||
${args.name}_global[o.name] = &o2
|
||||
${args.name}_default = o.name
|
||||
}
|
||||
|
||||
@else
|
||||
pub fn get(args_ ArgsGet) !&${args.classname} {
|
||||
@@ -61,34 +90,6 @@ pub fn get(args_ ArgsGet) !&${args.classname} {
|
||||
}
|
||||
@end
|
||||
|
||||
@if args.hasconfig
|
||||
fn config_exists(args_ ArgsGet) bool {
|
||||
mut args := args_get(args_)
|
||||
mut context:=base.context() or { panic("bug") }
|
||||
return context.hero_config_exists("${args.name}",args.name)
|
||||
}
|
||||
|
||||
fn config_load(args_ ArgsGet) ! {
|
||||
mut args := args_get(args_)
|
||||
mut context:=base.context()!
|
||||
mut heroscript := context.hero_config_get("${args.name}",args.name)!
|
||||
play(heroscript:heroscript)!
|
||||
}
|
||||
|
||||
fn config_save(args_ ArgsGet) ! {
|
||||
mut args := args_get(args_)
|
||||
mut context:=base.context()!
|
||||
context.hero_config_set("${args.name}",args.name,heroscript_default()!)!
|
||||
}
|
||||
|
||||
|
||||
fn set(o ${args.classname})! {
|
||||
mut o2:=obj_init(o)!
|
||||
${args.name}_global[o.name] = &o2
|
||||
${args.name}_default = o.name
|
||||
}
|
||||
|
||||
|
||||
^^[params]
|
||||
pub struct PlayArgs {
|
||||
pub mut:
|
||||
@@ -102,9 +103,7 @@ pub fn play(args_ PlayArgs) ! {
|
||||
mut args:=args_
|
||||
|
||||
@if args.hasconfig
|
||||
if args.heroscript == "" {
|
||||
args.heroscript = heroscript_default()!
|
||||
}
|
||||
|
||||
@end
|
||||
mut plbook := args.plbook or {
|
||||
playbook.new(text: args.heroscript)!
|
||||
@@ -114,8 +113,9 @@ pub fn play(args_ PlayArgs) ! {
|
||||
mut install_actions := plbook.find(filter: '${args.name}.configure')!
|
||||
if install_actions.len > 0 {
|
||||
for install_action in install_actions {
|
||||
mut p := install_action.params
|
||||
cfg_play(p)!
|
||||
heroscript:=install_action.heroscript()
|
||||
mut obj2:=heroscript_loads(heroscript)!
|
||||
set(obj2)!
|
||||
}
|
||||
}
|
||||
@end
|
||||
@@ -161,8 +161,6 @@ pub fn play(args_ PlayArgs) ! {
|
||||
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@if args.cat == .installer
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -309,3 +307,11 @@ pub fn (mut self ${args.classname}) destroy() ! {
|
||||
pub fn switch(name string) {
|
||||
${args.name}_default = name
|
||||
}
|
||||
|
||||
|
||||
//helpers
|
||||
|
||||
^^[params]
|
||||
pub struct DefaultConfigArgs{
|
||||
instance string = 'default'
|
||||
}
|
||||
@@ -1,47 +1,12 @@
|
||||
module ${args.name}
|
||||
import freeflowuniverse.herolib.data.paramsparser
|
||||
import freeflowuniverse.herolib.data.encoderhero
|
||||
import os
|
||||
|
||||
pub const version = '1.14.3'
|
||||
pub const version = '0.0.0'
|
||||
const singleton = ${args.singleton}
|
||||
const default = ${args.default}
|
||||
|
||||
@if args.hasconfig
|
||||
//TODO: THIS IS EXAMPLE CODE AND NEEDS TO BE CHANGED IN LINE TO STRUCT BELOW, IS STRUCTURED AS HEROSCRIPT
|
||||
pub fn heroscript_default() !string {
|
||||
@if args.cat == .installer
|
||||
heroscript:="
|
||||
!!${args.name}.configure
|
||||
name:'${args.name}'
|
||||
homedir: '{HOME}/hero/var/${args.name}'
|
||||
configpath: '{HOME}/.config/${args.name}/admin.yaml'
|
||||
username: 'admin'
|
||||
password: 'secretpassword'
|
||||
secret: ''
|
||||
title: 'My Hero DAG'
|
||||
host: 'localhost'
|
||||
port: 8888
|
||||
|
||||
"
|
||||
@else
|
||||
heroscript:="
|
||||
!!${args.name}.configure
|
||||
name:'${args.name}'
|
||||
mail_from: 'info@@example.com'
|
||||
mail_password: 'secretpassword'
|
||||
mail_port: 587
|
||||
mail_server: 'smtp-relay.brevo.com'
|
||||
mail_username: 'kristof@@incubaid.com'
|
||||
|
||||
"
|
||||
|
||||
@end
|
||||
|
||||
return heroscript
|
||||
|
||||
}
|
||||
@end
|
||||
|
||||
//THIS THE THE SOURCE OF THE INFORMATION OF THIS FILE, HERE WE HAVE THE CONFIG OBJECT CONFIGURED AND MODELLED
|
||||
@if args.cat == .installer
|
||||
^^[heap]
|
||||
@@ -53,33 +18,11 @@ pub mut:
|
||||
configpath string
|
||||
username string
|
||||
password string @@[secret]
|
||||
secret string @@[secret]
|
||||
title string
|
||||
host string
|
||||
port int
|
||||
@end
|
||||
}
|
||||
@if args.hasconfig
|
||||
fn cfg_play(p paramsparser.Params) !${args.classname} {
|
||||
//THIS IS EXAMPLE CODE AND NEEDS TO BE CHANGED IN LINE WITH struct above
|
||||
mut mycfg := ${args.classname}{
|
||||
name: p.get_default('name', 'default')!
|
||||
homedir: p.get_default('homedir', '{HOME}/hero/var/${args.name}')!
|
||||
configpath: p.get_default('configpath', '{HOME}/hero/var/${args.name}/admin.yaml')!
|
||||
username: p.get_default('username', 'admin')!
|
||||
password: p.get_default('password', '')!
|
||||
secret: p.get_default('secret', '')!
|
||||
title: p.get_default('title', 'HERO DAG')!
|
||||
host: p.get_default('host', 'localhost')!
|
||||
port: p.get_int_default('port', 8888)!
|
||||
}
|
||||
|
||||
if mycfg.password == '' && mycfg.secret == '' {
|
||||
return error('password or secret needs to be filled in for ${args.name}')
|
||||
}
|
||||
return mycfg
|
||||
}
|
||||
@end
|
||||
|
||||
@else
|
||||
|
||||
@@ -94,27 +37,16 @@ pub mut:
|
||||
mail_username string
|
||||
}
|
||||
|
||||
@if args.hasconfig
|
||||
fn cfg_play(p paramsparser.Params) ! {
|
||||
//THIS IS EXAMPLE CODE AND NEEDS TO BE CHANGED IN LINE WITH struct above
|
||||
mut mycfg := ${args.classname}{
|
||||
name: p.get_default('name', 'default')!
|
||||
mail_from: p.get('mail_from')!
|
||||
mail_password: p.get('mail_password')!
|
||||
mail_port: p.get_int_default('mail_port', 8888)!
|
||||
mail_server: p.get('mail_server')!
|
||||
mail_username: p.get('mail_username')!
|
||||
}
|
||||
set(mycfg)!
|
||||
}
|
||||
@end
|
||||
|
||||
@end
|
||||
|
||||
fn obj_init(obj_ ${args.classname})!${args.classname}{
|
||||
//never call get here, only thing we can do here is work on object itself
|
||||
mut obj:=obj_
|
||||
return obj
|
||||
//your checking & initialization code if needed
|
||||
fn obj_init(mycfg_ ${args.classname})!${args.classname}{
|
||||
mut mycfg:=mycfg_
|
||||
if mycfg.password == '' && mycfg.secret == '' {
|
||||
return error('password or secret needs to be filled in for ??{mycfg.name}')
|
||||
}
|
||||
return mycfg
|
||||
}
|
||||
|
||||
@if args.cat == .installer
|
||||
@@ -135,3 +67,13 @@ fn configure() ! {
|
||||
@end
|
||||
|
||||
|
||||
/////////////NORMALLY NO NEED TO TOUCH
|
||||
|
||||
pub fn heroscript_dumps(obj ${args.classname}) !string {
|
||||
return encoderhero.encode[${args.classname} ](obj)!
|
||||
}
|
||||
|
||||
pub fn heroscript_loads(heroscript string) !${args.classname} {
|
||||
mut obj := encoderhero.decode[${args.classname}](heroscript)!
|
||||
return obj
|
||||
}
|
||||
|
||||
@@ -70,37 +70,37 @@ pub fn decode[T](data []u8) !T {
|
||||
// Primitive types
|
||||
$if field.typ is string {
|
||||
// $(string_expr) produces an identifier
|
||||
result.$(field.name) = d.get_string()
|
||||
result.$(field.name) = d.get_string()!
|
||||
} $else $if field.typ is int {
|
||||
result.$(field.name) = d.get_int()
|
||||
result.$(field.name) = d.get_int()!
|
||||
} $else $if field.typ is u8 {
|
||||
result.$(field.name) = d.get_u8()
|
||||
result.$(field.name) = d.get_u8()!
|
||||
} $else $if field.typ is u16 {
|
||||
result.$(field.name) = d.get_u16()
|
||||
result.$(field.name) = d.get_u16()!
|
||||
} $else $if field.typ is u32 {
|
||||
result.$(field.name) = d.get_u32()
|
||||
result.$(field.name) = d.get_u32()!
|
||||
} $else $if field.typ is u64 {
|
||||
result.$(field.name) = d.get_u64()
|
||||
result.$(field.name) = d.get_u64()!
|
||||
} $else $if field.typ is time.Time {
|
||||
result.$(field.name) = d.get_time()
|
||||
result.$(field.name) = d.get_time()!
|
||||
// Arrays of primitive types
|
||||
} $else $if field.typ is []string {
|
||||
result.$(field.name) = d.get_list_string()
|
||||
result.$(field.name) = d.get_list_string()!
|
||||
} $else $if field.typ is []int {
|
||||
result.$(field.name) = d.get_list_int()
|
||||
result.$(field.name) = d.get_list_int()!
|
||||
} $else $if field.typ is []u8 {
|
||||
result.$(field.name) = d.get_list_u8()
|
||||
result.$(field.name) = d.get_list_u8()!
|
||||
} $else $if field.typ is []u16 {
|
||||
result.$(field.name) = d.get_list_u16()
|
||||
result.$(field.name) = d.get_list_u16()!
|
||||
} $else $if field.typ is []u32 {
|
||||
result.$(field.name) = d.get_list_u32()
|
||||
result.$(field.name) = d.get_list_u32()!
|
||||
} $else $if field.typ is []u64 {
|
||||
result.$(field.name) = d.get_list_u64()
|
||||
result.$(field.name) = d.get_list_u64()!
|
||||
// Maps of primitive types
|
||||
} $else $if field.typ is map[string]string {
|
||||
result.$(field.name) = d.get_map_string()
|
||||
result.$(field.name) = d.get_map_string()!
|
||||
} $else $if field.typ is map[string][]u8 {
|
||||
result.$(field.name) = d.get_map_bytes()
|
||||
result.$(field.name) = d.get_map_bytes()!
|
||||
// Structs
|
||||
} $else $if field.is_struct {
|
||||
// TODO handle recursive behavior
|
||||
|
||||
@@ -11,8 +11,8 @@ fn test_string() {
|
||||
assert e.data == [u8(1), 0, 97, 2, 0, 98, 99]
|
||||
|
||||
mut d := decoder_new(e.data)
|
||||
assert d.get_string() == 'a'
|
||||
assert d.get_string() == 'bc'
|
||||
assert d.get_string()! == 'a'
|
||||
assert d.get_string()! == 'bc'
|
||||
}
|
||||
|
||||
fn test_int() {
|
||||
@@ -22,8 +22,8 @@ fn test_int() {
|
||||
assert e.data == [u8(0x00), 0x00, 0x00, 0x80, 0xff, 0xff, 0xff, 0x7f]
|
||||
|
||||
mut d := decoder_new(e.data)
|
||||
assert d.get_int() == min_i32
|
||||
assert d.get_int() == max_i32
|
||||
assert d.get_int()! == min_i32
|
||||
assert d.get_int()! == max_i32
|
||||
}
|
||||
|
||||
fn test_bytes() {
|
||||
@@ -34,7 +34,7 @@ fn test_bytes() {
|
||||
assert e.data == [u8(6), 0, 97, 98, 99, 100, 101, 102]
|
||||
|
||||
mut d := decoder_new(e.data)
|
||||
assert d.get_list_u8() == sb
|
||||
assert d.get_list_u8()! == sb
|
||||
}
|
||||
|
||||
fn test_u8() {
|
||||
@@ -44,8 +44,8 @@ fn test_u8() {
|
||||
assert e.data == [u8(0x00), 0xff]
|
||||
|
||||
mut d := decoder_new(e.data)
|
||||
assert d.get_u8() == min_u8
|
||||
assert d.get_u8() == max_u8
|
||||
assert d.get_u8()! == min_u8
|
||||
assert d.get_u8()! == max_u8
|
||||
}
|
||||
|
||||
fn test_u16() {
|
||||
@@ -55,8 +55,8 @@ fn test_u16() {
|
||||
assert e.data == [u8(0x00), 0x00, 0xff, 0xff]
|
||||
|
||||
mut d := decoder_new(e.data)
|
||||
assert d.get_u16() == min_u16
|
||||
assert d.get_u16() == max_u16
|
||||
assert d.get_u16()! == min_u16
|
||||
assert d.get_u16()! == max_u16
|
||||
}
|
||||
|
||||
fn test_u32() {
|
||||
@@ -66,8 +66,8 @@ fn test_u32() {
|
||||
assert e.data == [u8(0x00), 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff]
|
||||
|
||||
mut d := decoder_new(e.data)
|
||||
assert d.get_u32() == min_u32
|
||||
assert d.get_u32() == max_u32
|
||||
assert d.get_u32()! == min_u32
|
||||
assert d.get_u32()! == max_u32
|
||||
}
|
||||
|
||||
fn test_u64() {
|
||||
@@ -78,8 +78,8 @@ fn test_u64() {
|
||||
0xff, 0xff, 0xff, 0xff]
|
||||
|
||||
mut d := decoder_new(e.data)
|
||||
assert d.get_u64() == min_u64
|
||||
assert d.get_u64() == max_u64
|
||||
assert d.get_u64()! == min_u64
|
||||
assert d.get_u64()! == max_u64
|
||||
}
|
||||
|
||||
fn test_time() {
|
||||
@@ -88,7 +88,7 @@ fn test_time() {
|
||||
e.add_time(t)
|
||||
|
||||
mut d := decoder_new(e.data)
|
||||
assert d.get_time() == t
|
||||
assert d.get_time()! == t
|
||||
}
|
||||
|
||||
fn test_list_string() {
|
||||
@@ -99,7 +99,7 @@ fn test_list_string() {
|
||||
assert e.data == [u8(3), 0, 1, 0, 97, 2, 0, 98, 99, 3, 0, 100, 101, 102]
|
||||
|
||||
mut d := decoder_new(e.data)
|
||||
assert d.get_list_string() == list
|
||||
assert d.get_list_string()! == list
|
||||
}
|
||||
|
||||
fn test_list_int() {
|
||||
@@ -110,7 +110,7 @@ fn test_list_int() {
|
||||
assert e.data == [u8(3), 0, 0x95, 0xea, 0x2f, 0x87, 0, 0, 0, 0, 0x8f, 0xe6, 0xf2, 0xfd]
|
||||
|
||||
mut d := decoder_new(e.data)
|
||||
assert d.get_list_int() == list
|
||||
assert d.get_list_int()! == list
|
||||
}
|
||||
|
||||
fn test_list_u8() {
|
||||
@@ -121,7 +121,7 @@ fn test_list_u8() {
|
||||
assert e.data == [u8(3), 0, 153, 0, 22]
|
||||
|
||||
mut d := decoder_new(e.data)
|
||||
assert d.get_list_u8() == list
|
||||
assert d.get_list_u8()! == list
|
||||
}
|
||||
|
||||
fn test_list_u16() {
|
||||
@@ -132,7 +132,7 @@ fn test_list_u16() {
|
||||
assert e.data == [u8(3), 0, 0x25, 0x87, 0, 0, 0xff, 0xfd]
|
||||
|
||||
mut d := decoder_new(e.data)
|
||||
assert d.get_list_u16() == list
|
||||
assert d.get_list_u16()! == list
|
||||
}
|
||||
|
||||
fn test_list_u32() {
|
||||
@@ -143,7 +143,7 @@ fn test_list_u32() {
|
||||
assert e.data == [u8(3), 0, 0x95, 0xea, 0x2f, 0x87, 0, 0, 0, 0, 0x8f, 0xe6, 0xf2, 0xfd]
|
||||
|
||||
mut d := decoder_new(e.data)
|
||||
assert d.get_list_u32() == list
|
||||
assert d.get_list_u32()! == list
|
||||
}
|
||||
|
||||
fn test_map_string() {
|
||||
@@ -157,7 +157,7 @@ fn test_map_string() {
|
||||
assert e.data == [u8(2), 0, 1, 0, 49, 1, 0, 97, 1, 0, 50, 2, 0, 98, 99]
|
||||
|
||||
mut d := decoder_new(e.data)
|
||||
assert d.get_map_string() == mp
|
||||
assert d.get_map_string()! == mp
|
||||
}
|
||||
|
||||
fn test_map_bytes() {
|
||||
@@ -171,7 +171,7 @@ fn test_map_bytes() {
|
||||
assert e.data == [u8(2), 0, 1, 0, 49, 1, 0, 0, 0, 97, 1, 0, 50, 2, 0, 0, 0, 98, 99]
|
||||
|
||||
mut d := decoder_new(e.data)
|
||||
assert d.get_map_bytes() == mp
|
||||
assert d.get_map_bytes()! == mp
|
||||
}
|
||||
|
||||
struct StructType[T] {
|
||||
|
||||
@@ -1,23 +1,18 @@
|
||||
# hero Encoder
|
||||
|
||||
> encoder hero is based on json2 from https://github.com/vlang/v/blob/master/vlib/x/json2/README.md
|
||||
|
||||
## Usage
|
||||
|
||||
#### encode[T]
|
||||
|
||||
```v
|
||||
#!/usr/bin/env -S v -n -cg -w -enable-globals run
|
||||
|
||||
#!/usr/bin/env -S v -n -w -gc none -cc tcc -d use_openssl -enable-globals run
|
||||
|
||||
import freeflowuniverse.herolib.data.encoderhero
|
||||
import freeflowuniverse.herolib.core.base
|
||||
import time
|
||||
|
||||
struct Person {
|
||||
mut:
|
||||
name string
|
||||
age ?int = 20
|
||||
age int = 20
|
||||
birthday time.Time
|
||||
deathday ?time.Time
|
||||
}
|
||||
|
||||
mut person := Person{
|
||||
@@ -26,44 +21,11 @@ mut person := Person{
|
||||
}
|
||||
heroscript := encoderhero.encode[Person](person)!
|
||||
|
||||
```
|
||||
println(heroscript)
|
||||
|
||||
#### decode[T]
|
||||
person2 := encoderhero.decode[Person](heroscript)!
|
||||
|
||||
```v
|
||||
import freeflowuniverse.herolib.data.encoderhero
|
||||
import time
|
||||
|
||||
struct Person {
|
||||
mut:
|
||||
name string
|
||||
age ?int = 20
|
||||
birthday time.Time
|
||||
deathday ?time.Time
|
||||
}
|
||||
|
||||
data := '
|
||||
|
||||
'
|
||||
|
||||
person := encoderhero.decode[Person](data)!
|
||||
/*
|
||||
struct Person {
|
||||
mut:
|
||||
name "Bob"
|
||||
age 20
|
||||
birthday "2022-03-11 13:54:25"
|
||||
}
|
||||
*/
|
||||
println(person2)
|
||||
|
||||
```
|
||||
|
||||
|
||||
## License
|
||||
|
||||
for all original code as used from Alexander:
|
||||
|
||||
// Copyright (c) 2019-2024 Alexander Medvednikov. All rights reserved.
|
||||
// Use of this source code is governed by an MIT license
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
|
||||
@@ -5,62 +5,35 @@ import os
|
||||
import encoding.csv
|
||||
import freeflowuniverse.herolib.osal
|
||||
import freeflowuniverse.herolib.core.pathlib
|
||||
import freeflowuniverse.herolib.clients.postgresql_client
|
||||
|
||||
// LocationDB handles all database operations for locations
|
||||
pub struct LocationDB {
|
||||
mut:
|
||||
pub mut:
|
||||
db pg.DB
|
||||
db_client postgresql_client.PostgresClient
|
||||
tmp_dir pathlib.Path
|
||||
db_dir pathlib.Path
|
||||
}
|
||||
|
||||
// new_location_db creates a new LocationDB instance
|
||||
pub fn new_location_db(reset bool) !LocationDB {
|
||||
pub fn new_location_db(mut db_client postgresql_client.PostgresClient, reset bool) !LocationDB {
|
||||
mut db_dir := pathlib.get_dir(path:'${os.home_dir()}/hero/var/db/location.db',create: true)!
|
||||
|
||||
// PostgreSQL connection parameters with defaults
|
||||
mut host := os.getenv('POSTGRES_HOST')
|
||||
if host == '' {
|
||||
host = 'localhost'
|
||||
// Create locations database if it doesn't exist
|
||||
if !db_client.db_exists('locations')! {
|
||||
db_client.db_create('locations')!
|
||||
}
|
||||
port := os.getenv('POSTGRES_PORT')
|
||||
port_num := if port == '' { 5432 } else { port.int() }
|
||||
mut user := os.getenv('POSTGRES_USER')
|
||||
if user == '' {
|
||||
user = 'postgres'
|
||||
}
|
||||
mut password := os.getenv('POSTGRES_PASSWORD')
|
||||
if password == '' {
|
||||
password = '1234'
|
||||
}
|
||||
mut dbname := os.getenv('POSTGRES_DB')
|
||||
if dbname == '' {
|
||||
dbname = 'locations'
|
||||
}
|
||||
|
||||
// First try to connect to create the database if it doesn't exist
|
||||
mut init_db := pg.connect(
|
||||
host: host
|
||||
port: port_num
|
||||
user: user
|
||||
password: password
|
||||
dbname: 'postgres'
|
||||
) or { return error('Failed to connect to PostgreSQL: ${err}') }
|
||||
|
||||
init_db.exec("CREATE DATABASE ${dbname}") or {}
|
||||
init_db.close()
|
||||
// Switch to locations database
|
||||
db_client.dbname = 'locations'
|
||||
|
||||
// Now connect to our database
|
||||
db := pg.connect(
|
||||
host: host
|
||||
port: port_num
|
||||
user: user
|
||||
password: password
|
||||
dbname: dbname
|
||||
) or { return error('Failed to connect to PostgreSQL: ${err}') }
|
||||
// Get the underlying pg.DB connection
|
||||
db := db_client.db()!
|
||||
|
||||
mut loc_db := LocationDB{
|
||||
db: db
|
||||
db_client: db_client
|
||||
tmp_dir: pathlib.get_dir(path: '/tmp/location/',create: true)!
|
||||
db_dir: db_dir
|
||||
}
|
||||
|
||||
@@ -1,16 +1,20 @@
|
||||
module location
|
||||
|
||||
import freeflowuniverse.herolib.clients.postgresql_client
|
||||
|
||||
// Location represents the main API for location operations
|
||||
pub struct Location {
|
||||
mut:
|
||||
db LocationDB
|
||||
db_client postgresql_client.PostgresClient
|
||||
}
|
||||
|
||||
// new creates a new Location instance
|
||||
pub fn new(reset bool) !Location {
|
||||
db := new_location_db(reset)!
|
||||
pub fn new(mut db_client postgresql_client.PostgresClient, reset bool) !Location {
|
||||
db := new_location_db(mut db_client, reset)!
|
||||
return Location{
|
||||
db: db
|
||||
db_client: db_client
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,12 +26,25 @@ pub fn (mut l Location) download_and_import(redownload bool) ! {
|
||||
// Example usage:
|
||||
/*
|
||||
fn main() ! {
|
||||
// Create a new location instance
|
||||
mut loc := location.new()!
|
||||
// Configure and get PostgreSQL client
|
||||
heroscript := "
|
||||
!!postgresql_client.configure
|
||||
name:'test'
|
||||
user: 'postgres'
|
||||
port: 5432
|
||||
host: 'localhost'
|
||||
password: '1234'
|
||||
dbname: 'postgres'
|
||||
"
|
||||
postgresql_client.play(heroscript: heroscript)!
|
||||
mut db_client := postgresql_client.get(name: "test")!
|
||||
|
||||
// Create a new location instance with db_client
|
||||
mut loc := location.new(db_client, false)!
|
||||
|
||||
// Initialize the database (downloads and imports data)
|
||||
// Only needs to be done once or when updating data
|
||||
loc.init_database()!
|
||||
loc.download_and_import(false)!
|
||||
|
||||
// Search for a city
|
||||
results := loc.search('London', 'GB', 5, true)!
|
||||
|
||||
@@ -310,11 +310,10 @@ fn (mut repo GitRepo) update_submodules() ! {
|
||||
}
|
||||
|
||||
fn (repo GitRepo) exec(cmd_ string) !string {
|
||||
import os { quoted_path }
|
||||
repo_path := quoted_path(repo.path())
|
||||
cmd_args := ["sh", "-c", "cd ${repo_path} && ${cmd_}"]
|
||||
// console.print_debug(cmd_args.join(" "))
|
||||
r := os.execute_opt(cmd_args)!
|
||||
repo_path := repo.path()
|
||||
cmd := 'cd ${repo_path} && ${cmd_}'
|
||||
// console.print_debug(cmd)
|
||||
r := os.execute(cmd)
|
||||
if r.exit_code != 0 {
|
||||
return error('Repo failed to exec cmd: ${cmd}\n${r.output})')
|
||||
}
|
||||
|
||||
@@ -94,20 +94,20 @@ fn (mut repo GitRepo) load_branches() ! {
|
||||
|
||||
// Helper to load remote tags
|
||||
fn (mut repo GitRepo) load_tags() ! {
|
||||
tags_result := repo.exec('git show-ref --tags') or {
|
||||
return error('Failed to list tags: ${err}. Please ensure git is installed and repository is accessible.')
|
||||
tags_result := repo.exec('git tag --list') or {
|
||||
return error('Failed to list tags: ${err}. Please ensure git is installed and repository is accessible.')
|
||||
}
|
||||
//println(tags_result)
|
||||
for line in tags_result.split('\n') {
|
||||
line_trimmed := line.trim_space()
|
||||
if line_trimmed == '' {
|
||||
continue
|
||||
}
|
||||
if parts := line_trimmed.split(' refs/tags/') {
|
||||
if parts.len != 2 {
|
||||
continue
|
||||
}
|
||||
commit_hash := parts[0].trim_space()
|
||||
tag_name := parts[1].trim_space()
|
||||
line_trimmed := line.trim_space()
|
||||
if line_trimmed != '' {
|
||||
parts := line_trimmed.split(' ')
|
||||
if parts.len < 2 {
|
||||
//console.print_debug('Skipping malformed tag line: ${line_trimmed}')
|
||||
continue
|
||||
}
|
||||
commit_hash := parts[0].trim_space()
|
||||
tag_name := parts[1].all_after('refs/tags/').trim_space()
|
||||
|
||||
// Update remote tags info
|
||||
repo.status_remote.tags[tag_name] = commit_hash
|
||||
|
||||
@@ -2,106 +2,61 @@ module gitea
|
||||
|
||||
import freeflowuniverse.herolib.osal
|
||||
import freeflowuniverse.herolib.core
|
||||
import freeflowuniverse.herolib.core.texttools
|
||||
import freeflowuniverse.herolib.ui.console
|
||||
import freeflowuniverse.herolib.installers.base
|
||||
import freeflowuniverse.herolib.installers.ulist
|
||||
import freeflowuniverse.herolib.installers.db.postgresql as postgres_installer
|
||||
import freeflowuniverse.herolib.installers.virt.podman as podman_installer
|
||||
import freeflowuniverse.herolib.osal.zinit
|
||||
import os
|
||||
|
||||
const postgres_container_name = 'herocontainer_postgresql'
|
||||
|
||||
// checks if a certain version or above is installed
|
||||
fn installed() !bool {
|
||||
mut podman := podman_installer.get()!
|
||||
podman.install()!
|
||||
|
||||
// We need to check also if postgres is installed
|
||||
mut result := os.execute('podman healthcheck run ${postgres_container_name}')
|
||||
|
||||
if result.exit_code != 0 {
|
||||
return false
|
||||
}
|
||||
|
||||
result = os.execute('gitea -v')
|
||||
|
||||
if result.exit_code != 0 {
|
||||
res := os.execute('${osal.profile_path_source_and()!} gitea version')
|
||||
if res.exit_code == 0 {
|
||||
r := res.output.split_into_lines().filter(it.trim_space().len > 0)
|
||||
if r.len != 1 {
|
||||
return error("couldn't parse gitea version.\n${res.output}")
|
||||
}
|
||||
if texttools.version(version) > texttools.version(r[0]) {
|
||||
return false
|
||||
}
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
fn install_postgres(cfg GiteaServer) ! {
|
||||
postgres_heroscript := "
|
||||
!!postgresql.configure
|
||||
name: '${cfg.database_name}'
|
||||
user: '${cfg.database_user}'
|
||||
password: '${cfg.database_passwd}'
|
||||
host: '${cfg.database_host}'
|
||||
port: ${cfg.database_port}
|
||||
volume_path:'/var/lib/postgresql/data'
|
||||
container_name: '${postgres_container_name}'
|
||||
"
|
||||
|
||||
postgres_installer.play(heroscript: postgres_heroscript)!
|
||||
mut postgres := postgres_installer.get()!
|
||||
postgres.install()!
|
||||
postgres.start()!
|
||||
}
|
||||
|
||||
fn install() ! {
|
||||
if installed()! {
|
||||
console.print_header('gitea binaraies already installed')
|
||||
return
|
||||
}
|
||||
|
||||
console.print_header('install gitea')
|
||||
server := get()!
|
||||
baseurl:="https://github.com/go-gitea/gitea/releases/download/v${version}/gitea-${version}"
|
||||
|
||||
// make sure we install base on the node
|
||||
base.install()!
|
||||
install_postgres(server)!
|
||||
|
||||
mut download_link := ''
|
||||
|
||||
is_linux_intel := core.is_linux_intel()!
|
||||
is_osx_arm := core.is_osx_arm()!
|
||||
|
||||
if is_linux_intel {
|
||||
download_link = 'https://dl.gitea.com/gitea/${server.version}/gitea-${server.version}-linux-amd64'
|
||||
mut url := ''
|
||||
if core.is_linux_arm()! {
|
||||
//https://github.com/go-gitea/gitea/releases/download/v1.23.2/gitea-1.23.2-linux-arm64.xz
|
||||
url = '${baseurl}-linux-arm64.xz'
|
||||
} else if core.is_linux_intel()! {
|
||||
// https://github.com/go-gitea/gitea/releases/download/v1.23.2/gitea-1.23.2-linux-amd64.xz
|
||||
url = '${baseurl}-linux-amd64.xz'
|
||||
} else if core.is_osx_arm()! {
|
||||
//https://github.com/go-gitea/gitea/releases/download/v1.23.2/gitea-1.23.2-darwin-10.12-arm64.xz
|
||||
url = '${baseurl}-darwin-10.12-arm64.xz'
|
||||
} else if core.is_osx_intel()! {
|
||||
//https://github.com/go-gitea/gitea/releases/download/v1.23.2/gitea-1.23.2-darwin-10.12-amd64.xz
|
||||
url = '${baseurl}-darwin-10.12-amd64.xz'
|
||||
} else {
|
||||
return error('unsported platform')
|
||||
}
|
||||
|
||||
if is_osx_arm {
|
||||
download_link = 'https://dl.gitea.com/gitea/${server.version}/gitea-${server.version}-darwin-10.12-amd64'
|
||||
}
|
||||
mut dest := osal.download(
|
||||
url: url
|
||||
minsize_kb: 9000
|
||||
expand_dir: '/tmp/gitea'
|
||||
)!
|
||||
|
||||
if download_link.len == 0 {
|
||||
return error('unsupported platform')
|
||||
}
|
||||
|
||||
binary := osal.download(
|
||||
url: download_link
|
||||
name: 'gitea'
|
||||
dest: '/tmp/gitea'
|
||||
) or { return error('failed to download gitea due to: ${err}') }
|
||||
|
||||
mut res := os.execute('sudo cp ${binary.path} /usr/local/bin/gitea')
|
||||
if res.exit_code != 0 {
|
||||
return error('failed to add gitea to the path due to: ${res.output}')
|
||||
}
|
||||
|
||||
res = os.execute('sudo chmod +x /usr/local/bin/gitea')
|
||||
if res.exit_code != 0 {
|
||||
return error('failed to make gitea executable due to: ${res.output}')
|
||||
}
|
||||
|
||||
// create config file
|
||||
file_content := $tmpl('./templates/app.ini')
|
||||
mut file := os.open_file('/etc/gitea_app.ini', 'w')!
|
||||
file.write(file_content.bytes())!
|
||||
|
||||
console.print_header('gitea installed properly.')
|
||||
mut binpath := dest.file_get('gitea')!
|
||||
osal.cmd_add(
|
||||
cmdname: 'gitea'
|
||||
source: binpath.path
|
||||
)!
|
||||
}
|
||||
|
||||
fn build() ! {
|
||||
@@ -137,65 +92,80 @@ fn ulist_get() !ulist.UList {
|
||||
fn upload() ! {}
|
||||
|
||||
fn startupcmd() ![]zinit.ZProcessNewArgs {
|
||||
mut cfg := get()!
|
||||
mut res := []zinit.ZProcessNewArgs{}
|
||||
cfg := get()!
|
||||
res << zinit.ZProcessNewArgs{
|
||||
name: 'gitea'
|
||||
// cmd: 'GITEA_WORK_DIR=${cfg.path} sudo -u git /var/lib/git/gitea web -c /etc/gitea_app.ini'
|
||||
cmd: '
|
||||
|
||||
# Variables
|
||||
GITEA_USER="${cfg.run_user}"
|
||||
GITEA_HOME="${cfg.path}"
|
||||
GITEA_BINARY="/usr/local/bin/gitea"
|
||||
GITEA_CONFIG="/etc/gitea_app.ini"
|
||||
GITEA_DATA_PATH="\$GITEA_HOME/data"
|
||||
GITEA_CUSTOM_PATH="\$GITEA_HOME/custom"
|
||||
GITEA_LOG_PATH="\$GITEA_HOME/log"
|
||||
|
||||
# Ensure the script is run as root
|
||||
if [[ \$EUID -ne 0 ]]; then
|
||||
echo "This script must be run as root."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Setting up Gitea..."
|
||||
|
||||
# Create Gitea user if it doesn\'t exist
|
||||
if id -u "\$GITEA_USER" &>/dev/null; then
|
||||
echo "User \$GITEA_USER already exists."
|
||||
else
|
||||
echo "Creating Gitea user..."
|
||||
if ! sudo adduser --system --shell /bin/bash --group --disabled-password --home "/var/lib/\$GITEA_USER" "\$GITEA_USER"; then
|
||||
echo "Failed to create user \$GITEA_USER."
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
# Create necessary directories
|
||||
echo "Creating directories..."
|
||||
mkdir -p "\$GITEA_DATA_PATH" "\$GITEA_CUSTOM_PATH" "\$GITEA_LOG_PATH"
|
||||
chown -R "\$GITEA_USER:\$GITEA_USER" "\$GITEA_HOME"
|
||||
chmod -R 750 "\$GITEA_HOME"
|
||||
|
||||
chown "\$GITEA_USER:\$GITEA_USER" "\$GITEA_CONFIG"
|
||||
chmod 640 "\$GITEA_CONFIG"
|
||||
|
||||
GITEA_WORK_DIR=\$GITEA_HOME sudo -u git gitea web -c \$GITEA_CONFIG
|
||||
'
|
||||
workdir: cfg.path
|
||||
}
|
||||
res << zinit.ZProcessNewArgs{
|
||||
name: 'restart_gitea'
|
||||
cmd: 'sleep 30 && zinit restart gitea && exit 1'
|
||||
after: ['gitea']
|
||||
oneshot: true
|
||||
workdir: cfg.path
|
||||
cmd: 'gitea server'
|
||||
env: {
|
||||
'HOME': os.home_dir()
|
||||
'GITEA_CONFIG': cfg.config_path()
|
||||
}
|
||||
}
|
||||
return res
|
||||
|
||||
|
||||
|
||||
// mut res := []zinit.ZProcessNewArgs{}
|
||||
// cfg := get()!
|
||||
// res << zinit.ZProcessNewArgs{
|
||||
// name: 'gitea'
|
||||
// // cmd: 'GITEA_WORK_DIR=${cfg.path} sudo -u git /var/lib/git/gitea web -c /etc/gitea_app.ini'
|
||||
// cmd: '
|
||||
|
||||
// # Variables
|
||||
// GITEA_USER="${cfg.run_user}"
|
||||
// GITEA_HOME="${cfg.path}"
|
||||
// GITEA_BINARY="/usr/local/bin/gitea"
|
||||
// GITEA_CONFIG="/etc/gitea_app.ini"
|
||||
// GITEA_DATA_PATH="\$GITEA_HOME/data"
|
||||
// GITEA_CUSTOM_PATH="\$GITEA_HOME/custom"
|
||||
// GITEA_LOG_PATH="\$GITEA_HOME/log"
|
||||
|
||||
// # Ensure the script is run as root
|
||||
// if [[ \$EUID -ne 0 ]]; then
|
||||
// echo "This script must be run as root."
|
||||
// exit 1
|
||||
// fi
|
||||
|
||||
// echo "Setting up Gitea..."
|
||||
|
||||
// # Create Gitea user if it doesn\'t exist
|
||||
// if id -u "\$GITEA_USER" &>/dev/null; then
|
||||
// echo "User \$GITEA_USER already exists."
|
||||
// else
|
||||
// echo "Creating Gitea user..."
|
||||
// if ! sudo adduser --system --shell /bin/bash --group --disabled-password --home "/var/lib/\$GITEA_USER" "\$GITEA_USER"; then
|
||||
// echo "Failed to create user \$GITEA_USER."
|
||||
// exit 1
|
||||
// fi
|
||||
// fi
|
||||
|
||||
// # Create necessary directories
|
||||
// echo "Creating directories..."
|
||||
// mkdir -p "\$GITEA_DATA_PATH" "\$GITEA_CUSTOM_PATH" "\$GITEA_LOG_PATH"
|
||||
// chown -R "\$GITEA_USER:\$GITEA_USER" "\$GITEA_HOME"
|
||||
// chmod -R 750 "\$GITEA_HOME"
|
||||
|
||||
// chown "\$GITEA_USER:\$GITEA_USER" "\$GITEA_CONFIG"
|
||||
// chmod 640 "\$GITEA_CONFIG"
|
||||
|
||||
// GITEA_WORK_DIR=\$GITEA_HOME sudo -u git gitea web -c \$GITEA_CONFIG
|
||||
// '
|
||||
// workdir: cfg.path
|
||||
// }
|
||||
// res << zinit.ZProcessNewArgs{
|
||||
// name: 'restart_gitea'
|
||||
// cmd: 'sleep 30 && zinit restart gitea && exit 1'
|
||||
// after: ['gitea']
|
||||
// oneshot: true
|
||||
// workdir: cfg.path
|
||||
// }
|
||||
// return res
|
||||
}
|
||||
|
||||
fn running() !bool {
|
||||
//TODO: extend with proper gitea client
|
||||
res := os.execute('curl -fsSL http://localhost:3000 || exit 1')
|
||||
return res.exit_code == 0
|
||||
}
|
||||
|
||||
@@ -2,239 +2,289 @@ module gitea
|
||||
|
||||
import freeflowuniverse.herolib.core.base
|
||||
import freeflowuniverse.herolib.core.playbook
|
||||
import freeflowuniverse.herolib.ui.console
|
||||
import freeflowuniverse.herolib.data.paramsparser
|
||||
|
||||
import freeflowuniverse.herolib.sysadmin.startupmanager
|
||||
import freeflowuniverse.herolib.osal.zinit
|
||||
import freeflowuniverse.herolib.ui.console
|
||||
import time
|
||||
|
||||
__global (
|
||||
gitea_global map[string]&GiteaServer
|
||||
gitea_default string
|
||||
gitea_global map[string]&GiteaServer
|
||||
gitea_default string
|
||||
)
|
||||
|
||||
/////////FACTORY
|
||||
|
||||
@[params]
|
||||
pub struct ArgsGet {
|
||||
pub struct ArgsGet{
|
||||
pub mut:
|
||||
name string = 'default'
|
||||
name string
|
||||
}
|
||||
|
||||
fn args_get(args_ ArgsGet) ArgsGet {
|
||||
mut args := args_
|
||||
if args.name == '' {
|
||||
args.name = gitea_default
|
||||
}
|
||||
if args.name == '' {
|
||||
args.name = 'default'
|
||||
}
|
||||
return args
|
||||
fn args_get (args_ ArgsGet) ArgsGet {
|
||||
mut args:=args_
|
||||
if args.name == ""{
|
||||
args.name = "default"
|
||||
}
|
||||
return args
|
||||
}
|
||||
|
||||
pub fn get(args_ ArgsGet) !&GiteaServer {
|
||||
mut args := args_get(args_)
|
||||
if args.name !in gitea_global {
|
||||
if !config_exists() {
|
||||
if default {
|
||||
config_save()!
|
||||
}
|
||||
}
|
||||
config_load()!
|
||||
}
|
||||
return gitea_global[args.name] or {
|
||||
println(gitea_global)
|
||||
panic('failed to get gitea server for ${args.name}')
|
||||
}
|
||||
pub fn get(args_ ArgsGet) !&GiteaServer {
|
||||
mut context:=base.context()!
|
||||
mut args := args_get(args_)
|
||||
mut obj := GiteaServer{}
|
||||
if !(args.name in gitea_global) {
|
||||
if ! exists(args)!{
|
||||
set(obj)!
|
||||
}else{
|
||||
heroscript := context.hero_config_get("gitea",args.name)!
|
||||
mut obj2:=heroscript_loads(heroscript)!
|
||||
set_in_mem(obj2)!
|
||||
}
|
||||
}
|
||||
return gitea_global[args.name] or {
|
||||
println(gitea_global)
|
||||
//bug if we get here because should be in globals
|
||||
panic("could not get config for gitea with name, is bug:${args.name}")
|
||||
}
|
||||
}
|
||||
|
||||
fn config_exists(args_ ArgsGet) bool {
|
||||
mut args := args_get(args_)
|
||||
mut context := base.context() or { panic('bug') }
|
||||
return context.hero_config_exists('gitea', args.name)
|
||||
//register the config for the future
|
||||
pub fn set(o GiteaServer)! {
|
||||
set_in_mem(o)!
|
||||
mut context := base.context()!
|
||||
heroscript := heroscript_dumps(o)!
|
||||
context.hero_config_set("gitea", o.name, heroscript)!
|
||||
}
|
||||
|
||||
fn config_load(args_ ArgsGet) ! {
|
||||
mut args := args_get(args_)
|
||||
mut context := base.context()!
|
||||
mut heroscript := context.hero_config_get('gitea', args.name)!
|
||||
play(heroscript: heroscript)!
|
||||
//does the config exists?
|
||||
pub fn exists(args_ ArgsGet) !bool {
|
||||
mut context := base.context()!
|
||||
mut args := args_get(args_)
|
||||
return context.hero_config_exists("gitea", args.name)
|
||||
}
|
||||
|
||||
fn config_save(args_ ArgsGet) ! {
|
||||
mut args := args_get(args_)
|
||||
mut context := base.context()!
|
||||
context.hero_config_set('gitea', args.name, heroscript_default()!)!
|
||||
pub fn delete(args_ ArgsGet)! {
|
||||
mut args := args_get(args_)
|
||||
mut context:=base.context()!
|
||||
context.hero_config_delete("gitea",args.name)!
|
||||
if args.name in gitea_global {
|
||||
//del gitea_global[args.name]
|
||||
}
|
||||
}
|
||||
|
||||
fn set(o GiteaServer) ! {
|
||||
mut o2 := obj_init(o)!
|
||||
gitea_global['default'] = &o2
|
||||
//only sets in mem, does not set as config
|
||||
fn set_in_mem(o GiteaServer)! {
|
||||
mut o2:=obj_init(o)!
|
||||
gitea_global[o.name] = &o2
|
||||
gitea_default = o.name
|
||||
}
|
||||
|
||||
|
||||
@[params]
|
||||
pub struct PlayArgs {
|
||||
pub mut:
|
||||
name string = 'default'
|
||||
heroscript string // if filled in then plbook will be made out of it
|
||||
plbook ?playbook.PlayBook
|
||||
reset bool
|
||||
|
||||
start bool
|
||||
stop bool
|
||||
restart bool
|
||||
delete bool
|
||||
configure bool // make sure there is at least one installed
|
||||
heroscript string //if filled in then plbook will be made out of it
|
||||
plbook ?playbook.PlayBook
|
||||
reset bool
|
||||
}
|
||||
|
||||
pub fn play(args_ PlayArgs) ! {
|
||||
mut args := args_
|
||||
|
||||
mut args:=args_
|
||||
|
||||
if args.heroscript == '' {
|
||||
args.heroscript = heroscript_default()!
|
||||
}
|
||||
mut plbook := args.plbook or { playbook.new(text: args.heroscript)! }
|
||||
mut plbook := args.plbook or {
|
||||
playbook.new(text: args.heroscript)!
|
||||
}
|
||||
|
||||
mut install_actions := plbook.find(filter: 'gitea.configure')!
|
||||
if install_actions.len > 0 {
|
||||
for install_action in install_actions {
|
||||
heroscript:=install_action.heroscript()
|
||||
mut obj:=heroscript_loads(heroscript)!
|
||||
set(obj)!
|
||||
}
|
||||
}
|
||||
|
||||
mut other_actions := plbook.find(filter: 'gitea.')!
|
||||
for other_action in other_actions {
|
||||
if other_action.name in ["destroy","install","build"]{
|
||||
mut p := other_action.params
|
||||
reset:=p.get_default_false("reset")
|
||||
if other_action.name == "destroy" || reset{
|
||||
console.print_debug("install action gitea.destroy")
|
||||
destroy()!
|
||||
}
|
||||
if other_action.name == "install"{
|
||||
console.print_debug("install action gitea.install")
|
||||
install()!
|
||||
}
|
||||
}
|
||||
if other_action.name in ["start","stop","restart"]{
|
||||
mut p := other_action.params
|
||||
name := p.get('name')!
|
||||
mut gitea_obj:=get(name:name)!
|
||||
console.print_debug("action object:\n${gitea_obj}")
|
||||
if other_action.name == "start"{
|
||||
console.print_debug("install action gitea.${other_action.name}")
|
||||
gitea_obj.start()!
|
||||
}
|
||||
|
||||
if other_action.name == "stop"{
|
||||
console.print_debug("install action gitea.${other_action.name}")
|
||||
gitea_obj.stop()!
|
||||
}
|
||||
if other_action.name == "restart"{
|
||||
console.print_debug("install action gitea.${other_action.name}")
|
||||
gitea_obj.restart()!
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mut install_actions := plbook.find(filter: 'gitea.configure')!
|
||||
if install_actions.len > 0 {
|
||||
for install_action in install_actions {
|
||||
mut p := install_action.params
|
||||
cfg := cfg_play(p)!
|
||||
set(cfg)!
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////# LIVE CYCLE MANAGEMENT FOR INSTALLERS ///////////////////////////////////
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
fn startupmanager_get(cat zinit.StartupManagerType) !startupmanager.StartupManager {
|
||||
// unknown
|
||||
// screen
|
||||
// zinit
|
||||
// tmux
|
||||
// systemd
|
||||
match cat {
|
||||
.zinit {
|
||||
console.print_debug('startupmanager: zinit')
|
||||
return startupmanager.get(cat: .zinit)!
|
||||
}
|
||||
.systemd {
|
||||
console.print_debug('startupmanager: systemd')
|
||||
return startupmanager.get(cat: .systemd)!
|
||||
}
|
||||
else {
|
||||
console.print_debug('startupmanager: auto')
|
||||
return startupmanager.get()!
|
||||
}
|
||||
}
|
||||
// unknown
|
||||
// screen
|
||||
// zinit
|
||||
// tmux
|
||||
// systemd
|
||||
match cat{
|
||||
.zinit{
|
||||
console.print_debug("startupmanager: zinit")
|
||||
return startupmanager.get(cat:.zinit)!
|
||||
}
|
||||
.systemd{
|
||||
console.print_debug("startupmanager: systemd")
|
||||
return startupmanager.get(cat:.systemd)!
|
||||
}else{
|
||||
console.print_debug("startupmanager: auto")
|
||||
return startupmanager.get()!
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// load from disk and make sure is properly intialized
|
||||
//load from disk and make sure is properly intialized
|
||||
pub fn (mut self GiteaServer) reload() ! {
|
||||
switch(self.name)
|
||||
self = obj_init(self)!
|
||||
switch(self.name)
|
||||
self=obj_init(self)!
|
||||
}
|
||||
|
||||
pub fn (mut self GiteaServer) start() ! {
|
||||
switch(self.name)
|
||||
if self.running()! {
|
||||
return
|
||||
}
|
||||
switch(self.name)
|
||||
if self.running()!{
|
||||
return
|
||||
}
|
||||
|
||||
console.print_header('gitea start')
|
||||
console.print_header('gitea start')
|
||||
|
||||
if !installed()! {
|
||||
install()!
|
||||
}
|
||||
if ! installed()!{
|
||||
install()!
|
||||
}
|
||||
|
||||
configure()!
|
||||
configure()!
|
||||
|
||||
start_pre()!
|
||||
start_pre()!
|
||||
|
||||
for zprocess in startupcmd()! {
|
||||
mut sm := startupmanager_get(zprocess.startuptype)!
|
||||
for zprocess in startupcmd()!{
|
||||
mut sm:=startupmanager_get(zprocess.startuptype)!
|
||||
|
||||
console.print_debug('starting gitea with ${zprocess.startuptype}...')
|
||||
console.print_debug('starting gitea with ${zprocess.startuptype}...')
|
||||
|
||||
sm.new(zprocess)!
|
||||
sm.new(zprocess)!
|
||||
|
||||
sm.start(zprocess.name)!
|
||||
}
|
||||
sm.start(zprocess.name)!
|
||||
}
|
||||
|
||||
start_post()!
|
||||
start_post()!
|
||||
|
||||
for _ in 0 .. 50 {
|
||||
if self.running()! {
|
||||
return
|
||||
}
|
||||
time.sleep(100 * time.millisecond)
|
||||
}
|
||||
return error('gitea did not install properly.')
|
||||
|
||||
for _ in 0 .. 50 {
|
||||
if self.running()! {
|
||||
return
|
||||
}
|
||||
time.sleep(100 * time.millisecond)
|
||||
}
|
||||
return error('cannot start gitea')
|
||||
}
|
||||
|
||||
pub fn (mut self GiteaServer) install_start(args InstallArgs) ! {
|
||||
switch(self.name)
|
||||
self.install(args)!
|
||||
self.start()!
|
||||
switch(self.name)
|
||||
self.install(args)!
|
||||
self.start()!
|
||||
}
|
||||
|
||||
pub fn (mut self GiteaServer) stop() ! {
|
||||
switch(self.name)
|
||||
stop_pre()!
|
||||
for zprocess in startupcmd()! {
|
||||
mut sm := startupmanager_get(zprocess.startuptype)!
|
||||
sm.stop(zprocess.name)!
|
||||
}
|
||||
stop_post()!
|
||||
switch(self.name)
|
||||
stop_pre()!
|
||||
for zprocess in startupcmd()!{
|
||||
mut sm:=startupmanager_get(zprocess.startuptype)!
|
||||
sm.stop(zprocess.name)!
|
||||
}
|
||||
stop_post()!
|
||||
}
|
||||
|
||||
pub fn (mut self GiteaServer) restart() ! {
|
||||
switch(self.name)
|
||||
self.stop()!
|
||||
self.start()!
|
||||
switch(self.name)
|
||||
self.stop()!
|
||||
self.start()!
|
||||
}
|
||||
|
||||
pub fn (mut self GiteaServer) running() !bool {
|
||||
switch(self.name)
|
||||
switch(self.name)
|
||||
|
||||
// walk over the generic processes, if not running return
|
||||
for zprocess in startupcmd()! {
|
||||
mut sm := startupmanager_get(zprocess.startuptype)!
|
||||
r := sm.running(zprocess.name)!
|
||||
if r == false {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return running()!
|
||||
//walk over the generic processes, if not running return
|
||||
for zprocess in startupcmd()!{
|
||||
mut sm:=startupmanager_get(zprocess.startuptype)!
|
||||
r:=sm.running(zprocess.name)!
|
||||
if r==false{
|
||||
return false
|
||||
}
|
||||
}
|
||||
return running()!
|
||||
}
|
||||
|
||||
@[params]
|
||||
pub struct InstallArgs {
|
||||
pub struct InstallArgs{
|
||||
pub mut:
|
||||
reset bool
|
||||
reset bool
|
||||
}
|
||||
|
||||
pub fn (mut self GiteaServer) install(args InstallArgs) ! {
|
||||
switch(self.name)
|
||||
if args.reset || (!installed()!) {
|
||||
install()!
|
||||
}
|
||||
switch(self.name)
|
||||
if args.reset || (!installed()!) {
|
||||
install()!
|
||||
}
|
||||
}
|
||||
|
||||
pub fn (mut self GiteaServer) build() ! {
|
||||
switch(self.name)
|
||||
build()!
|
||||
switch(self.name)
|
||||
build()!
|
||||
}
|
||||
|
||||
pub fn (mut self GiteaServer) destroy() ! {
|
||||
switch(self.name)
|
||||
|
||||
self.stop() or {}
|
||||
destroy()!
|
||||
switch(self.name)
|
||||
self.stop() or {}
|
||||
destroy()!
|
||||
}
|
||||
|
||||
// switch instance to be used for gitea
|
||||
|
||||
|
||||
//switch instance to be used for gitea
|
||||
pub fn switch(name string) {
|
||||
gitea_default = name
|
||||
gitea_default = name
|
||||
}
|
||||
|
||||
|
||||
//helpers
|
||||
|
||||
@[params]
|
||||
pub struct DefaultConfigArgs{
|
||||
instance string = 'default'
|
||||
}
|
||||
|
||||
@@ -1,117 +1,94 @@
|
||||
module gitea
|
||||
|
||||
import freeflowuniverse.herolib.data.paramsparser
|
||||
import freeflowuniverse.herolib.osal.zinit
|
||||
import freeflowuniverse.herolib.data.encoderhero
|
||||
import freeflowuniverse.herolib.core.pathlib
|
||||
import freeflowuniverse.herolib.ui.console
|
||||
import freeflowuniverse.herolib.osal
|
||||
import os
|
||||
import freeflowuniverse.herolib.clients.mailclient
|
||||
import freeflowuniverse.herolib.clients.postgresql_client
|
||||
import rand
|
||||
|
||||
pub const version = '0.0.0'
|
||||
const singleton = true
|
||||
const default = true
|
||||
|
||||
// TODO: THIS IS EXAMPLE CODE AND NEEDS TO BE CHANGED IN LINE TO STRUCT BELOW, IS STRUCTURED AS HEROSCRIPT
|
||||
pub fn heroscript_default() !string {
|
||||
heroscript := "
|
||||
!!gitea.configure
|
||||
name:'gitea'
|
||||
version:'1.22.6'
|
||||
run_user: 'git'
|
||||
path: '/var/lib/git'
|
||||
passwd: '12345678'
|
||||
postgresql_name: 'default'
|
||||
mail_from: 'git@meet.tf'
|
||||
smtp_addr: 'smtp-relay.brevo.com'
|
||||
smtp_login: 'admin'
|
||||
smtp_port: 587
|
||||
smtp_passwd: '12345678'
|
||||
domain: 'meet.tf'
|
||||
jwt_secret: ''
|
||||
lfs_jwt_secret: ''
|
||||
internal_token: ''
|
||||
secret_key: ''
|
||||
database_passwd: 'postgres'
|
||||
database_name: 'postgres'
|
||||
database_user: 'postgres'
|
||||
database_host: 'localhost'
|
||||
database_port: 5432
|
||||
"
|
||||
|
||||
return heroscript
|
||||
}
|
||||
|
||||
// THIS THE THE SOURCE OF THE INFORMATION OF THIS FILE, HERE WE HAVE THE CONFIG OBJECT CONFIGURED AND MODELLED
|
||||
const default = false
|
||||
|
||||
@[heap]
|
||||
pub struct GiteaServer {
|
||||
pub mut:
|
||||
name string = 'default'
|
||||
|
||||
// reset bool
|
||||
version string = '1.22.6'
|
||||
run_user string = 'git'
|
||||
path string = '/var/lib/git'
|
||||
name string = 'default'
|
||||
path string = '${os.home_dir()}/hero/var/gitea'
|
||||
passwd string
|
||||
mail_from string = 'git@meet.tf'
|
||||
smtp_addr string = 'smtp-relay.brevo.com'
|
||||
smtp_login string @[required]
|
||||
smtp_port int = 587
|
||||
smtp_passwd string
|
||||
domain string @[required]
|
||||
jwt_secret string
|
||||
domain string = "git.test.com"
|
||||
jwt_secret string = rand.hex(12)
|
||||
lfs_jwt_secret string
|
||||
internal_token string
|
||||
secret_key string
|
||||
|
||||
// Database config
|
||||
database_passwd string = 'postgres'
|
||||
database_name string = 'postgres'
|
||||
database_user string = 'postgres'
|
||||
database_host string = 'localhost'
|
||||
database_port int = 5432
|
||||
|
||||
process ?zinit.ZProcess
|
||||
path_config pathlib.Path
|
||||
postgresql_client_name string = "default"
|
||||
mail_client_name string = "default"
|
||||
}
|
||||
|
||||
fn cfg_play(p paramsparser.Params) !GiteaServer {
|
||||
// THIS IS EXAMPLE CODE AND NEEDS TO BE CHANGED IN LINE WITH struct above
|
||||
mut mycfg := GiteaServer{
|
||||
name: p.get_default('name', 'default')!
|
||||
version: p.get_default('version', '1.22.6')!
|
||||
run_user: p.get_default('run_user', 'git')!
|
||||
path: p.get_default('path', '/var/lib/git')!
|
||||
passwd: p.get('passwd')!
|
||||
mail_from: p.get_default('mail_from', 'git@meet.tf')!
|
||||
smtp_addr: p.get_default('smtp_addr', 'smtp-relay.brevo.com')!
|
||||
smtp_login: p.get('smtp_login')!
|
||||
smtp_port: p.get_int_default('smtp_port', 587)!
|
||||
smtp_passwd: p.get('smtp_passwd')!
|
||||
domain: p.get('domain')!
|
||||
jwt_secret: p.get('jwt_secret')!
|
||||
lfs_jwt_secret: p.get('lfs_jwt_secret')!
|
||||
internal_token: p.get('internal_token')!
|
||||
secret_key: p.get('secret_key')!
|
||||
|
||||
// Set database config
|
||||
database_passwd: p.get_default('database_passwd', 'postgres')!
|
||||
database_name: p.get_default('database_name', 'postgres')!
|
||||
database_user: p.get_default('database_user', 'postgres')!
|
||||
database_host: p.get_default('database_host', 'localhost')!
|
||||
database_port: p.get_int_default('database_port', 5432)!
|
||||
pub fn (obj GiteaServer) config_path() string {
|
||||
return '${obj.path}/config.ini'
|
||||
}
|
||||
|
||||
//your checking & initialization code if needed
|
||||
fn obj_init(mycfg_ GiteaServer)!GiteaServer{
|
||||
mut mycfg:=mycfg_
|
||||
return mycfg
|
||||
}
|
||||
|
||||
//called before start if done
|
||||
fn configure() ! {
|
||||
mut server := get()!
|
||||
|
||||
if !osal.cmd_exists('gitea') {
|
||||
return error('gitea binary not found in path. Please install gitea first.')
|
||||
}
|
||||
// Generate and set any missing secrets
|
||||
if server.lfs_jwt_secret == '' {
|
||||
server.lfs_jwt_secret = os.execute_opt('gitea generate secret LFS_JWT_SECRET')!.output.trim_space()
|
||||
set(server)!
|
||||
}
|
||||
if server.internal_token == '' {
|
||||
server.internal_token = os.execute_opt('gitea generate secret INTERNAL_TOKEN')!.output.trim_space()
|
||||
set(server)!
|
||||
}
|
||||
if server.secret_key == '' {
|
||||
server.secret_key = os.execute_opt('gitea generate secret SECRET_KEY')!.output.trim_space()
|
||||
set(server)!
|
||||
}
|
||||
|
||||
return mycfg
|
||||
// Initialize required clients with detailed error handling
|
||||
mut db_client := postgresql_client.get(name: server.postgresql_client_name) or {
|
||||
return error('Failed to initialize PostgreSQL client "${server.postgresql_client_name}": ${err}')
|
||||
}
|
||||
mut mail_client := mailclient.get(name: server.mail_client_name) or {
|
||||
return error('Failed to initialize mail client "${server.mail_client_name}": ${err}')
|
||||
}
|
||||
|
||||
//TODO: check database exists
|
||||
if !db_client.db_exists('gitea_${server.name}')! {
|
||||
console.print_header('Creating database gitea_${server.name} for gitea.')
|
||||
db_client.db_create('gitea_${server.name}')!
|
||||
}
|
||||
|
||||
db_client.dbname = 'gitea_${server.name}'
|
||||
|
||||
mut mycode := $tmpl('templates/app.ini')
|
||||
mut path := pathlib.get_file(path: server.config_path(), create: true)!
|
||||
path.write(mycode)!
|
||||
console.print_debug(mycode)
|
||||
}
|
||||
|
||||
fn obj_init(obj_ GiteaServer) !GiteaServer {
|
||||
// never call get here, only thing we can do here is work on object itself
|
||||
mut obj := obj_
|
||||
return obj
|
||||
/////////////NORMALLY NO NEED TO TOUCH
|
||||
|
||||
pub fn heroscript_dumps(obj GiteaServer) !string {
|
||||
return encoderhero.encode[GiteaServer ](obj)!
|
||||
}
|
||||
|
||||
// called before start if done
|
||||
fn configure() ! {
|
||||
// mut installer := get()!
|
||||
|
||||
// mut mycode := $tmpl('templates/atemplate.yaml')
|
||||
// mut path := pathlib.get_file(path: cfg.configpath, create: true)!
|
||||
// path.write(mycode)!
|
||||
// console.print_debug(mycode)
|
||||
pub fn heroscript_loads(heroscript string) !GiteaServer {
|
||||
mut obj := encoderhero.decode[GiteaServer](heroscript)!
|
||||
return obj
|
||||
}
|
||||
|
||||
@@ -6,31 +6,24 @@ To get started
|
||||
|
||||
```vlang
|
||||
|
||||
import freeflowuniverse.herolib.installers.infra.gitea as gitea_installer
|
||||
|
||||
|
||||
import freeflowuniverse.herolib.installers.something. gitea
|
||||
|
||||
mut installer:= gitea.get()!
|
||||
//if you want to configure using heroscript
|
||||
gitea_installer.play(heroscript:'
|
||||
!!gitea.configure name:test
|
||||
passwd:'something'
|
||||
domain: 'docs.info.com'
|
||||
')!
|
||||
|
||||
mut installer:= gitea_installer.get(name:'test')!
|
||||
installer.start()!
|
||||
|
||||
|
||||
|
||||
|
||||
```
|
||||
|
||||
## example heroscript
|
||||
|
||||
|
||||
```hero
|
||||
!!gitea.install
|
||||
homedir: '/home/user/gitea'
|
||||
username: 'admin'
|
||||
password: 'secretpassword'
|
||||
title: 'Some Title'
|
||||
host: 'localhost'
|
||||
port: 8888
|
||||
|
||||
```
|
||||
|
||||
|
||||
this will look for a configured mail & postgresql client both on instance name: "default", change in heroscript if needed
|
||||
|
||||
- postgresql_client_name = "default"
|
||||
- mail_client_name = "default"
|
||||
@@ -1,6 +1,6 @@
|
||||
APP_NAME = ${server.name}
|
||||
RUN_MODE = prod
|
||||
RUN_USER = ${server.run_user}
|
||||
|
||||
WORK_PATH = ${server.path}
|
||||
|
||||
[repository]
|
||||
@@ -26,12 +26,12 @@ LFS_JWT_SECRET = ${server.lfs_jwt_secret}
|
||||
OFFLINE_MODE = false
|
||||
|
||||
[database]
|
||||
PATH = ${server.path}/gitea.db
|
||||
PATH = /tmp/gitea.db
|
||||
DB_TYPE = postgres
|
||||
HOST = ${server.database_host}:${server.database_port}
|
||||
NAME = ${server.database_name}
|
||||
USER = ${server.database_user}
|
||||
PASSWD = ${server.database_passwd}
|
||||
HOST = ${db_client.host}:${db_client.port}
|
||||
NAME = ${db_client.dbname}
|
||||
USER = ${db_client.user}
|
||||
PASSWD = ${db_client.password}
|
||||
LOG_SQL = false
|
||||
SCHEMA =
|
||||
SSL_MODE = disable
|
||||
@@ -80,12 +80,12 @@ PATH = ${server.path}/lfs
|
||||
|
||||
[mailer]
|
||||
ENABLED = true
|
||||
FROM = ${server.mail_from}
|
||||
FROM = ${mail_client.mail_from}
|
||||
; PROTOCOL = smtps
|
||||
SMTP_ADDR = ${server.smtp_addr}
|
||||
SMTP_PORT = ${server.smtp_port}
|
||||
USER = ${server.smtp_login}
|
||||
PASSWD = ${server.smtp_passwd}
|
||||
SMTP_ADDR = ${mail_client.mail_server}
|
||||
SMTP_PORT = ${mail_client.mail_port}
|
||||
USER = ${mail_client.mail_username}
|
||||
PASSWD = ${mail_client.mail_password}
|
||||
|
||||
[openid]
|
||||
ENABLE_OPENID_SIGNIN = true
|
||||
@@ -105,4 +105,3 @@ JWT_SECRET = ${server.jwt_secret}
|
||||
|
||||
[actions]
|
||||
ENABLED=true
|
||||
|
||||
|
||||
@@ -30,6 +30,12 @@ fn load_test_cache() TestCache {
|
||||
} }
|
||||
}
|
||||
|
||||
fn in_github_actions() bool{
|
||||
a:=os.environ()["GITHUB_ACTIONS"] or {return false}
|
||||
return true
|
||||
}
|
||||
|
||||
|
||||
// Save the test cache to JSON file
|
||||
fn save_test_cache(cache TestCache) {
|
||||
json_str := json.encode_pretty(cache)
|
||||
@@ -72,7 +78,7 @@ fn get_cache_key(path string, base_dir string) string {
|
||||
}
|
||||
|
||||
// Check if a file should be ignored or marked as error based on its path
|
||||
fn process_test_file(path string, base_dir string, test_files_ignore []string, test_files_error []string, mut cache TestCache, mut tests_in_error []string) ! {
|
||||
fn process_test_file(path string, base_dir string, test_files_ignore []string, test_files_error []string, mut cache TestCache) ! {
|
||||
// Get normalized paths
|
||||
norm_path, rel_path := get_normalized_paths(path, base_dir)
|
||||
|
||||
@@ -85,28 +91,21 @@ fn process_test_file(path string, base_dir string, test_files_ignore []string, t
|
||||
|
||||
// Check if any ignore pattern matches the path
|
||||
for pattern in test_files_ignore {
|
||||
if pattern.trim_space() != '' && rel_path.contains(pattern) {
|
||||
should_ignore = true
|
||||
break
|
||||
println('Check ignore test: ${pattern} -- ${rel_path} ::: ${rel_path.contains(pattern.trim_space())}')
|
||||
if pattern.trim_space() != '' && rel_path.contains(pattern.trim_space()) {
|
||||
println('Ignoring test: ${rel_path}')
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// Check if any error pattern matches the path
|
||||
for pattern in test_files_error {
|
||||
if pattern.trim_space() != '' && rel_path.contains(pattern) {
|
||||
is_error = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if !should_ignore && !is_error {
|
||||
dotest(norm_path, base_dir, mut cache)!
|
||||
} else {
|
||||
println('Ignoring test: ${rel_path}')
|
||||
if !should_ignore {
|
||||
tests_in_error << rel_path
|
||||
if pattern.trim_space() != '' && rel_path.contains(pattern.trim_space()) {
|
||||
println('Ignoring test because is error: ${rel_path}')
|
||||
return
|
||||
}
|
||||
}
|
||||
dotest(norm_path, base_dir, mut cache)!
|
||||
}
|
||||
|
||||
fn dotest(path string, base_dir string, mut cache TestCache) ! {
|
||||
@@ -173,17 +172,24 @@ lib/develop
|
||||
'
|
||||
|
||||
// the following tests have no prio and can be ignored
|
||||
tests_ignore := '
|
||||
mut tests_ignore := '
|
||||
notifier_test.v
|
||||
clients/meilisearch
|
||||
clients/zdb
|
||||
clients/openai
|
||||
systemd_process_test.v
|
||||
|
||||
// We should fix that one
|
||||
data/graphdb
|
||||
data/radixtree
|
||||
clients/livekit
|
||||
'
|
||||
|
||||
|
||||
|
||||
if in_github_actions(){
|
||||
println("**** WE ARE IN GITHUB ACTION")
|
||||
tests_ignore+="\nosal/tmux\n"
|
||||
}
|
||||
|
||||
tests_error := '
|
||||
tmux_window_test.v
|
||||
tmux_test.v
|
||||
@@ -208,12 +214,13 @@ test_files := tests.split('\n').filter(it.trim_space() != '')
|
||||
test_files_ignore := tests_ignore.split('\n').filter(it.trim_space() != '')
|
||||
test_files_error := tests_error.split('\n').filter(it.trim_space() != '')
|
||||
|
||||
mut tests_in_error := []string{}
|
||||
|
||||
// Load test cache
|
||||
mut cache := load_test_cache()
|
||||
println('Test cache loaded from ${cache_file}')
|
||||
|
||||
println("tests to ignore")
|
||||
println(tests_ignore)
|
||||
|
||||
// Run each test with proper v command flags
|
||||
for test in test_files {
|
||||
if test.trim_space() == '' || test.trim_space().starts_with('//')
|
||||
@@ -232,21 +239,12 @@ for test in test_files {
|
||||
// If directory, run tests for each .v file in it recursively
|
||||
files := os.walk_ext(full_path, '.v')
|
||||
for file in files {
|
||||
process_test_file(file, norm_dir_of_script, test_files_ignore, test_files_error, mut
|
||||
cache, mut tests_in_error)!
|
||||
process_test_file(file, norm_dir_of_script, test_files_ignore, test_files_error, mut cache)!
|
||||
}
|
||||
} else if os.is_file(full_path) {
|
||||
process_test_file(full_path, norm_dir_of_script, test_files_ignore, test_files_error, mut
|
||||
cache, mut tests_in_error)!
|
||||
process_test_file(full_path, norm_dir_of_script, test_files_ignore, test_files_error, mut cache)!
|
||||
}
|
||||
}
|
||||
|
||||
println('All (non skipped) tests ok')
|
||||
|
||||
if tests_in_error.len > 0 {
|
||||
println('\n\033[31mTests that need to be fixed (not executed):')
|
||||
for test in tests_in_error {
|
||||
println(' ${test}')
|
||||
}
|
||||
println('\033[0m')
|
||||
}
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
import db.sqlite
|
||||
|
||||
fn main() {
|
||||
db := sqlite.connect(':memory:')!
|
||||
println('SQLite connection successful')
|
||||
db.close()!
|
||||
}
|
||||
97
workflows/hero_build_linux.yml
Normal file
97
workflows/hero_build_linux.yml
Normal file
@@ -0,0 +1,97 @@
|
||||
name: Build Hero on Linux & Run tests
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
|
||||
on:
|
||||
push:
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
build:
|
||||
strategy:
|
||||
matrix:
|
||||
include:
|
||||
- target: x86_64-unknown-linux-musl
|
||||
os: ubuntu-latest
|
||||
short-name: linux-i64
|
||||
# - target: aarch64-unknown-linux-musl
|
||||
# os: ubuntu-latest
|
||||
# short-name: linux-arm64
|
||||
# - target: aarch64-apple-darwin
|
||||
# os: macos-latest
|
||||
# short-name: macos-arm64
|
||||
# - target: x86_64-apple-darwin
|
||||
# os: macos-13
|
||||
# short-name: macos-i64
|
||||
runs-on: ${{ matrix.os }}
|
||||
steps:
|
||||
- run: echo "🎉 The job was automatically triggered by a ${{ github.event_name }} event."
|
||||
- run: echo "🐧 This job is now running on a ${{ runner.os }} server hosted by GitHub!"
|
||||
- run: echo "🔎 The name of your branch is ${{ github.ref_name }} and your repository is ${{ github.repository }}."
|
||||
|
||||
- name: Check out repository code
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Setup Vlang
|
||||
run: |
|
||||
git clone --depth=1 https://github.com/vlang/v
|
||||
cd v
|
||||
make
|
||||
sudo ./v symlink
|
||||
cd ..
|
||||
|
||||
- name: Setup Herolib
|
||||
run: |
|
||||
mkdir -p ~/.vmodules/freeflowuniverse
|
||||
ln -s $GITHUB_WORKSPACE/lib ~/.vmodules/freeflowuniverse/herolib
|
||||
|
||||
echo "Installing secp256k1..."
|
||||
# Install build dependencies
|
||||
sudo apt-get install -y build-essential wget autoconf libtool
|
||||
|
||||
# Download and extract secp256k1
|
||||
cd /tmp
|
||||
wget https://github.com/bitcoin-core/secp256k1/archive/refs/tags/v0.3.2.tar.gz
|
||||
tar -xvf v0.3.2.tar.gz
|
||||
|
||||
# Build and install
|
||||
cd secp256k1-0.3.2/
|
||||
./autogen.sh
|
||||
./configure
|
||||
make -j 5
|
||||
sudo make install
|
||||
|
||||
# Cleanup
|
||||
rm -rf secp256k1-0.3.2 v0.3.2.tar.gz
|
||||
|
||||
echo "secp256k1 installation complete!"
|
||||
|
||||
- name: Install and Start Redis
|
||||
run: |
|
||||
# Import Redis GPG key
|
||||
curl -fsSL https://packages.redis.io/gpg | sudo gpg --dearmor -o /usr/share/keyrings/redis-archive-keyring.gpg
|
||||
# Add Redis repository
|
||||
echo "deb [signed-by=/usr/share/keyrings/redis-archive-keyring.gpg] https://packages.redis.io/deb $(lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/redis.list
|
||||
# Install Redis
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y redis
|
||||
|
||||
# Start Redis
|
||||
redis-server --daemonize yes
|
||||
|
||||
# Print versions
|
||||
redis-cli --version
|
||||
redis-server --version
|
||||
|
||||
- name: Build Hero
|
||||
run: |
|
||||
v -cg -enable-globals -w -n cli/hero.v
|
||||
|
||||
- name: Do all the basic tests
|
||||
run: |
|
||||
./test_basic.vsh
|
||||
env:
|
||||
LIVEKIT_API_KEY: ${{secrets.LIVEKIT_API_KEY}}
|
||||
LIVEKIT_API_SECRET: ${{secrets.LIVEKIT_API_SECRET}}
|
||||
LIVEKIT_URL: ${{secrets.LIVEKIT_URL}}
|
||||
@@ -3,10 +3,6 @@ name: Build Hero on Macos & Run tests
|
||||
permissions:
|
||||
contents: write
|
||||
|
||||
on:
|
||||
push:
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
build:
|
||||
strategy:
|
||||
Reference in New Issue
Block a user