Compare commits

...

64 Commits

Author SHA1 Message Date
29c2fccbe5 bump version to 1.0.14 2025-02-19 16:14:20 +03:00
975c07fc2e ... 2025-02-19 16:09:11 +03:00
ff45beac09 ... 2025-02-19 09:46:41 +03:00
24eb709293 fixes docusaurus 2025-02-19 09:44:03 +03:00
49e2146152 Merge branch 'development_bizmodel' into development_installers 2025-02-19 07:15:28 +03:00
cdaf64b3cf git print better 2025-02-19 07:15:14 +03:00
49af31776e gitools 2025-02-19 05:53:29 +03:00
0880823576 Merge branch 'development_installers' of github.com:freeflowuniverse/herolib into development_installers 2025-02-19 05:10:45 +03:00
1fa1ecb8ec Merge branch 'development_fix' into development_installers 2025-02-19 05:09:56 +03:00
d6108c9836 Merge branch 'development' into development_installers 2025-02-19 05:08:41 +03:00
timurgordon
cc344fa60e bizmodel example report export wip 2025-02-18 23:23:26 +03:00
timurgordon
5e468359a1 start implementing docusaurus bizmodel exporting 2025-02-18 05:09:56 +03:00
timurgordon
2317dd2d4c tidy up action processing & playing 2025-02-18 05:09:06 +03:00
timurgordon
b92647c52e fix sheet processing issues 2025-02-18 05:07:56 +03:00
timurgordon
54024ee222 bizmodel example wip 2025-02-17 18:40:11 +03:00
60d6474a42 ... 2025-02-17 08:29:57 +03:00
8c52326550 ... 2025-02-17 06:41:19 +03:00
52aba347a8 ... 2025-02-17 06:40:06 +03:00
Mahmoud Emad
61a0fd2aa6 chore: Change the factories 2025-02-16 11:12:59 +00:00
Mahmoud Emad
d604d739e3 feat: Support garage_s3 installer
- Added a new config template file to be loaded when starting the server
- Run the server in zinit as a service
- Fix the install, destroy, installed, and running functions
2025-02-16 11:10:27 +00:00
Mahmoud Emad
a57f53fdb4 feat: Improved rclone installer 2025-02-16 08:56:28 +00:00
Mahmoud Emad
f276cdf697 feat: Improved tailwind installer 2025-02-16 08:15:43 +00:00
Mahmoud Emad
7fb46a4c0b feat: Improved b2 installer 2025-02-16 07:48:11 +00:00
Mahmoud Emad
fc993a95d7 feat: simplify actrunner installer
- Remove unnecessary dependencies and simplify the actrunner installation process.
2025-02-16 07:19:03 +00:00
c6ff7e7ba5 Merge branch 'development' of github.com:freeflowuniverse/herolib into development 2025-02-16 10:05:41 +03:00
3f9a3fb1cd caldav... 2025-02-16 10:05:35 +03:00
7ae4f7dbd0 mail/contacts... 2025-02-16 09:30:51 +03:00
dbb44ec30a mail 2025-02-16 08:25:25 +03:00
7f4fc42a7a mail 2025-02-16 07:49:06 +03:00
01db4540b1 imap 2025-02-16 06:44:43 +03:00
5c0c096a79 Merge pull request #64 from freeflowuniverse/development_coredns
Development coredns
2025-02-13 19:19:09 +02:00
c1719a057a Merge pull request #62 from freeflowuniverse/development_coredns
coredns
2025-02-13 19:10:13 +02:00
e969eacd06 fix(golang): add go path to env 2025-02-13 16:56:45 +00:00
8ed3439cdc fix(coredns): comment getting machine public ip 2025-02-13 16:13:15 +00:00
Mahmoud Emad
5241dfddd4 refactor: rename mycelium to mycelium_installer
- Renamed the `mycelium` module to `mycelium_installer` to improve clarity and avoid naming conflicts.
- Updated all related files and references to reflect the name change.
2025-02-13 13:29:16 +00:00
Mahmoud Emad
6e0572b48a chore: restructure the installers for organize the installers 2025-02-13 13:11:49 +00:00
Mahmoud Emad
9a4a39b19a feat: add screen installer
- Add a new screen installer to the project.
2025-02-13 13:01:48 +00:00
Mahmoud Emad
8abf113715 feat: improve LiveKit installer
- Implement key generation for LiveKit.
- Improve health check for LiveKit server.
- Add support for different startup managers.
- Simplify installation process.
- Remove unnecessary code.
- Update dependencies.
2025-02-13 12:52:03 +00:00
25c997fec5 fix(coredns): fixes in coredns installer and client 2025-02-12 17:55:36 +02:00
Mahmoud Emad
1546bf7f87 chore: Format the installers 2025-02-12 14:29:07 +00:00
Mahmoud Emad
02d4adcff0 refactor: improve gitea installer
- Simplify gitea installer logic.
- Remove unnecessary variables and functions.
- Improve code readability and maintainability.
- Update gitea version to 1.23.3.
- Add default values for GiteaServer fields.
- Remove redundant installer.v and server.v files.
2025-02-12 14:27:18 +00:00
Mahmoud Emad
147c889b53 feat: Add ZeroDB installer
- Add a new ZeroDB installer to the installers.
2025-02-12 13:44:52 +00:00
Mahmoud Emad
f6e7644284 refactor: Improve dagu, meilisearch, and postgres installers
- Remove redundant code and improve the overall structure of the installer actions.
- Add more robust error handling and logging.
- Update the postgres and dagu `destroy` function to properly remove all related services.
- Improve the `install` function to ensure all necessary components are installed.
2025-02-12 12:07:38 +00:00
Mahmoud Emad
582da6d7f0 feat: add wireguard installer
- Add a new wireguard installer to the installers.
2025-02-12 11:24:16 +00:00
Mahmoud Emad
3a337b7b0a refactor: fix meilisearch installler and rename meilisearchinstaller to meilisearch_installer
- Renamed the `meilisearchinstaller` module and related files to  `meilisearch_installer` for consistency.
- Updated import statements and references accordingly.
- Added functionality to install, start, and destroy the  Meilisearch service.
- Improved code readability and organization.
2025-02-12 11:06:08 +00:00
Mahmoud Emad
2953dd0172 fix: simplify meilisearch destroy action
- Remove unnecessary code from the `destroy` function in the `meilisearchinstaller_actions.v` file.
- NOTE: Couldn't test it due to the new hero update, don't know how even send the configs, WIP.
2025-02-12 09:31:39 +00:00
Mahmoud Emad
08f0620305 feat: add rust installer
- Add a new Rust installer.
- Fix some issues with the rust installer.
- better organize the language-specific installers.
2025-02-12 09:28:10 +00:00
Mahmoud Emad
ec22a8e0ec refactor: improve installer code
- Refactor installer code for better readability and maintainability.
- Move `dagu_server.vsh` to `examples/virt/daguserver/dagu_server.vsh`.
- Remove unnecessary `println` statements.
- Improve error handling in `zinit_installer_actions.v`.
- Update `zinit_installer_actions.v` startup type to systemd.
- Refactor several factory functions.
2025-02-12 09:02:33 +00:00
Mahmoud Emad
be4d2547e4 refactor: Improved the hero generator, removed unneeded lines 2025-02-11 11:18:04 +00:00
Mahmoud Emad
a7f8893399 feat: Improved the zinit installer, 2025-02-11 11:11:21 +00:00
Mahmoud-Emad
d0b52f40b7 feat: Improved the pacman installer, added an example 2025-02-11 10:32:15 +00:00
3117d288b1 WIP(osal.coredns): add example for coredns usage
- added openssl and iproute2 installation to install_v.sh since they're
  needed in coredns installation and usage.
- fixed bug in coredns build process.
- fixed bug in getting own public ip.
- fixed bugs in json encoding dns records before pushing to redis
2025-02-10 17:07:49 +00:00
Mahmoud-Emad
6ecd190de8 feat: Improved the docker installer, added an example 2025-02-10 13:53:53 +00:00
Mahmoud-Emad
dacd6d5afb feat: Improved the nodejs installer, added an example 2025-02-10 13:49:27 +00:00
Mahmoud-Emad
de0e66a94a feat: Improved the python installer, added an example 2025-02-10 12:08:49 +00:00
Mahmoud-Emad
e86504ecd5 feat: Improved the griddriver installer, added an example 2025-02-10 11:51:39 +00:00
Mahmoud-Emad
1b192328b2 feat: Add an example for golang usage 2025-02-10 11:39:53 +00:00
Mahmoud-Emad
77a77ff87e fix: Rename zinit files to zinit_installer 2025-02-10 11:35:21 +00:00
Mahmoud-Emad
439dff4a64 fix: Updated the golang installer 2025-02-10 11:34:45 +00:00
Mahmoud-Emad
f8cb6f25f7 fix: Rename zinit files to zinit_installer 2025-02-10 11:23:38 +00:00
Mahmoud-Emad
c157c86600 refactor: move zinit installer to infra
- Move the zinit installer from `sysadmintools` to `infra`.
- This change improves the organization of the codebase and
- makes it easier to find and manage installers.  The old
- `zinit` module was a factory only and is removed.  The
- `zinit_installer` is now a normal installer.  The code is
- significantly refactored.
2025-02-10 09:00:49 +00:00
cb0110ed20 ... 2025-02-09 17:53:16 +01:00
2bbf814003 ... 2025-02-09 17:44:40 +01:00
86e3fdb910 WIP(osal.coredns): add example for coredns usage
- create an example to use coredns module for adding dns records
- fix module errors
2025-02-09 18:06:16 +02:00
244 changed files with 6536 additions and 4676 deletions

View File

@@ -51,7 +51,7 @@ fn do() ! {
mut cmd := Command{
name: 'hero'
description: 'Your HERO toolset.'
version: '1.0.13'
version: '1.0.14'
}
// herocmds.cmd_run_add_flags(mut cmd)

View File

@@ -0,0 +1,2 @@
bizmodel
dest

View File

@@ -0,0 +1,41 @@
#!/usr/bin/env -S v -n -w -cg -gc none -no-retry-compilation -cc tcc -d use_openssl -enable-globals run
//#!/usr/bin/env -S v -cg -enable-globals run
import freeflowuniverse.herolib.data.doctree
import freeflowuniverse.herolib.biz.bizmodel
import freeflowuniverse.herolib.core.playbook
import freeflowuniverse.herolib.core.playcmds
import freeflowuniverse.herolib.web.mdbook
import os
const wikipath = os.dir(@FILE) + '/wiki'
const summarypath = os.dir(@FILE) + '/wiki/summary.md'
buildpath := '${os.home_dir()}/hero/var/mdbuild/bizmodel'
mut m := bizmodel.getset('example')!
m.workdir = wikipath
m.play(mut playbook.new(path: wikipath)!)!
m.export_sheets()!
bizmodel.set(m)
// // execute the actions so we have the info populated
// // playcmds.run(mut plb,false)!
// // just run the doctree & mdbook and it should
// // load the doctree, these are all collections
// mut tree := doctree.new(name: 'bizmodel')!
// tree.scan(path: wikipath)!
// tree.export(dest: buildpath, reset: true)!
// // mut bm:=bizmodel.get("test")!
// // println(bm)
// mut mdbooks := mdbook.get()!
// mdbooks.generate(
// name: 'bizmodel'
// summary_path: summarypath
// doctree_path: buildpath
// title: 'bizmodel example'
// )!
// mdbook.book_open('bizmodel')!

View File

@@ -0,0 +1,10 @@
## Loader instructions
this will make sure we load the appropriate biz model
```js
!!bizmodel.load name:'default' url:'https://github.com/freeflowuniverse/herolib/tree/development/bizmodel/example/data'
```

View File

@@ -0,0 +1 @@
name:bizmodel_example

View File

@@ -0,0 +1,10 @@
![](img/ms1bmodel.png)
# bizmodel
OurWorld has developed a tool to generate and keep business models up to date.
Our aim is to make it easy for ourworld to track changes in planning over the multiple projects and even be able to aggregated them. Because the input for such a plan is text (as you can see in this ebook) its easy to see how the modelling and parameters change over time.
This is a very flexible tool which will be extended for budgetting, cashflow management, shareholder tables, ...

View File

@@ -0,0 +1,4 @@
# Debug
Some tools and info to help debug the bizmodel simulator.

View File

@@ -0,0 +1,8 @@
# Hr Overview
!!!bizmodel.employees_wiki bizname:'test'
> note: Nr People like 0:5,20:5 means, month 0 (start) is 5, month 20 its 5 people

View File

@@ -0,0 +1,5 @@
# CTO
!!!bizmodel.employee_wiki bizname:'test' name:'despiegk'
!!wiki.include page:cto_description.md

View File

@@ -0,0 +1,3 @@
## CTO Description
this is a page to test nested includes

View File

@@ -0,0 +1 @@
ms1bmodel.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 MiB

View File

@@ -0,0 +1,52 @@
# This is our business model planner
## P&L Overview
<!-- period is in months, 3 means every quarter -->
!!bizmodel.graph_bar_row rowname:revenue_total unit:million title:'A Title' title_sub:'Sub' sheetname:'bizmodel_test'
Unit is in Million USD.
!!bizmodel.graph_bar_row rowname:revenue_total unit:million sheetname:'bizmodel_test'
!!bizmodel.graph_line_row rowname:revenue_total unit:million sheetname:'bizmodel_test'
!!bizmodel.graph_pie_row rowname:revenue_total unit:million size:'80%' sheetname:'bizmodel_test'
## FUNDING
!!bizmodel.sheet_wiki includefilter:'funding' sheetname:'bizmodel_test'
!!bizmodel.sheet_wiki title:'REVENUE' includefilter:rev sheetname:'bizmodel_test'
!!bizmodel.sheet_wiki title:'Revenue Total' includefilter:'revtotal' sheetname:'bizmodel_test'
!!bizmodel.sheet_wiki title:'REVENUE' includefilter:'revtotal2' sheetname:'bizmodel_test'
!!bizmodel.sheet_wiki title:'COGS' includefilter:'cogs' sheetname:'bizmodel_test'
!!bizmodel.sheet_wiki title:'Margin' includefilter:'margin' sheetname:'bizmodel_test'
!!bizmodel.sheet_wiki title:'HR Teams' includefilter:'hrnr' sheetname:'bizmodel_test'
!!bizmodel.sheet_wiki title:'HR Costs' includefilter:'hrcost' sheetname:'bizmodel_test'
!!bizmodel.sheet_wiki title:'COSTS' includefilter:'ocost' sheetname:'bizmodel_test'
!!bizmodel.sheet_wiki title:'HR Costs' includefilter:'hrcost' sheetname:'bizmodel_test'
!!bizmodel.sheet_wiki title:'P&L Overview' includefilter:'pl' sheetname:'bizmodel_test'
!!bizmodel.sheet_wiki title:'P&L Overview' includefilter:'pl' sheetname:'bizmodel_test'
## Some Details
> show how we can do per month
!!bizmodel.sheet_wiki includefilter:'pl' period_months:1 sheetname:'bizmodel_test'

View File

@@ -0,0 +1,31 @@
# HR Params
## Engineering
Costs can be grouped in cost centers which can then be used to futher process e.g. transcactions between companies.
```js
!!bizmodel.costcenter_define bizname:'test'
name:'tfdmcc'
descr:'TFDMCC executes on near source agreement for TFTech'
min_month:'10000USD'
max_month:'100000USD'
end_date:'1/1/2026' //when does agreement stop
!!bizmodel.costcenter_define bizname:'test'
name:'cs_tftech'
descr:'Nearsource agreement for TFTech towards Codescalers'
min_month:'10000USD'
max_month:'100000USD'
end_date:'1/1/2026'
!!bizmodel.costcenter_define bizname:'test'
name:'cs_tfcloud'
descr:'Nearsource agreement for TFCloud towards Codescalers'
min_month:'10000USD'
max_month:'100000USD'
end_date:'1/1/2026'
```

View File

@@ -0,0 +1,39 @@
# Generic Overhead Costs
possible parameters
- name
- descr: description of the cost
- cost: is 'month:amount,month:amount, ...', no extrapolation
- cost_growth: is 'month:amount,month:amount, ..., or just a nr', will extrapolate
- type: travel, admin, legal, varia, office
- cost_percent_revenue e.g. 4%, will make sure the cost will be at least 4% of revenue
- indexation, e.g. 2%
Other financial flows can be mentioned here as well.
```js
!!bizmodel.cost_define bizname:'test'
name:'rental'
descr:'Office Rental in BE.'
cost:'5000'
indexation:'2%'
type:'office'
!!bizmodel.cost_define bizname:'test'
name:'oneoff'
descr:'Event in Z.'
cost_one:'3:50000'
type:'event'
!!bizmodel.cost_define bizname:'test'
name:'cloud'
descr:'Datacenter and Cloud Costs'
cost:'2000eur'
cost_percent_revenue:'2%'
type:'cloud'
```

View File

@@ -0,0 +1,20 @@
# Department Params
```js
!!bizmodel.department_define bizname:'test'
name:'ops'
title:'Operations'
order:5
!!bizmodel.department_define bizname:'test'
name:'coordination'
title:'Coordination'
order:1
!!bizmodel.department_define bizname:'test'
name:'engineering'
title:'Engineering'
order:4
```

View File

@@ -0,0 +1,29 @@
# Funding Params
possible parameters
- name, e.g. for a specific person
- descr: description of the funding
- investment is month:amount,month:amount, ...
- type: loan or capital
Other financial flows can be mentioned here as well.
```js
!!bizmodel.funding_define bizname:'test'
name:'our_investor'
descr:'A fantastic super investor.'
investment:'3:1000000EUR'
type:'capital'
!!bizmodel.funding_define bizname:'test'
name:'a_founder'
descr:'Together Are Strong'
investment:'2000000'
type:'loan'
```

View File

@@ -0,0 +1,73 @@
# HR Params
## Engineering
possible parameters
- descr, description of the function (e.g. master architect)
- cost, any currency eg. 1000usd
- in case cost changes over time e.g. 1:10000USD,20:20000USD,60:30000USD
- indexation, e.g. 2%
- department
- name, e.g. for a specific person
- nrpeople: how many people per month, growth over time notation e.g. 1:10,60:20 means 10 in month 1 growing to 20 month 60
- cost_percent_revenue e.g. 4%, will make sure the cost will be at least 4% of revenue
```js
!!bizmodel.employee_define bizname:'test'
sid:2
descr:'Senior Engineer'
cost:'1:12000,12:14000' //cost is always per person
department:'engineering'
nrpeople:'0:5,20:5'
!!bizmodel.employee_define bizname:'test'
name:'despiegk'
title: 'CTO and crazy inventor.'
sid:3
descr:'CTO'
cost:'12000EUR' //the salary is the cost independent of the fulltime status
indexation:'10%'
department:'coordination'
page:'cto.md'
fulltime: "50%" //100% means yes
!!bizmodel.employee_define bizname:'test'
descr:'Senior Architect'
cost:'10000USD' indexation:'5%'
department:'engineering'
nrpeople:'0:5,20:10'
!!bizmodel.employee_define bizname:'test'
descr:'Junior Engineer'
cost:'4000USD' indexation:'5%'
department:'engineering'
nrpeople:'0:5,20:10'
```
## Operations
```js
!!bizmodel.employee_define bizname:'test'
descr:'Ops Manager'
cost:'1:8000,12:14000'
department:'ops'
!!bizmodel.employee_define bizname:'test'
descr:'Support Junior'
cost:'2000EUR' indexation:'5%'
department:'ops'
nrpeople:'7:5,18:10'
cost_percent_revenue:'1%'
!!bizmodel.employee_define bizname:'test'
descr:'Support Senior'
cost:'5000EUR' indexation:'5%'
department:'ops'
nrpeople:'3:5,20:10'
cost_percent_revenue:'1%'
costcenter:'tfdmcc:25,cs_tfcloud:75'
generate_page:'../employees/support_senior.md'
```

View File

@@ -0,0 +1,14 @@
# Bizmodel Params
In this section we can find all the parameters for the bizmodel.
## how to use and read
The params are defined in the different instruction files e.g. revenue_params.md
Often you will see something like `revenue_growth:'10:1000,20:1100'` this can be read as month 10 it 1000, month 20 its 1100.
The software will extrapolate.

View File

@@ -0,0 +1,64 @@
# HR Params
## Revenue Items (non recurring)
This company is a cloud company ...
```js
!!bizmodel.revenue_define bizname:'test'
descr:'OEM Deals'
revenue_time:'10:1000000EUR,15:3333,20:1200000'
cogs_perc: '1:5%,20:10%'
!!bizmodel.revenue_define bizname:'test'
descr:'License Deals'
revenue_growth:'10:1000,20:1100'
cogs_perc: '10%'
rev_delay_month: 1
!!bizmodel.revenue_define bizname:'test'
descr:'3NODE License Sales 1 Time'
//means revenue is 100 month 1, 200 month 60
revenue_item:'1:100,60:200'
revenue_nr:'10:1000,24:2000,60:40000'
cogs_perc: '10%'
rev_delay_month: 1
```
## Revenue Items Recurring
possible parameters
- name, e.g. for a specific project
- descr, description of the revenue line item
- revenue_setup, revenue for 1 item '1000usd'
- revenue_monthly, revenue per month for 1 item
- revenue_setup_delay, how many months before revenue comes in after sales
- revenue_monthly_delay, how many months before monthly revenue starts
- cogs_setup, cost of good for 1 item at setup
- cogs_setup_perc: what is percentage of the cogs (can change over time) for setup e.g. 0:50%
- cogs_monthly, cost of goods for the monthly per 1 item
- cogs_monthly_perc: what is percentage of the cogs (can change over time) for monthly e.g. 0:5%,12:10%
- nr_sold: how many do we sell per month (is in growth format e.g. 10:100,20:200)
- nr_months: how many months is recurring
if currency not specified then is always in USD
```js
!!bizmodel.revenue_recurring_define bizname:'test'
name: '3node_lic'
descr:'3NODE License Sales Recurring Basic'
revenue_setup:'1:100,60:50'
// revenue_setup:'5'
revenue_monthly_delay:3
revenue_monthly:'1:1,60:1'
// cogs_setup:'1:0'
cogs_setup_perc:'50%'
revenue_setup_delay:1
cogs_monthly_perc:'50%'
nr_sold:'10:1000,24:2000,60:40000'
60 is the default
nr_months:60
```

View File

@@ -0,0 +1,13 @@
## Revenue
Overview of achieved revenue.
Unit is in Million USD.
!!bizmodel.sheet_wiki title:'REVENUE' includefilter:rev sheetname:'bizmodel_test'
!!bizmodel.graph_bar_row rowname:revenue_total unit:million sheetname:'bizmodel_test'
!!bizmodel.graph_line_row rowname:revenue_total unit:million sheetname:'bizmodel_test'
!!bizmodel.graph_pie_row rowname:revenue_total unit:million size:'80%' sheetname:'bizmodel_test'

View File

@@ -0,0 +1,13 @@
- [bizmodel](bizmodel_example/bizmodel.md)
- [Revenue](bizmodel_example/revenue.md)
- [Result](bizmodel_example/overview.md)
- [parameters](bizmodel_example/params.md)
- [revenue_params](bizmodel_example/params/revenue_params.md)
- [funding_params](bizmodel_example/params/funding_params.md)
- [hr_params](bizmodel_example/params/hr_params.md)
- [costs_params](bizmodel_example/params/costs_params.md)
- [rows overview](bizmodel_example/rows_overview.md)
- [employees](bizmodel_example/employees.md)
- [debug](bizmodel_example/debug.md)
- [worksheet](bizmodel_example/worksheet.md)

View File

@@ -0,0 +1,4 @@
# Overview of the rows in the biz model sheet
!!bizmodel.sheet_wiki sheetname:'bizmodel_test'

View File

@@ -0,0 +1,48 @@
#!/usr/bin/env -S v -cg -gc none -no-retry-compilation -cc tcc -d use_openssl -enable-globals run
// #!/usr/bin/env -S v -cg -enable-globals run
import freeflowuniverse.herolib.data.doctree
import freeflowuniverse.herolib.ui.console
import freeflowuniverse.herolib.biz.bizmodel
import freeflowuniverse.herolib.core.playbook
import freeflowuniverse.herolib.core.playcmds
import freeflowuniverse.herolib.web.mdbook
import freeflowuniverse.herolib.biz.spreadsheet
import os
const name = 'tf9_budget'
const wikipath = '${os.home_dir()}/code/git.ourworld.tf/ourworld_holding/info_ourworld/collections/${name}'
const summarypath = '${wikipath}/summary.md'
// mut sh := spreadsheet.sheet_new(name: 'test2') or { panic(err) }
// println(sh)
// sh.row_new(descr: 'this is a description', name: 'something', growth: '0:100aed,55:1000eur')!
// println(sh)
// println(sh.wiki()!)
// exit(0)
// execute the actions so we have the info populated
// mut plb:=playbook.new(path: wikipath)!
// playcmds.run(mut plb,false)!
buildpath := '${os.home_dir()}/hero/var/mdbuild/bizmodel'
// just run the doctree & mdbook and it should
// load the doctree, these are all collections
mut tree := doctree.new(name: name)!
tree.scan(path: wikipath)!
tree.export(dest: buildpath, reset: true)!
// mut bm:=bizmodel.get("test")!
// println(bm)
mut mdbooks := mdbook.get()!
mdbooks.generate(
name: 'bizmodel'
summary_path: summarypath
doctree_path: buildpath
title: 'bizmodel ${name}'
)!
mdbook.book_open('bizmodel')!

View File

@@ -0,0 +1,12 @@
need to find where the manual is
- [manual](bizmodel_example/configuration.md)
- [widgets](bizmodel_example/widgets.md)
- [graph_bar_row](bizmodel_example/graph_bar_row.md)
- [sheet_tables](bizmodel_example/sheet_tables.md)
- [widget_args](bizmodel_example/widget_args.md)
- [params](bizmodel_example/configuration.md)
- [revenue params](bizmodel_example/revenue_params.md)
- [funding params](bizmodel_example/funding_params.md)
- [hr params](bizmodel_example/hr_params.md)
- [costs params](bizmodel_example/costs_params.md)

View File

@@ -0,0 +1,11 @@
#!/usr/bin/env -S v -gc none -no-retry-compilation -cc tcc -d use_openssl -enable-globals run
import freeflowuniverse.herolib.biz.investortool
import freeflowuniverse.herolib.core.playbook
import os
mut plbook := playbook.new(
path: '${os.home_dir()}/code/git.ourworld.tf/ourworld_holding/investorstool/output'
)!
mut it := investortool.play(mut plbook)!
it.check()!

View File

@@ -1 +0,0 @@
#!/usr/bin/env -S v -n -w -gc none -cc tcc -d use_openssl -enable-globals run

View File

@@ -1 +0,0 @@
#!/usr/bin/env -S v -n -w -gc none -cc tcc -d use_openssl -enable-globals run

View File

@@ -1,15 +0,0 @@
#!/usr/bin/env -S v -n -w -gc none -cc tcc -d use_openssl -enable-globals run
import freeflowuniverse.herolib.installers.sysadmintools.daguserver
import freeflowuniverse.herolib.installers.infra.zinit
// make sure zinit is there and running, will restart it if needed
mut z := zinit.get()!
z.destroy()!
z.start()!
// mut ds := daguserver.get()!
// ds.destroy()!
// ds.start()!
// println(ds)

View File

@@ -0,0 +1,8 @@
#!/usr/bin/env -S v -n -w -gc none -cc tcc -d use_openssl -enable-globals run
import freeflowuniverse.herolib.installers.db.meilisearch_installer
mut meilisearch := meilisearch_installer.get()!
meilisearch.install()!
meilisearch.start()!
meilisearch.destroy()!

View File

@@ -0,0 +1,9 @@
#!/usr/bin/env -S v -n -w -gc none -cc tcc -d use_openssl -enable-globals run
import freeflowuniverse.herolib.installers.db.postgresql as postgresql_installer
mut db := postgresql_installer.get()!
db.install()!
db.start()!
db.destroy()!

View File

@@ -0,0 +1,9 @@
#!/usr/bin/env -S v -n -w -gc none -cc tcc -d use_openssl -enable-globals run
import freeflowuniverse.herolib.installers.db.zerodb as zerodb_installer
mut db := zerodb_installer.get()!
db.install()!
db.start()!
db.destroy()!

View File

@@ -1,16 +0,0 @@
#!/usr/bin/env -S v -n -w -gc none -cc tcc -d use_openssl -enable-globals run
import freeflowuniverse.herolib.installers.infra.gitea as gitea_installer
mut installer := gitea_installer.get(name: 'test')!
// if you want to configure using heroscript
gitea_installer.play(
heroscript: "
!!gitea.configure name:test
passwd:'something'
domain: 'docs.info.com'
"
)!
installer.start()!

View File

@@ -0,0 +1,8 @@
#!/usr/bin/env -S v -n -w -gc none -cc tcc -d use_openssl -enable-globals run
import freeflowuniverse.herolib.installers.infra.gitea as gitea_installer
mut gitea := gitea_installer.get()!
gitea.install()!
gitea.start()!
gitea.destroy()!

View File

@@ -0,0 +1,8 @@
#!/usr/bin/env -S v -n -w -gc none -cc tcc -d use_openssl -enable-globals run
import freeflowuniverse.herolib.installers.infra.livekit as livekit_installer
mut livekit := livekit_installer.get()!
livekit.install()!
livekit.start()!
livekit.destroy()!

View File

@@ -0,0 +1,8 @@
#!/usr/bin/env -S v -n -w -gc none -cc tcc -d use_openssl -enable-globals run
import freeflowuniverse.herolib.installers.infra.screen as screen_installer
mut screen := screen_installer.get()!
screen.install()!
screen.destroy()!

View File

@@ -1,6 +1,8 @@
#!/usr/bin/env -S v -n -w -gc none -cc tcc -d use_openssl -enable-globals run
import freeflowuniverse.herolib.installers.sysadmintools.zinit as zinit_installer
import freeflowuniverse.herolib.installers.infra.zinit_installer
mut installer := zinit_installer.get()!
installer.install()!
installer.start()!
// installer.destroy()!

View File

@@ -0,0 +1,6 @@
#!/usr/bin/env -S v -n -w -gc none -cc tcc -d use_openssl -enable-globals run
import freeflowuniverse.herolib.installers.lang.golang
mut golang_installer := golang.get()!
golang_installer.install()!

View File

@@ -0,0 +1,7 @@
#!/usr/bin/env -S v -n -w -gc none -cc tcc -d use_openssl -enable-globals run
import freeflowuniverse.herolib.installers.lang.nodejs
mut nodejs_installer := nodejs.get()!
// nodejs_installer.install()!
nodejs_installer.destroy()!

View File

@@ -0,0 +1,7 @@
#!/usr/bin/env -S v -n -w -gc none -cc tcc -d use_openssl -enable-globals run
import freeflowuniverse.herolib.installers.lang.python as python_module
mut python_installer := python_module.get()!
// python_installer.install()!
python_installer.destroy()!

View File

@@ -0,0 +1,7 @@
#!/usr/bin/env -S v -n -w -gc none -cc tcc -d use_openssl -enable-globals run
import freeflowuniverse.herolib.installers.lang.rust as rust_module
mut rust_installer := rust_module.get()!
// rust_installer.install()!
rust_installer.destroy()!

View File

@@ -1,6 +1,6 @@
#!/usr/bin/env -S v -n -w -gc none -cc tcc -d use_openssl -enable-globals run
import freeflowuniverse.herolib.installers.net.mycelium as mycelium_installer
import freeflowuniverse.herolib.installers.net.mycelium_installer
import freeflowuniverse.herolib.clients.mycelium
mut installer := mycelium_installer.get()!
@@ -13,25 +13,27 @@ mut client := mycelium.get()!
// Send a message to a node by public key
// Parameters: public_key, payload, topic, wait_for_reply
msg := client.send_msg('abc123...', // destination public key
'Hello World', // message payload
'greetings', // optional topic
true // wait for reply
)!
msg := client.send_msg(
public_key: 'abc123...' // destination public key
payload: 'Hello World' // message payload
topic: 'greetings' // optional topic
wait: true // wait for reply
)!
println('Sent message ID: ${msg.id}')
// Receive messages
// Parameters: wait_for_message, peek_only, topic_filter
received := client.receive_msg(true, false, 'greetings')!
received := client.receive_msg(wait: true, peek: false, topic: 'greetings')!
println('Received message from: ${received.src_pk}')
println('Message payload: ${received.payload}')
// Reply to a message
client.reply_msg(received.id, // original message ID
received.src_pk, // sender's public key
'Got your message!', // reply payload
'greetings' // topic
)!
client.reply_msg(
id: received.id // original message ID
public_key: received.src_pk // sender's public key
payload: 'Got your message!' // reply payload
topic: 'greetings' // topic
)!
// Check message status
status := client.get_msg_status(msg.id)!

View File

@@ -0,0 +1,7 @@
#!/usr/bin/env -S v -n -w -gc none -cc tcc -d use_openssl -enable-globals run
import freeflowuniverse.herolib.installers.net.wireguard_installer as wireguard
mut wireguard_installer := wireguard.get()!
wireguard_installer.install()!
wireguard_installer.destroy()!

View File

@@ -1,13 +0,0 @@
#!/usr/bin/env -S v -n -w -gc none -cc tcc -d use_openssl -enable-globals run
import time
import freeflowuniverse.herolib.installers.db.postgresql
mut db := postgresql.get()!
// db.destroy()!
db.start()!
// db.db_create('my_new_db')!
// db.stop()!
// db.start()!

View File

@@ -1,7 +1,8 @@
#!/usr/bin/env -S v -n -w -gc none -cc tcc -d use_openssl -enable-globals run
import freeflowuniverse.herolib.installers.sysadmintools.actrunner
import freeflowuniverse.herolib.installers.virt.herocontainers
// import freeflowuniverse.herolib.installers.virt.herocontainers
actrunner.install()!
mut actrunner_ := actrunner.get()!
actrunner_.install()!
// herocontainers.start()!

View File

@@ -0,0 +1,8 @@
#!/usr/bin/env -S v -n -w -gc none -cc tcc -d use_openssl -enable-globals run
import freeflowuniverse.herolib.installers.sysadmintools.garage_s3 as garage_s3_installer
mut garage_s3 := garage_s3_installer.get()!
garage_s3.install()!
garage_s3.start()!
garage_s3.destroy()!

View File

@@ -0,0 +1,7 @@
#!/usr/bin/env -S v -n -w -gc none -cc tcc -d use_openssl -enable-globals run
import freeflowuniverse.herolib.installers.sysadmintools.rclone as rclone_installer
mut rclone := rclone_installer.get()!
rclone.install()!
rclone.destroy()!

View File

@@ -4,3 +4,4 @@ import freeflowuniverse.herolib.installers.threefold.griddriver
mut griddriver_installer := griddriver.get()!
griddriver_installer.install()!
griddriver_installer.destroy()!

View File

@@ -0,0 +1,9 @@
#!/usr/bin/env -S v -n -w -gc none -cc tcc -d use_openssl -enable-globals run
import freeflowuniverse.herolib.installers.sysadmintools.daguserver
import freeflowuniverse.herolib.installers.infra.zinit_installer
mut ds := daguserver.get()!
ds.install()!
ds.start()!
ds.destroy()!

View File

@@ -0,0 +1,11 @@
#!/usr/bin/env -S v -n -w -gc none -cc tcc -d use_openssl -enable-globals run
import freeflowuniverse.herolib.installers.virt.pacman as pacman_installer
mut pacman := pacman_installer.get()!
// To install
pacman.install()!
// To remove
pacman.destroy()!

View File

@@ -0,0 +1,60 @@
#!/usr/bin/env -S v -n -w -cg -d use_openssl -enable-globals run
import freeflowuniverse.herolib.installers.infra.coredns as coredns_installer
import freeflowuniverse.herolib.osal.coredns
import freeflowuniverse.herolib.core.playbook
// coredns_installer.delete()!
mut installer := coredns_installer.get()!
// coredns_installer.fix()!
installer.start()!
mut script := "
!!dns.a_record
sub_domain: 'host1'
ip: '1.2.3.4'
ttl: 300
!!dns.aaaa_record
sub_domain: 'host1'
ip: '2001:db8::1'
ttl: 300
!!dns.mx_record
sub_domain: '*'
host: 'mail.example.com'
preference: 10
ttl: 300
!!dns.txt_record
sub_domain: '*'
text: 'v=spf1 mx ~all'
ttl: 300
!!dns.srv_record
service: 'ssh'
protocol: 'tcp'
host: 'host1'
target: 'sip.example.com'
port: 5060
priority: 10
weight: 100
ttl: 300
!!dns.ns_record
host: 'ns1.example.com'
ttl: 300
!!dns.soa_record
mbox: 'hostmaster.example.com'
ns: 'ns1.example.com'
refresh: 44
retry: 55
expire: 66
minttl: 100
ttl: 300
"
mut plbook := playbook.new(text: script)!
mut set := coredns.play_dns(mut plbook)!
set.set(key_prefix: 'dns:', domain: 'heroexample.com')!

View File

@@ -4,7 +4,7 @@ set -e
os_name="$(uname -s)"
arch_name="$(uname -m)"
version='1.0.13'
version='1.0.14'
# Base URL for GitHub releases

View File

@@ -181,7 +181,7 @@ function os_update {
fi
#apt install apt-transport-https ca-certificates curl software-properties-common -y -o Dpkg::Options::="--force-confdef" -o Dpkg::Options::="--force-confold" --force-yes
package_install "apt-transport-https ca-certificates curl wget software-properties-common tmux"
package_install "rclone rsync mc redis-server screen net-tools git dnsutils htop ca-certificates screen lsb-release binutils pkg-config"
package_install "rclone rsync mc redis-server screen net-tools git dnsutils htop ca-certificates screen lsb-release binutils pkg-config libssl-dev iproute2"
elif [[ "${OSNAME}" == "darwin"* ]]; then
if command -v brew >/dev/null 2>&1; then

155
lib/biz/bizmodel/act.v Normal file
View File

@@ -0,0 +1,155 @@
module bizmodel
import os
import freeflowuniverse.herolib.core.texttools
import freeflowuniverse.herolib.core.pathlib
import freeflowuniverse.herolib.core.playbook { PlayBook, Action }
import freeflowuniverse.herolib.ui.console
// import freeflowuniverse.herolib.core.texttools
import freeflowuniverse.herolib.data.paramsparser {Params}
import freeflowuniverse.herolib.biz.spreadsheet {RowGetArgs, UnitType, PeriodType}
pub fn (mut m BizModel) act(action Action) !Action {
return match texttools.snake_case(action.name) {
'funding_define' {
m.funding_define_action(action)!
}
'revenue_define' {
m.funding_define_action(action)!
}
'costcenter_define' {
m.costcenter_define_action(action)!
}
'cost_define' {
m.cost_define_action(action)!
}
'department_define' {
m.department_define_action(action)!
}
'employee_define' {
m.employee_define_action(action)!
}
'export_report' {
m.new_report_action(action)!
}
'sheet_wiki' {
m.export_sheet_action(action)!
}
'graph_bar_row' {
m.export_graph_bar_action(action)!
}
'graph_pie_row' {
m.export_graph_pie_action(action)!
}
'graph_line_row' {
m.export_graph_line_action(action)!
}
'row_overview' {
m.export_overview_action(action)!
}
else {
return error('Unknown operation: ${action.name}')
}
}
}
fn (mut m BizModel) export_sheet_action(action Action) !Action {
return m.export_action(m.sheet.wiki(row_args_from_params(action.params)!)!, action)
}
fn (mut m BizModel) export_graph_title_action(action Action) !Action {
return m.export_action(m.sheet.wiki_title_chart(row_args_from_params(action.params)!), action)
}
fn (mut m BizModel) export_graph_line_action(action Action) !Action {
return m.export_action(m.sheet.wiki_line_chart(row_args_from_params(action.params)!)!, action)
}
fn (mut m BizModel) export_graph_bar_action(action Action) !Action {
return m.export_action(m.sheet.wiki_bar_chart(row_args_from_params(action.params)!)!, action)
}
pub fn (mut m BizModel) export_graph_pie_action(action Action) !Action {
return m.export_action(m.sheet.wiki_pie_chart(row_args_from_params(action.params)!)!, action)
}
pub fn (mut m BizModel) export_overview_action(action Action) !Action {
return m.export_action(m.sheet.wiki_row_overview(row_args_from_params(action.params)!)!, action)
}
fn (mut m BizModel) new_report_action(action Action) !Action {
m.new_report(action.params.decode[Report]()!)!
return action
}
// fetches args for getting row from params
pub fn row_args_from_params(p Params) !RowGetArgs {
rowname := p.get_default('rowname', '')!
namefilter := p.get_list_default('namefilter', [])!
includefilter := p.get_list_default('includefilter', [])!
excludefilter := p.get_list_default('excludefilter', [])!
size := p.get_default('size', '')!
title_sub := p.get_default('title_sub', '')!
title := p.get_default('title', '')!
unit := p.get_default('unit', 'normal')!
unit_e := match unit {
'thousand' { UnitType.thousand }
'million' { UnitType.million }
'billion' { UnitType.billion }
else { UnitType.normal }
}
period_type := p.get_default('period_type', 'year')!
if period_type !in ['year', 'month', 'quarter'] {
return error('period type needs to be in year,month,quarter')
}
period_type_e := match period_type {
'year' { PeriodType.year }
'month' { PeriodType.month }
'quarter' { PeriodType.quarter }
else { PeriodType.error }
}
if period_type_e == .error {
return error('period type needs to be in year,month,quarter')
}
rowname_show := p.get_default_true('rowname_show')
descr_show := p.get_default_true('descr_show')
return RowGetArgs{
rowname: rowname
namefilter: namefilter
includefilter: includefilter
excludefilter: excludefilter
period_type: period_type_e
unit: unit_e
title_sub: title_sub
title: title
size: size
rowname_show: rowname_show
descr_show: descr_show
}
}
// creates the name for a file being exported given the params of the export action
fn (m BizModel) export_action(content string, action Action) !Action {
// determine name of file being exported
name := if action.params.exists('name') { action.params.get('name')! } else {
if action.params.exists('title') { action.params.get('title')! } else {
// if no name or title, name is ex: revenue_total_graph_bar_row
rowname := action.params.get_default('rowname', '')!
'${rowname}_${action.name}'
}
}
// by default exports to working dir of bizmodel
destination := action.params.get_default('destination', m.workdir)!
mut path := pathlib.get_file(
path: os.join_path(destination, name)
increment: true
empty: action.params.get_default_false('overwrite')
)!
path.write(content)!
return action
}

90
lib/biz/bizmodel/export.v Normal file
View File

@@ -0,0 +1,90 @@
module bizmodel
import os
import freeflowuniverse.herolib.web.docusaurus
import freeflowuniverse.herolib.core.texttools
import freeflowuniverse.herolib.core.pathlib
pub struct Export {
pub:
path string
overwrite bool
format ExportFormat
}
pub enum ExportFormat {
docusaurus
mdbook
}
pub struct Report {
pub:
name string
title string
description string
path string
sections []ReportSection
}
pub enum ReportSection {
revenue_model
cost_structure
human_resources
}
pub fn (b BizModel) new_report(report Report) !Report {
name := if report.name != '' {report.name} else { texttools.snake_case(report.title) }
path := pathlib.get_dir(
path: os.join_path(os.home_dir(), '/hero/var/bizmodel/reports/${name}')
)!
return Report {
...report,
name: name
path: path.path
}
// b.export_summary()
// b.export_business_description()
// b.export_market_analysis()
// b.export_business_model()
// b.export_revenue_model(export)!
// b.export_cost_structure(export)
// b.export_operational_plan(export)!
// b.export_fundraising(export)
}
pub fn (r Report) export(export Export) ! {
match export.format {
.docusaurus {
mut factory := docusaurus.new()!
mut site := factory.get(
name: r.name
path: r.path
publish_path: export.path
config: docusaurus.Config {} //TODO: is this needed
)!
site.build()!
}
.mdbook {panic('MDBook export not fully implemented')}
}
}
pub fn (b BizModel) export_operational_plan(export Export) ! {
mut hr_page := pathlib.get_file(path: '${export.path}/human_resources.md')!
hr_page.template_write('./templates/human_resources.md', export.overwrite)!
for key, employee in b.employees {
mut employee_page := pathlib.get_file(path: '${export.path}/${texttools.snake_case(employee.name)}.md')!
employee_page.template_write('./templates/employee.md', export.overwrite)!
}
}
pub fn (b BizModel) export_revenue_model(export Export) ! {
println('begin')
mut overview_page := pathlib.get_file(path: '${export.path}/revenue_overview.md')!
overview_page.template_write('./templates/overview.md', export.overwrite)!
for key, product in b.products {
mut product_page := pathlib.get_file(path: '${export.path}/${texttools.snake_case(product.name)}.md')!
product_page.template_write('./templates/product.md', export.overwrite)!
}
}

View File

@@ -0,0 +1,14 @@
module bizmodel
import os
import freeflowuniverse.herolib.web.docusaurus
const bizmodel_name = 'test'
const export_path = os.join_path(os.dir(@FILE), 'testdata')
pub fn test_export_report() ! {
model := getset(bizmodel_name)!
model.export_report(Report{
title: 'My Business Model'
}, path: export_path)!
}

View File

@@ -11,8 +11,8 @@ pub fn get(name string) !&BizModel {
if name in bizmodels {
return bizmodels[name] or { panic('bug') }
}
return error("cann't find biz model:'${name}' in global bizmodels ${bizmodels.keys()}")
}
return error("cann't find biz model:'${name}' in global bizmodels")
}
// get bizmodel from global

View File

@@ -1,10 +1,12 @@
module bizmodel
import os
import freeflowuniverse.herolib.biz.spreadsheet
pub struct BizModel {
pub mut:
name string
workdir string = '${os.home_dir()}/hero/var/bizmodel'
sheet &spreadsheet.Sheet
employees map[string]&Employee
departments map[string]&Department

View File

@@ -1,89 +1,51 @@
module bizmodel
import freeflowuniverse.herolib.core.playbook { PlayBook }
import arrays
import freeflowuniverse.herolib.core.texttools
import freeflowuniverse.herolib.core.playbook { PlayBook, Action }
import freeflowuniverse.herolib.ui.console
// import freeflowuniverse.herolib.core.texttools
// import freeflowuniverse.herolib.ui.console
import freeflowuniverse.herolib.biz.spreadsheet
pub fn play(mut plbook PlayBook) ! {
// first make sure we find a run action to know the name
mut actions4 := plbook.actions_find(actor: 'bizmodel')!
if actions4.len == 0 {
return
}
knownactions := ['revenue_define', 'employee_define', 'department_define', 'funding_define',
'costcenter_define', 'cost_define']
for action in actions4 {
// biz name needs to be specified in the the bizmodel hero actions
bizname := action.params.get('bizname') or {
return error("Can't find param: 'bizname' for ${action.actor}.${action.name} macro, is a requirement argument.")
}
mut sim := getset(bizname)!
if action.name !in knownactions {
return error("Can't find macro with name: ${action.name} for macro's for bizmodel.")
}
console.print_debug(action.name)
match action.name {
'revenue_define' {
sim.revenue_action(action)!
}
'funding_define' {
sim.funding_define_action(action)!
}
'costcenter_define' {
sim.costcenter_define_action(action)!
}
else {}
}
}
console.print_debug('TOTALS for bizmodel play')
// now we have processed the macro's, we can calculate the totals
rlock bizmodels {
for _, mut sim in bizmodels {
// sim.hr_total()!
sim.cost_total()!
sim.revenue_total()!
sim.funding_total()!
}
}
for action in actions4 {
console.print_debug(action.name)
// biz name needs to be specified in the the bizmodel hero actions
bizname := action.params.get('bizname') or {
return error("Can't find param: 'bizname' for bizmodel macro, is a requirement argument.")
}
mut sim := get(bizname)!
if action.name !in knownactions {
return error("Can't find macro with name: ${action.name} for macro's for bizmodel.")
}
match action.name {
'cost_define' {
sim.cost_define_action(action)!
}
'department_define' {
sim.department_define_action(action)!
}
'employee_define' {
sim.employee_define_action(action)!
}
else {}
}
}
// mut sim:=get("test")!
// //println(sim.sheet.rows.keys())
// //println(spreadsheet.sheets_keys())
// println(spreadsheet.sheet_get('bizmodel_test')!)
// if true{panic("sss")}
const action_priorities = {
0: ['revenue_define', 'costcenter_define', 'funding_define']
1: ['cost_define', 'department_define', 'employee_define']
2: ['sheet_wiki', 'graph_bar_row', 'graph_pie_row', 'graph_line_row', 'row_overview']
}
pub fn play(mut plbook PlayBook) ! {
// group actions by which bizmodel they belong to
actions_by_biz := arrays.group_by[string, &Action](
plbook.actions_find(actor: 'bizmodel')!,
fn (a &Action) string {
return a.params.get('bizname') or {'default'}
}
)
// play actions for each biz in playbook
for biz, actions in actions_by_biz {
mut model := getset(biz)!
model.play(mut plbook)!
}
}
pub fn (mut m BizModel) play(mut plbook PlayBook) ! {
mut actions := plbook.actions_find(actor: 'bizmodel')!
for action in actions.filter(it.name in action_priorities[0]) {
m.act(*action)!
}
m.cost_total()!
m.revenue_total()!
m.funding_total()!
for action in actions.filter(it.name in action_priorities[1]) {
m.act(*action)!
}
for action in actions.filter(it.name in action_priorities[2]) {
m.act(*action)!
}
}

View File

@@ -3,7 +3,7 @@ module bizmodel
import freeflowuniverse.herolib.core.playbook { Action }
import freeflowuniverse.herolib.core.texttools
fn (mut m BizModel) cost_define_action(action Action) ! {
fn (mut m BizModel) cost_define_action(action Action) !Action {
mut name := action.params.get_default('name', '')!
mut descr := action.params.get_default('descr', '')!
if descr.len == 0 {
@@ -73,6 +73,7 @@ fn (mut m BizModel) cost_define_action(action Action) ! {
)!
m.sheet.row_delete('tmp3')
}
return action
}
fn (mut sim BizModel) cost_total() ! {

View File

@@ -3,7 +3,7 @@ module bizmodel
import freeflowuniverse.herolib.core.playbook { Action }
import freeflowuniverse.herolib.core.texttools
fn (mut m BizModel) costcenter_define_action(action Action) ! {
fn (mut m BizModel) costcenter_define_action(action Action) !Action {
mut name := action.params.get_default('name', '')!
mut descr := action.params.get_default('descr', '')!
if descr.len == 0 {
@@ -20,4 +20,5 @@ fn (mut m BizModel) costcenter_define_action(action Action) ! {
department: department
}
m.costcenters[name] = &cc
return action
}

View File

@@ -9,7 +9,7 @@ import freeflowuniverse.herolib.core.texttools
// - descr: description of the funding .
// - investment is month:amount,month:amount, ... .
// - type: loan or capital .
fn (mut m BizModel) funding_define_action(action Action) ! {
fn (mut m BizModel) funding_define_action(action Action) !Action {
mut name := action.params.get_default('name', '')!
mut descr := action.params.get_default('descr', '')!
if descr.len == 0 {
@@ -29,6 +29,7 @@ fn (mut m BizModel) funding_define_action(action Action) ! {
descr: descr
extrapolate: false
)!
return action
}
fn (mut sim BizModel) funding_total() ! {

View File

@@ -15,7 +15,7 @@ import freeflowuniverse.herolib.core.texttools
// department:'engineering'
// cost_percent_revenue e.g. 4%, will make sure the cost will be at least 4% of revenue
fn (mut m BizModel) employee_define_action(action Action) ! {
fn (mut m BizModel) employee_define_action(action Action) !Action {
mut name := action.params.get_default('name', '')!
mut descr := action.params.get_default('descr', '')!
if descr.len == 0 {
@@ -107,10 +107,7 @@ fn (mut m BizModel) employee_define_action(action Action) ! {
fulltime_perc: action.params.get_percentage_default('fulltime', '100%')!
}
// println(employee)
// todo: use existing id gen
if name != '' {
// sid = smartid.sid_new('')!
// // TODO: this isn't necessary if sid_new works correctly
@@ -120,9 +117,10 @@ fn (mut m BizModel) employee_define_action(action Action) ! {
// }
m.employees[name] = &employee
}
return action
}
fn (mut m BizModel) department_define_action(action Action) ! {
fn (mut m BizModel) department_define_action(action Action) !Action {
mut name := action.params.get_default('name', '')!
mut descr := action.params.get_default('descr', '')!
if descr.len == 0 {
@@ -141,6 +139,8 @@ fn (mut m BizModel) department_define_action(action Action) ! {
if name != '' {
m.departments[name] = &department
}
return action
}
// fn (mut sim BizModel) hr_total() ! {

View File

@@ -21,7 +21,7 @@ import freeflowuniverse.herolib.core.texttools
// - nr_sold: how many do we sell per month (is in growth format e.g. 10:100,20:200)
// - nr_months_recurring: how many months is recurring, if 0 then no recurring
//
fn (mut m BizModel) revenue_action(action Action) ! {
fn (mut m BizModel) revenue_action(action Action) !Action {
mut name := action.params.get_default('name', '')!
mut descr := action.params.get_default('descr', '')!
if descr.len == 0 {
@@ -312,6 +312,7 @@ fn (mut m BizModel) revenue_action(action Action) ! {
// panic("sdsd")
// }
return action
}
// revenue_total calculates and aggregates the total revenue and cost of goods sold (COGS) for the business model

View File

@@ -0,0 +1,9 @@
# Human Resources
| Name | Title | Nr People |
|------|-------|-------|
@for employee in model.employees.values().filter(it.department == dept.name)
| @{employee_names[employee.name]} | @{employee.title} | @{employee.nrpeople} |
@end
@end

View File

@@ -2,53 +2,48 @@
## FUNDING
!!bizmodel.sheet_wiki includefilter:'funding'
@{bizmodel.sheet.wiki(includefilter:'funding')!}
## REVENUE vs COGS
!!bizmodel.sheet_wiki includefilter:rev
@{bizmodel.sheet.wiki(includefilter:'rev')!}
#### Revenue Lines
!!bizmodel.sheet_wiki title:'Revenue Total' includefilter:'revtotal'
@{bizmodel.sheet.wiki(title:'Revenue Total', includefilter:'revtotal')!}
#### COGS Lines
!!bizmodel.sheet_wiki title:'COGS' includefilter:'cogstotal'
@{bizmodel.sheet.wiki(title:'COGS', includefilter:'cogstotal')!}
## HR
!!bizmodel.sheet_wiki title:'HR Teams' includefilter:'hrnr'
!!bizmodel.sheet_wiki title:'HR Costs' includefilter:'hrcost'
@{bizmodel.sheet.wiki(title:'HR Teams', includefilter:'hrnr')!}
@{bizmodel.sheet.wiki(title:'HR Costs', includefilter:'hrcost')!}
## Operational Costs
!!bizmodel.sheet_wiki title:'COSTS' includefilter:'ocost'
@{bizmodel.sheet.wiki(title:'COSTS', includefilter:'ocost')!}
## P&L Overview
<!-- period is in months, 3 means every quarter -->
!!bizmodel.sheet_wiki title:'P&L Overview' includefilter:'pl'
@{bizmodel.sheet.wiki(title:'P&L Overview', includefilter:'pl')!}
!!bizmodel.graph_bar_row rowname:revenue_total unit:million title:'A Title' title_sub:'Sub'
@{bizmodel.graph_bar_row(rowname:'revenue_total', unit:'million', title:'A Title', title_sub:'Sub')!}
Unit is in Million USD.
!!bizmodel.graph_bar_row rowname:revenue_total unit:million
@{bizmodel.graph_bar_row(rowname:'revenue_total', unit:'million')!}
!!bizmodel.graph_line_row rowname:revenue_total unit:million
!!bizmodel.graph_pie_row rowname:revenue_total unit:million size:'80%'
@{bizmodel.graph_line_row(rowname:'revenue_total', unit:'million')!}
@{bizmodel.graph_pie_row(rowname:'revenue_total', unit:'million', size:'80%')!}
## Some Details
> show how we can do per month
!!bizmodel.sheet_wiki includefilter:'pl' period_months:1
@{bizmodel.sheet_wiki(includefilter:'pl', period_months:1)!}

View File

@@ -0,0 +1,68 @@
# @{product.title}
@{product.description}
#### parameters for the product
@if product.has_oneoffs
Product ${name1} has revenue events (one offs)
!!!spreadsheet.sheet_wiki
namefilter:'${name1}_revenue,${name1}_cogs,${name1}_cogs_perc,${name1}_maintenance_month_perc' sheetname:'bizmodel_tf9
- COGS = Cost of Goods Sold (is our cost to deliver the product/service)
- maintenance is fee we charge to the customer per month in relation to the revenue we charged e.g. 1% of a product which was sold for 1m EUR means we charge 1% of 1 m EUR per month.
@end //one offs
@if product.has_items
Product sold and its revenue/cost of goods
!!!spreadsheet.sheet_wiki
namefilter:'${name1}_nr_sold,${name1}_revenue_setup,${name1}_revenue_monthly,${name1}_cogs_setup,${name1}_cogs_setup_perc,${name1}_cogs_monthly,${name1}_cogs_monthly_perc'
sheetname:'bizmodel_tf9
- nr sold, is the nr sold per month of ${name1}
- revenue setup is setup per item for ${name1}, this is the money we receive. Similar there is a revenue monthly.
- cogs = Cost of Goods Sold (is our cost to deliver the product)
- can we as a setup per item, or per month per item
@if product.nr_months_recurring>1
This product ${name1} is recurring, means customer pays per month ongoing, the period customer is paying for in months is: **${product.nr_months_recurring}**
@end //recurring
@end
#### the revenue/cogs calculated
!!!spreadsheet.sheet_wiki
namefilter:'${name1}_nr_sold_recurring'
sheetname:'bizmodel_tf9
This results in following revenues and cogs:
!!!spreadsheet.sheet_wiki
namefilter:'${name1}_revenue_setup_total,${name1}_revenue_monthly_total,${name1}_cogs_setup_total,${name1}_cogs_monthly_total,${name1}_cogs_setup_from_perc,${name1}_cogs_monthly_from_perc,${name1}_maintenance_month,
${name1}_revenue_monthly_recurring,${name1}_cogs_monthly_recurring'
sheetname:'bizmodel_tf9
resulting revenues:
!!!spreadsheet.sheet_wiki
namefilter:'${name1}_revenue_total,${name1}_cogs_total'
sheetname:'bizmodel_tf9
!!!spreadsheet.graph_line_row rowname:'${name1}_cogs_total' unit:million sheetname:'bizmodel_tf9'
!!!spreadsheet.graph_line_row rowname:'${name1}_revenue_total' unit:million sheetname:'bizmodel_tf9'
@end //product has_revenue
@end //loop

View File

@@ -124,9 +124,4 @@ fn test_curr() {
console.print_debug(sh.rows['something'].cells[0])
assert sh.rows['something']!.cells[0].val == 25.0
assert sh.rows['something']!.cells[60 - 1].val == 900.0
// TODO: we need to create tests for it
console.print_debug(sh)
panic('test1')
}

View File

@@ -95,7 +95,7 @@ pub fn (mut r Row) cell_get(colnr int) !&Cell {
return &r.cells[colnr]
}
pub fn (mut r Row) values_get() []f64 {
pub fn (r Row) values_get() []f64 {
mut out := []f64{}
for cell in r.cells {
out << cell.val

View File

@@ -259,13 +259,13 @@ pub fn (mut s Sheet) json() string {
}
// find row, report error if not found
pub fn (mut s Sheet) row_get(name string) !&Row {
mut row := s.rows[name] or { return error('could not find row with name: ${name}') }
pub fn (s Sheet) row_get(name string) !&Row {
row := s.rows[name] or { return error('could not find row with name: ${name}, available rows: ${s.rows.keys()}') }
return row
}
pub fn (mut s Sheet) values_get(name string) ![]f64 {
mut r := s.row_get(name)!
pub fn (s Sheet) values_get(name string) ![]f64 {
r := s.row_get(name)!
vs := r.values_get()
return vs
}

View File

@@ -121,7 +121,7 @@ pub fn (mut s Sheet) data_get_as_string(args RowGetArgs) !string {
mut s2 := s
if args.period_type == .year {
s.toyear(
s2 = s.toyear(
name: args.rowname
namefilter: args.namefilter
includefilter: args.includefilter
@@ -129,7 +129,7 @@ pub fn (mut s Sheet) data_get_as_string(args RowGetArgs) !string {
)!
}
if args.period_type == .quarter {
s.toquarter(
s2 = s.toquarter(
name: args.rowname
namefilter: args.namefilter
includefilter: args.includefilter
@@ -141,13 +141,13 @@ pub fn (mut s Sheet) data_get_as_string(args RowGetArgs) !string {
// console.print_debug(s2.row_get(args.rowname)!)
mut vals := s2.values_get(args.rowname)!
if args.period_type == .year && vals.len != nryears {
return error('${err_pre}Vals.len need to be 6, for year.\nhere:\n${vals}')
return error('${err_pre}Vals.len need to be ${nryears}, for year.\nhere:\n${vals}')
}
if args.period_type == .quarter && vals.len != nryears * 4 {
return error('${err_pre}vals.len need to be 6*4, for quarter.\nhere:\n${vals}')
return error('${err_pre}vals.len need to be ${nryears}*4, for quarter.\nhere:\n${vals}')
}
if args.period_type == .month && vals.len != nryears * 12 {
return error('${err_pre}vals.len need to be 6*12, for month.\nhere:\n${vals}')
return error('${err_pre}vals.len need to be ${nryears}*12, for month.\nhere:\n${vals}')
}
for mut val in vals {

View File

@@ -77,7 +77,6 @@ module livekit
// token.grants.video = grant
// }
// // Method to generate a JWT token
// pub fn (token AccessToken) to_jwt() !string {
// // Create JWT payload
@@ -150,4 +149,4 @@ module livekit
// // Parse and return the claims as ClaimGrants
// return json.decode(ClaimGrants, payload_json)
// }
// }

View File

@@ -1,4 +1,4 @@
module zdb
module zerodb_client
import freeflowuniverse.herolib.core.redisclient
import freeflowuniverse.herolib.ui.console
@@ -14,11 +14,12 @@ pub mut:
// /tmp/redis-default.sock
pub fn get(addr string, auth string, namespace string) !ZDB {
console.print_header(' ZDB get: addr:${addr} namespace:${namespace}')
mut redis := redisclient.get(addr)!
mut redis := redisclient.new(addr)!
mut zdb := ZDB{
redis: redis
}
println('Here..')
if auth != '' {
zdb.redis.send_expect_ok(['AUTH', auth])!
}

View File

@@ -2,6 +2,7 @@ module generic
import freeflowuniverse.herolib.ui.console
import freeflowuniverse.herolib.core.pathlib
import freeflowuniverse.herolib.osal
fn generate_exec(path string, reset bool) ! {
mut args := args_get(path)!
@@ -43,12 +44,15 @@ fn generate_exec(path string, reset bool) ! {
if args.reset {
path_templ_dir.delete()!
}
if args.templates {
if !path_templ_dir.exists() {
mut templ_6 := $tmpl('templates/atemplate.yaml')
pathlib.template_write(templ_6, '${args.path}/templates/atemplate.yaml', true)!
}
}
console.print_debug('formating dir ${args.path}')
osal.execute_silent('v fmt -w ${args.path}')!
}
fn platform_check(args GeneratorArgs) ! {

View File

@@ -47,7 +47,7 @@ fn args_get(path string) !GeneratorArgs {
classname: p.get('classname')!
title: p.get_default('title', '')!
default: p.get_default_true('default')
supported_platforms: p.get_list('supported_platforms')!
supported_platforms: p.get_list_default('supported_platforms', [])!
singleton: p.get_default_false('singleton')
templates: p.get_default_false('templates')
reset: p.get_default_false('reset')

View File

@@ -1,15 +1,18 @@
module ${args.name}
@if args.hasconfig
import freeflowuniverse.herolib.core.base
@end
import freeflowuniverse.herolib.core.playbook
import freeflowuniverse.herolib.ui.console
import freeflowuniverse.herolib.data.paramsparser
@if args.cat == .installer
import freeflowuniverse.herolib.sysadmin.startupmanager
import freeflowuniverse.herolib.osal.zinit
@if args.startupmanager
import time
@end
@end
__global (
${args.name}_global map[string]&${args.classname}

View File

@@ -29,6 +29,15 @@ pub fn cmd_docusaurus(mut cmdroot Command) {
description: 'Url where docusaurus source is.'
})
cmd_run.add_flag(Flag{
flag: .string
required: false
name: 'path'
abbrev: 'p'
// default: ''
description: 'Path where docusaurus source is.'
})
cmd_run.add_flag(Flag{
flag: .string
required: false
@@ -36,7 +45,7 @@ pub fn cmd_docusaurus(mut cmdroot Command) {
abbrev: 'dk'
// default: ''
description: 'Path of SSH Key used to deploy.'
})
})
cmd_run.add_flag(Flag{
flag: .string
@@ -46,7 +55,6 @@ pub fn cmd_docusaurus(mut cmdroot Command) {
description: 'Path where to publish.'
})
cmd_run.add_flag(Flag{
flag: .bool
required: false
@@ -78,20 +86,25 @@ pub fn cmd_docusaurus(mut cmdroot Command) {
description: 'Run your dev environment on local browser.'
})
cmd_run.add_flag(Flag{
flag: .bool
required: false
name: 'new'
abbrev: 'n'
description: 'create a new docusaurus site.'
})
cmdroot.add_command(cmd_run)
}
fn cmd_docusaurus_execute(cmd Command) ! {
mut update := cmd.flags.get_bool('update') or { false }
mut init := cmd.flags.get_bool('new') or { false }
mut url := cmd.flags.get_string('url') or { '' }
mut publish_path := cmd.flags.get_string('publish') or { '' }
mut deploykey := cmd.flags.get_string('deploykey') or { '' }
// mut path := cmd.flags.get_string('path') or { '' }
// if path == '' {
// path = os.getwd()
// }
// path = path.replace('~', os.home_dir())
mut path := cmd.flags.get_string('path') or { '' }
mut buildpublish := cmd.flags.get_bool('buildpublish') or { false }
mut builddevpublish := cmd.flags.get_bool('builddevpublish') or { false }
@@ -101,43 +114,30 @@ fn cmd_docusaurus_execute(cmd Command) ! {
// eprintln("specify build, builddev or dev")
// exit(1)
// }
mut docs := docusaurus.new(update: update)!
if publish_path.len>0 {
_ := docs.build(
url: url
update: update
publish_path: publish_path
deploykey:deploykey
)!
mut docs := docusaurus.new(update: update)!
mut site := docs.get(
url: url
path: path
update: update
publish_path: publish_path
deploykey: deploykey
init: init
)!
if publish_path.len > 0 {
site.build()!
}
if buildpublish {
// Create a new docusaurus site
_ := docs.build_publish(
url: url
update: update
deploykey:deploykey
)!
site.build_publish()!
}
if builddevpublish {
// Create a new docusaurus site
_ := docs.build_dev_publish(
url: url
update: update
deploykey:deploykey
)!
site.build_dev_publish()!
}
if dev {
// Create a new docusaurus site
_ := docs.dev(
url: url
update: update
deploykey:deploykey
)!
site.dev()!
}
}

View File

@@ -171,36 +171,36 @@ pub fn cmd_git(mut cmdroot Command) {
description: 'Filter is part of path of repo e.g. threefoldtech/info_'
})
c.add_flag(Flag{
flag: .string
required: false
name: 'repo'
abbrev: 'r'
description: 'name of repo'
})
c.add_flag(Flag{
flag: .string
required: false
name: 'branch'
abbrev: 'b'
description: 'branch of repo (optional)'
})
// c.add_flag(Flag{
// flag: .string
// required: false
// name: 'repo'
// abbrev: 'r'
// description: 'name of repo'
// })
// c.add_flag(Flag{
// flag: .string
// required: false
// name: 'branch'
// abbrev: 'b'
// description: 'branch of repo (optional)'
// })
c.add_flag(Flag{
flag: .string
required: false
name: 'account'
abbrev: 'a'
description: 'name of account e.g. threefoldtech'
})
// c.add_flag(Flag{
// flag: .string
// required: false
// name: 'account'
// abbrev: 'a'
// description: 'name of account e.g. threefoldtech'
// })
c.add_flag(Flag{
flag: .string
required: false
name: 'provider'
abbrev: 'p'
description: 'name of provider e.g. github'
})
// c.add_flag(Flag{
// flag: .string
// required: false
// name: 'provider'
// abbrev: 'p'
// description: 'name of provider e.g. github'
// })
}
for mut c_ in allcmdsref {
mut c := *c_
@@ -245,21 +245,21 @@ fn cmd_git_execute(cmd Command) ! {
// create the filter for doing group actions, or action on 1 repo
mut filter := cmd.flags.get_string('filter') or { '' }
mut branch := cmd.flags.get_string('branch') or { '' }
mut repo := cmd.flags.get_string('repo') or { '' }
mut account := cmd.flags.get_string('account') or { '' }
mut provider := cmd.flags.get_string('provider') or { '' }
// mut branch := cmd.flags.get_string('branch') or { '' }
// mut repo := cmd.flags.get_string('repo') or { '' }
// mut account := cmd.flags.get_string('account') or { '' }
// mut provider := cmd.flags.get_string('provider') or { '' }
if cmd.name != 'cd' {
// check if we are in a git repo
if repo == '' && account == '' && provider == '' && filter == '' {
if r0 := gs.get_working_repo() {
repo = r0.name
account = r0.account
provider = r0.provider
}
}
}
// if cmd.name != 'cd' {
// // check if we are in a git repo
// if repo == '' && account == '' && provider == '' && filter == '' {
// if r0 := gs.get_working_repo() {
// repo = r0.name
// account = r0.account
// provider = r0.provider
// }
// }
// }
if cmd.name in gittools.gitcmds.split(',') {
mut pull := cmd.flags.get_bool('pull') or { false }
@@ -271,11 +271,7 @@ fn cmd_git_execute(cmd Command) ! {
}
mypath := gs.do(
filter: filter
repo: repo
reload: reload
account: account
provider: provider
branch: branch
recursive: recursive
cmd: cmd.name
script: cmd.flags.get_bool('script') or { false }

View File

@@ -189,7 +189,6 @@ pub fn (mut h HTTPConnection) get(req_ Request) !string {
req.debug = true
req.method = .get
result := h.send(req)!
println(result)
return result.data
}

View File

@@ -29,11 +29,12 @@ pub fn get_no_check(path_ string) Path {
@[params]
pub struct GetArgs {
pub mut:
path string
create bool
check bool = true // means will check the dir, link or file exists
empty bool // will empty the dir or the file
delete bool
path string
create bool
check bool = true // means will check the dir, link or file exists
empty bool // will empty the dir or the file
delete bool
increment bool // will increment filename until free name available (filename1...)
}
// get a directory, or needs to be created
@@ -81,6 +82,17 @@ pub fn get_file(args_ GetArgs) !Path {
mut p2 := get_no_check(args.path)
if args.check {
p2.check()
if args.increment {
if p2.exists() {
incr := if args.path[args.path.len - 1].is_digit() {
args.path[args.path.len - 1].ascii_str().int()
} else {
0
}
return get_file(GetArgs{ ...args, path: '${args.path}${incr}' })
}
}
if args.create {
mut parent_ := p2.parent()!
parent_.check()

View File

@@ -13,7 +13,7 @@ pub mut:
delete bool // do we want to delete the destination
ignore []string // arguments to ignore e.g. ['*.pyc','*.bak']
ignore_default bool = true // if set will ignore a common set
debug bool = true
debug bool
fast_rsync bool
sshkey string
}
@@ -37,8 +37,8 @@ pub fn rsync(args_ RsyncArgs) ! {
get(args.source)
}
cmdoptions := rsync_cmd_options(args)!
$if debug {
console.print_debug(' rsync command:\nrsync ${cmdoptions}')
if args.debug {
console.print_debug('rsync ${cmdoptions}')
}
r := os.execute('which rsync')
if r.exit_code > 0 {

View File

@@ -10,7 +10,7 @@ pub fn template_write(template_ string, dest string, overwrite bool) ! {
if overwrite || !(os.exists(dest)) {
mut p := get_file(path: dest, create: true)!
$if debug {
console.print_header(" write template to '${dest}'")
console.print_debug(" write template to '${dest}'")
}
p.write(template)!
}

View File

@@ -0,0 +1,38 @@
module texttools
pub fn snake_case(s string) string {
return separate_words(s).join('_')
}
pub fn title_case(s string) string {
return separate_words(s).join(' ').title()
}
pub fn pascal_case(s string) string {
mut pascal := s.replace('_', ' ')
return pascal.title().replace(' ', '')
}
pub fn camel_case(s string) string {
return pascal_case(s).uncapitalize()
}
const separators = ['.', '_', '-', '/', ' ', ':', ',', ';']
fn separate_words(s string) []string {
mut words := []string{}
mut word := ''
for i, c in s {
if (c.is_capital() || c.ascii_str() in separators) && word != '' {
words << word.to_lower()
word = ''
}
if c.ascii_str() !in separators {
word += c.ascii_str().to_lower()
}
}
if word != '' {
words << word.to_lower()
}
return words
}

View File

@@ -37,7 +37,6 @@ pub fn new(args_ GitStructureArgsNew) !&GitStructure {
debug: args.debug
ssh_key_name: args.ssh_key_name
ssh_key_path: args.ssh_key_path
}
return get(coderoot: args.coderoot, reload: args.reload, cfg: cfg)
@@ -81,18 +80,20 @@ pub fn get(args_ GitStructureArgGet) !&GitStructure {
}
mut cfg := args.cfg or {
mut cfg_:=GitStructureConfig{coderoot:"SKIP"}
mut cfg_ := GitStructureConfig{
coderoot: 'SKIP'
}
cfg_
}
if cfg.coderoot != "SKIP"{
if cfg.coderoot != 'SKIP' {
gs.config_ = cfg
gs.config_save()!
//println(gs.config()!)
// println(gs.config()!)
}
gs.config()! // will load the config, don't remove
gs.load(false)!
if gs.repos.keys().len == 0 || args.reload {

View File

@@ -17,7 +17,6 @@ pub mut:
ssh_key_path string
}
// GitStructure holds information about repositories within a specific code root.
// This structure keeps track of loaded repositories, their configurations, and their status.
@[heap]

View File

@@ -11,7 +11,11 @@ fn get_repo_status(gr GitRepo) !string {
statuses << 'COMMIT'
}
if repo.need_push_or_pull()! {
if repo.need_push()! {
statuses << 'PUSH'
}
if repo.need_pull()! {
statuses << 'PULL'
}
@@ -28,7 +32,7 @@ fn format_repo_info(repo GitRepo) ![]string {
'[${repo.status_local.branch}]' // Otherwise, display branch
}
relative_path := repo.get_relative_path()!
relative_path := repo.get_human_path()!
return [' - ${relative_path}', tag_or_branch, status]
}

View File

@@ -34,16 +34,16 @@ pub fn (mut gitstructure GitStructure) clone(args GitCloneArgs) !&GitRepo {
extra = '--depth 1 --no-single-branch '
}
cfg:=gitstructure.config()!
cfg := gitstructure.config()!
mut cmd := 'cd ${parent_dir} && git clone ${extra} ${repo.get_http_url()!} ${repo.name}'
mut sshkey_include := ""
if cfg.ssh_key_path.len>0{
sshkey_include="GIT_SSH_COMMAND=\"ssh -i ${cfg.ssh_key_path}\" "
mut sshkey_include := ''
if cfg.ssh_key_path.len > 0 {
sshkey_include = "GIT_SSH_COMMAND=\"ssh -i ${cfg.ssh_key_path}\" "
cmd = 'cd ${parent_dir} && ${sshkey_include}git clone ${extra} ${repo.get_ssh_url()!} ${repo.name}'
}
console.print_debug(cmd)
result := os.execute(cmd)
if result.exit_code != 0 {

View File

@@ -48,8 +48,8 @@ pub fn (mut repo GitRepo) need_commit() !bool {
return repo.has_changes
}
// Check if the repository has changes that need to be pushed (is against the cached info).
pub fn (mut repo GitRepo) need_push_or_pull() !bool {
// Check if the repository has local changes that need to be pushed to remote
pub fn (mut repo GitRepo) need_push() !bool {
repo.status_update()!
last_remote_commit := repo.get_last_remote_commit() or {
return error('Failed to get last remote commit: ${err}')
@@ -57,10 +57,44 @@ pub fn (mut repo GitRepo) need_push_or_pull() !bool {
last_local_commit := repo.get_last_local_commit() or {
return error('Failed to get last local commit: ${err}')
}
// println('commit status: ${repo.name} ${last_local_commit} ${last_remote_commit}')
// If remote commit is empty, it means the branch doesn't exist remotely yet
if last_remote_commit.len == 0 {
return true
}
// If local commit is different from remote and exists, we need to push
return last_local_commit != last_remote_commit
}
// Check if the repository needs to pull changes from remote
pub fn (mut repo GitRepo) need_pull() !bool {
repo.status_update()!
last_remote_commit := repo.get_last_remote_commit() or {
return error('Failed to get last remote commit: ${err}')
}
// If remote doesn't exist, no need to pull
if last_remote_commit.len == 0 {
return false
}
// Check if the remote commit exists in our local history
// If it doesn't exist, we need to pull
result := repo.exec('git merge-base --is-ancestor ${last_remote_commit} HEAD') or {
if err.msg().contains('exit code: 1') {
// Exit code 1 means the remote commit is not in our history
// Therefore we need to pull
return true
}
return error('Failed to check merge-base: ${err}')
}
// If we get here, the remote commit is in our history
// Therefore we don't need to pull
return false
}
// Legacy function for backward compatibility
pub fn (mut repo GitRepo) need_push_or_pull() !bool {
return repo.need_push()! || repo.need_pull()!
}
// Determine if the repository needs to checkout to a different branch or tag
fn (mut repo GitRepo) need_checkout() bool {
if repo.status_wanted.branch.len > 0 {

View File

@@ -46,7 +46,6 @@ fn (mut repo GitRepo) load() ! {
repo.has_changes = repo.detect_changes() or {
return error('Failed to detect changes in repository ${repo.name}: ${err}')
}
repo.cache_set() or {
return error('Failed to update cache for repository ${repo.name}: ${err}')
}

View File

@@ -71,6 +71,12 @@ pub fn (repo GitRepo) get_relative_path() !string {
return mypath.path_relative(repo_.gs.coderoot.path) or { panic("couldn't get relative path") }
}
// path where we use ~ and its the full path
pub fn (repo GitRepo) get_human_path() !string {
mut mypath := repo.patho()!.path.replace(os.home_dir(), '~')
return mypath
}
pub fn (mut repo GitRepo) get_parent_dir(args GetParentDir) !string {
repo_path := repo.path()
parent_dir := os.dir(repo_path)

View File

@@ -1,7 +1,7 @@
!!hero_code.generate_installer
name:'meilisearchinstaller'
classname:'MeilisearchServer'
name:'meilisearch_installer'
classname:'MeilisearchInstaller'
singleton:0
templates:0
default:1

View File

@@ -0,0 +1,178 @@
module meilisearch_installer
import freeflowuniverse.herolib.osal
import freeflowuniverse.herolib.ui.console
import freeflowuniverse.herolib.osal.zinit
import freeflowuniverse.herolib.installers.ulist
import freeflowuniverse.herolib.core.httpconnection
import freeflowuniverse.herolib.core.texttools
import os
import rand
import json
fn generate_master_key(length int) !string {
mut key := []rune{}
valid_chars := 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'
for _ in 0 .. length {
random_index := rand.int_in_range(0, valid_chars.len)!
key << valid_chars[random_index]
}
return key.string()
}
fn startupcmd() ![]zinit.ZProcessNewArgs {
mut res := []zinit.ZProcessNewArgs{}
mut installer := get()!
mut env := 'development'
if installer.production {
env = 'production'
}
res << zinit.ZProcessNewArgs{
name: 'meilisearch'
cmd: 'meilisearch --no-analytics --http-addr ${installer.host}:${installer.port} --env ${env} --db-path ${installer.path} --master-key ${installer.masterkey}'
startuptype: .zinit
start: true
restart: true
}
return res
}
struct MeilisearchVersionResponse {
version string @[json: 'pkgVersion']
commit_date string @[json: 'commitDate']
commit_sha string @[json: 'commitSha']
}
fn running() !bool {
mut cfg := get()!
url := 'http://${cfg.host}:${cfg.port}'
mut conn := httpconnection.new(name: 'meilisearchinstaller', url: url)!
conn.default_header.add(.authorization, 'Bearer ${cfg.masterkey}')
response := conn.get(prefix: 'version', debug: true) or {
return error('Failed to get meilisearch version: ${err}')
}
decoded_response := json.decode(MeilisearchVersionResponse, response) or {
return error('Failed to decode meilisearch version: ${err}')
}
if decoded_response.version == '' {
console.print_stderr('Meilisearch is not running')
return false
}
console.print_header('Meilisearch is running')
return true
}
fn start_pre() ! {
}
fn start_post() ! {
}
fn stop_pre() ! {
}
fn stop_post() ! {
}
//////////////////// following actions are not specific to instance of the object
// checks if a certain version or above is installed
fn installed() !bool {
res := os.execute('${osal.profile_path_source_and()!} meilisearch -V')
if res.exit_code != 0 {
return false
}
r := res.output.split_into_lines().filter(it.trim_space().len > 0)
if r.len != 1 {
return error("couldn't parse meilisearch version.\n${res.output}")
}
r2 := r[0].all_after('meilisearch').trim(' ')
if texttools.version(version) != texttools.version(r2) {
return false
}
return true
}
// get the Upload List of the files
fn ulist_get() !ulist.UList {
// optionally build a UList which is all paths which are result of building, is then used e.g. in upload
return ulist.UList{}
}
// uploads to S3 server if configured
fn upload() ! {}
fn install() ! {
cfg := get()!
console.print_header('install meilisearch')
// Check if meilisearch is installed
mut res := os.execute('meilisearch --version')
if res.exit_code == 0 {
console.print_header('meilisearch is already installed')
return
}
// Check if curl is installed
res = os.execute('curl --version')
if res.exit_code == 0 {
console.print_header('curl is already installed')
} else {
osal.package_install('curl') or {
return error('Could not install curl, its required to install meilisearch.\nerror:\n${err}')
}
}
if os.exists('${cfg.path}') {
os.rmdir_all('${cfg.path}') or {
return error('Could not remove directory ${cfg.path}.\nerror:\n${err}')
}
}
os.mkdir('${cfg.path}') or {
return error('Could not create directory ${cfg.path}.\nerror:\n${err}')
}
mut cmd := 'cd ${cfg.path} && curl -L https://install.meilisearch.com | sh'
osal.execute_stdout(cmd)!
cmd = 'mv /tmp/meilisearch/meilisearch /usr/local/bin/meilisearch'
osal.execute_stdout(cmd)!
console.print_header('meilisearch is installed')
}
fn build() ! {}
fn destroy() ! {
console.print_header('destroy meilisearch')
mut cfg := get()!
if os.exists('${cfg.path}') {
console.print_header('removing directory ${cfg.path}')
os.rmdir_all('${cfg.path}') or {
return error('Could not remove directory ${cfg.path}.\nerror:\n${err}')
}
}
res := os.execute('meilisearch --version')
if res.exit_code == 0 {
console.print_header('removing meilisearch binary')
osal.execute_silent('sudo rm -rf /usr/local/bin/meilisearch')!
}
mut zinit_factory := zinit.new()!
if zinit_factory.exists('meilisearch') {
zinit_factory.stop('meilisearch') or {
return error('Could not stop meilisearch service due to: ${err}')
}
zinit_factory.delete('meilisearch') or {
return error('Could not delete meilisearch service due to: ${err}')
}
}
console.print_header('meilisearch is destroyed')
}

View File

@@ -0,0 +1,279 @@
module meilisearch_installer
import freeflowuniverse.herolib.core.base
import freeflowuniverse.herolib.core.playbook
import freeflowuniverse.herolib.ui.console
import freeflowuniverse.herolib.sysadmin.startupmanager
import freeflowuniverse.herolib.osal.zinit
import time
__global (
meilisearch_installer_global map[string]&MeilisearchInstaller
meilisearch_installer_default string
)
/////////FACTORY
@[params]
pub struct ArgsGet {
pub mut:
name string
}
fn args_get(args_ ArgsGet) ArgsGet {
mut args := args_
if args.name == '' {
args.name = 'default'
}
return args
}
pub fn get(args_ ArgsGet) !&MeilisearchInstaller {
mut context := base.context()!
mut args := args_get(args_)
mut obj := MeilisearchInstaller{}
if args.name !in meilisearch_installer_global {
if !exists(args)! {
set(obj)!
} else {
heroscript := context.hero_config_get('meilisearch_installer', args.name)!
mut obj_ := heroscript_loads(heroscript)!
set_in_mem(obj_)!
}
}
return meilisearch_installer_global[args.name] or {
println(meilisearch_installer_global)
// bug if we get here because should be in globals
panic('could not get config for meilisearch_installer with name, is bug:${args.name}')
}
}
// register the config for the future
pub fn set(o MeilisearchInstaller) ! {
set_in_mem(o)!
mut context := base.context()!
heroscript := heroscript_dumps(o)!
context.hero_config_set('meilisearch_installer', o.name, 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('meilisearch_installer', args.name)
}
pub fn delete(args_ ArgsGet) ! {
mut args := args_get(args_)
mut context := base.context()!
context.hero_config_delete('meilisearch_installer', args.name)!
if args.name in meilisearch_installer_global {
// del meilisearch_installer_global[args.name]
}
}
// only sets in mem, does not set as config
fn set_in_mem(o MeilisearchInstaller) ! {
mut o2 := obj_init(o)!
meilisearch_installer_global[o.name] = &o2
meilisearch_installer_default = o.name
}
@[params]
pub struct PlayArgs {
pub mut:
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 plbook := args.plbook or { playbook.new(text: args.heroscript)! }
mut install_actions := plbook.find(filter: 'meilisearch_installer.configure')!
if install_actions.len > 0 {
for install_action in install_actions {
heroscript := install_action.heroscript()
mut obj2 := heroscript_loads(heroscript)!
set(obj2)!
}
}
mut other_actions := plbook.find(filter: 'meilisearch_installer.')!
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 meilisearch_installer.destroy')
destroy()!
}
if other_action.name == 'install' {
console.print_debug('install action meilisearch_installer.install')
install()!
}
}
if other_action.name in ['start', 'stop', 'restart'] {
mut p := other_action.params
name := p.get('name')!
mut meilisearch_installer_obj := get(name: name)!
console.print_debug('action object:\n${meilisearch_installer_obj}')
if other_action.name == 'start' {
console.print_debug('install action meilisearch_installer.${other_action.name}')
meilisearch_installer_obj.start()!
}
if other_action.name == 'stop' {
console.print_debug('install action meilisearch_installer.${other_action.name}')
meilisearch_installer_obj.stop()!
}
if other_action.name == 'restart' {
console.print_debug('install action meilisearch_installer.${other_action.name}')
meilisearch_installer_obj.restart()!
}
}
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////# 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()!
}
}
}
// load from disk and make sure is properly intialized
pub fn (mut self MeilisearchInstaller) reload() ! {
switch(self.name)
self = obj_init(self)!
}
pub fn (mut self MeilisearchInstaller) start() ! {
switch(self.name)
if self.running()! {
return
}
console.print_header('meilisearch_installer start')
if !installed()! {
install()!
}
configure()!
start_pre()!
for zprocess in startupcmd()! {
mut sm := startupmanager_get(zprocess.startuptype)!
console.print_debug('starting meilisearch_installer with ${zprocess.startuptype}...')
sm.new(zprocess)!
sm.start(zprocess.name)!
}
start_post()!
for _ in 0 .. 50 {
if self.running()! {
return
}
time.sleep(100 * time.millisecond)
}
return error('meilisearch_installer did not install properly.')
}
pub fn (mut self MeilisearchInstaller) install_start(args InstallArgs) ! {
switch(self.name)
self.install(args)!
self.start()!
}
pub fn (mut self MeilisearchInstaller) stop() ! {
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 MeilisearchInstaller) restart() ! {
switch(self.name)
self.stop()!
self.start()!
}
pub fn (mut self MeilisearchInstaller) running() !bool {
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()!
}
@[params]
pub struct InstallArgs {
pub mut:
reset bool
}
pub fn (mut self MeilisearchInstaller) install(args InstallArgs) ! {
switch(self.name)
if args.reset || (!installed()!) {
install()!
}
}
pub fn (mut self MeilisearchInstaller) build() ! {
switch(self.name)
build()!
}
pub fn (mut self MeilisearchInstaller) destroy() ! {
switch(self.name)
self.stop() or {}
destroy()!
}
// switch instance to be used for meilisearch_installer
pub fn switch(name string) {
meilisearch_installer_default = name
}
// helpers
@[params]
pub struct DefaultConfigArgs {
instance string = 'default'
}

View File

@@ -0,0 +1,60 @@
module meilisearch_installer
import freeflowuniverse.herolib.data.encoderhero
pub const version = '1.11.3'
const singleton = false
const default = true
// THIS THE THE SOURCE OF THE INFORMATION OF THIS FILE, HERE WE HAVE THE CONFIG OBJECT CONFIGURED AND MODELLED
@[heap]
pub struct MeilisearchInstaller {
pub mut:
name string = 'default'
path string = '/tmp/meilisearch'
masterkey string @[secret]
host string = 'localhost'
port int = 7700
production bool
}
// your checking & initialization code if needed
fn obj_init(mycfg_ MeilisearchInstaller) !MeilisearchInstaller {
mut mycfg := mycfg_
if mycfg.masterkey == '' {
mycfg.masterkey = generate_master_key(16)!
}
if mycfg.path == '' {
mycfg.path = '/tmp/meilisearch'
}
if mycfg.host == '' {
mycfg.host = 'localhost'
}
if mycfg.port == 0 {
mycfg.port = 7700
}
if mycfg.name == '' {
mycfg.name = 'default'
}
return mycfg
}
// called before start if done
fn configure() ! {
// mut installer := get()!
}
/////////////NORMALLY NO NEED TO TOUCH
pub fn heroscript_dumps(obj MeilisearchInstaller) !string {
return encoderhero.encode[MeilisearchInstaller](obj)!
}
pub fn heroscript_loads(heroscript string) !MeilisearchInstaller {
mut obj := encoderhero.decode[MeilisearchInstaller](heroscript)!
return obj
}

Some files were not shown because too many files have changed in this diff Show More