Compare commits

..

37 Commits

Author SHA1 Message Date
0f3b5e078b Merge pull request 'specified info for install and uninstall' (#19) from development_flist_msg into main
Reviewed-on: #19
2024-10-12 14:31:53 +00:00
mik-tf
bdea372932 specified info for install and uninstall 2024-10-12 10:30:57 -04:00
mik-tf
8c439a69c9 clearer info_msg for windows 2024-10-12 10:21:33 -04:00
mik-tf
e128388d52 updated readme 2024-10-12 09:59:58 -04:00
95ec920c9a Merge pull request 'made specific errors instead of general one' (#17) from development_errors into main
Reviewed-on: #17
2024-10-12 13:23:21 +00:00
Mik-TF
feea1941fe made specific errors instead of general one 2024-10-12 06:22:15 -07:00
25b609cba3 Merge pull request 'simplified login docker' (#16) from development_docker into main
Reviewed-on: #16
2024-10-12 12:28:44 +00:00
mik-tf
1aeaea6e40 simplified login docker 2024-10-12 08:27:43 -04:00
mik-tf
4e9da76069 removed powershell info in help for windows, now in error message 2024-10-12 07:58:43 -04:00
eef5a0dfbe Merge pull request 'updated panic message to clearer message' (#15) from development_privilege into main
Reviewed-on: #15
2024-10-12 11:56:48 +00:00
mik-tf
859697faf3 updated panic message to clearer message 2024-10-12 07:55:32 -04:00
bd218134fe Merge pull request 'updated help for windows with install and uninstall' (#14) from development_issues into main
Reviewed-on: #14
2024-10-12 11:48:44 +00:00
mik-tf
ecf9e48c92 updated help for windows with install and uninstall 2024-10-12 07:47:22 -04:00
0281bd6260 updated readme with links to prereqs 2024-10-11 15:59:23 +00:00
fc2d2643fe Merge pull request 'updated readme' (#9) from development_readme into main
Reviewed-on: #9
2024-10-11 07:24:38 +00:00
mik-tf
00e130929f updated readme 2024-10-11 03:23:47 -04:00
1a94511d9b Merge pull request 'development_strings' (#8) from development_strings into main
Reviewed-on: #8
2024-10-11 07:14:29 +00:00
Mik-TF
fbca09a0ca fixed windows remove path function 2024-10-11 00:07:30 -07:00
Mik-TF
2ccb0286da added info 2024-10-10 23:44:48 -07:00
mik-tf
fd2a4c2853 test simpler strings for windows path 2024-10-11 02:33:45 -04:00
1580602523 Merge pull request 'Flist CLI Updated for Linux, MacOS, Windows' (#7) from development_mac_2 into main
Reviewed-on: #7
2024-10-11 04:50:58 +00:00
mik-tf
1d97660e8e fixed typo in msg 2024-10-11 00:42:04 -04:00
mik-tf
7304271e22 macos v flist fixes 2024-10-11 00:37:37 -04:00
mik-tf
e7d572f50e fixed macos version 2024-10-11 00:21:14 -04:00
mik-tf
7a5449c718 testing macos 2024-10-11 00:01:42 -04:00
mik-tf
b7f793c8d1 finalized readme for win mac linux 2024-10-10 10:42:44 -04:00
mik-tf
6d0781cdc4 fixed mac specific error 2024-10-10 09:57:15 -04:00
Mik-TF
a39c062339 added os specific info for help 2024-10-10 06:29:22 -07:00
Mik-TF
9d9b92c14d set docker cmd for windows or not 2024-10-10 06:06:23 -07:00
Mik-TF
6f4c146ec0 set help fn with windows specific 2024-10-10 05:59:46 -07:00
Mik-TF
3eb53a4b3b windows version working function now are ls ls url login logout rename delete, todo: push 2024-10-10 05:56:21 -07:00
Mik-TF
f6f52c46f3 updated make for windows, simplified globally, set cyan for color instead of blue 2024-10-10 05:15:33 -07:00
Mik-TF
2652b35834 fixed help for windows 2024-10-09 16:55:18 -07:00
mik-tf
4ea5bf3c7b added shortcut if windows 2024-10-09 19:48:55 -04:00
Mik-TF
25d61bc6a2 set makefile for windows, macos, linux 2024-10-09 16:00:49 -07:00
Mik-TF
ca543c10b7 started work on install windows 2024-10-09 15:26:18 -07:00
Mik-TF
222e4c43da started working on windows native version 2024-10-09 12:36:22 -07:00
4 changed files with 335 additions and 158 deletions

4
.gitignore vendored
View File

@ -1 +1,3 @@
flist
flist
flist.exe
test/

View File

@ -4,12 +4,24 @@ build:
sudo ./flist install
rebuild:
sudo rm flist
sudo flist uninstall
v fmt -w flist.v
v -o flist .
sudo ./flist install
delete:
sudo rm flist
sudo flist uninstall
sudo flist uninstall
build-win:
v fmt -w flist.v
v -o flist .
./flist.exe install
rebuild-win:
./flist.exe uninstall
v fmt -w flist.v
v -o flist .
./flist.exe install
delete-win:
./flist.exe uninstall

170
README.md
View File

@ -3,12 +3,13 @@
<h2>Table of Contents</h2>
- [Introduction](#introduction)
- [Installation](#installation)
- [Prerequisites](#prerequisites)
- [Building and Installing](#building-and-installing)
- [Rebuild and Uninstall](#rebuild-and-uninstall)
- [Prerequisites](#prerequisites)
- [Makefile Installation](#makefile-installation)
- [Building and Installing with Makefile](#building-and-installing-with-makefile)
- [Rebuilding and Uninstalling with Makefile](#rebuilding-and-uninstalling-with-makefile)
- [Manual Installation](#manual-installation)
- [Available Commands](#available-commands)
- [Usage](#usage)
- [Commands](#commands)
- [OS-Specific Instructions](#os-specific-instructions)
- [Linux](#linux)
- [macOS](#macos)
@ -24,41 +25,103 @@
Flist CLI is a tool that turns Dockerfiles and Docker images directly into Flist on the TF Flist Hub, passing through Docker Hub.
## Installation
### Prerequisites
## Prerequisites
- [V programming language](https://vlang.io/) (latest version) installed on your system
- Docker installed and running
- Docker Hub account
- TF Hub account and token
- [Docker Engine](https://docs.docker.com/engine/install/) installed and running (Linux)
- [Docker Desktop](https://www.docker.com/products/docker-desktop/) installed and running (MacOS+Windows)
- [Docker Hub](https://hub.docker.com/) account
- [TF Hub](https://hub.grid.tf/) account and token
- Makefile (optional)
### Building and Installing
Read more on the TF Hub and Flist on the ThreeFold Manual [here](https://manual.grid.tf/documentation/developers/flist/flist.html).
Clone this repository, build the project, and install the CLI:
```
git clone https://git.ourworld.tf/tfgrid/flist_cli_v
cd flist_cli_v
make build
```
## Makefile Installation
This will build the `flist` executable and install it to the appropriate system location.
### Building and Installing with Makefile
### Rebuild and Uninstall
- To clone this repository, build the project, and install the CLI:
- MacOS and Linux
```
git clone https://git.ourworld.tf/tfgrid/flist_cli_v
cd flist_cli_v
make build
```
- Windows
```
git clone https://git.ourworld.tf/tfgrid/flist_cli_v
cd flist_cli_v
make build-win
```
This will build the executable and install it to the appropriate system location.
### Rebuilding and Uninstalling with Makefile
You can use the following Makefile commands:
- To rebuild and reinstall:
```
make rebuild
```
- MacOS and Linux
```
make rebuild
```
- Windows
```
make rebuild-win
```
- To uninstall and remove the binary:
```
make delete
```
- MacOS and Linux
```
make delete
```
- Windows
```
make delete-win
```
## Usage
## Manual Installation
You can install the Flist with the following commands. You do not need Makefile to use the Flist CLI.
- Linux and MacOS
- Build
```
v fmt -w flist.v
v -o flist .
sudo ./flist install
```
- Rebuild
```
sudo flist uninstall
v fmt -w flist.v
v -o flist .
sudo ./flist install
```
- Delete
```
sudo flist uninstall
```
- Windows
- Build
```
v fmt -w flist.v
v -o flist .
./flist.exe install
```
- Rebuild
```
./flist.exe uninstall
v fmt -w flist.v
v -o flist .
./flist.exe install
```
- Delete
```
./flist.exe uninstall
```
## Available Commands
After installation, you can use the `flist` command followed by various subcommands:
@ -66,24 +129,41 @@ After installation, you can use the `flist` command followed by various subcomma
flist <command> [arguments]
```
## Commands
Run `flist` or `flist help` to see all available commands for your specific OS.
- `install`: Install the Flist CLI
- `uninstall`: Uninstall the Flist CLI
- `login`: Log in to Docker Hub and save the Flist Hub token
- `logout`: Log out of Docker Hub and remove the Flist Hub token
- `push <image>:<tag>`: Build and push a Docker image, then convert and push it as an flist
- `delete <flist_name>`: Delete an flist from Flist Hub
- `rename <flist_name> <new_flist_name>`: Rename an flist in Flist Hub
- `ls`: List all flists of the current user
- `ls url`: List all flists of the current user with full URLs
- `help`: Display help information
- `install` - Install the Flist CLI
- `uninstall` - Uninstall the Flist CLI
- `login` - Log in to Docker Hub and save the Flist Hub token
- `logout` - Log out of Docker Hub and remove the Flist Hub token
- `push` - Build and push a Docker image to Docker Hub, then convert and push it as an Flist to Flist Hub
- `delete` - Delete an Flist from Flist Hub
- `rename` - Rename an Flist in Flist Hub
- `ls` - List all Flists of the current user
- `ls url` - List all Flists of the current user with full URLs
- `help` - Display this help message
## Usage
A Linux user would use the following commands:
```
sudo ./flist install
sudo flist uninstall
flist login
flist logout
flist push <image>:<tag>
flist delete <flist_name>
flist rename <flist_name> <new_flist_name>
flist ls
flist ls url
flist help
```
## OS-Specific Instructions
### Linux
1. Ensure Docker is installed and the Docker daemon is running.
1. Ensure Docker Engine is installed and running.
2. The `flist` executable will be installed to:
```
/usr/local/bin/flist
@ -99,21 +179,25 @@ flist <command> [arguments]
### Windows
For now, we recommend to use WSL and follow the Linux steps.
1. Ensure Docker Desktop is installed and running.
2. Run the program and installer in an admin PowerShell.
3. The `flist.exe` executable will be installed to:
```
C:\\Program Files\\flist\\flist.exe
```
## Troubleshooting
- If you encounter permission issues, ensure you're running the command with appropriate privileges (e.g., as administrator on Windows or with `sudo` on Unix-like systems).
- Make sure Docker is running before using Flist CLI commands.
- If you face issues with Docker commands, try logging out and logging back in to refresh your Docker credentials.
- If you encounter compilation errors, ensure you have the latest version of V installed.
- If you encounter compilation errors, ensure you have the latest version of V installed. To update v, run `v up`.
## Development
To modify the Flist CLI:
1. Make your changes to the `flist.v` file.
2. Rebuild the project using `make rebuild`
2. Rebuild the project using using the appropriate Make command.
3. Test your changes thoroughly across different operating systems if possible.
## Contributing

301
flist.v
View File

@ -2,15 +2,33 @@ import os
import net.http
import term
import json
import x.json2
const token_file = os.join_path(os.home_dir(), '.config', 'tfhubtoken')
const binary_location = if os.user_os() == 'windows' {
const docker_username_file = os.join_path(os.home_dir(), '.config', 'dockerusername')
const config_dir = os.join_path(os.home_dir(), '.config')
const binary_location = $if windows {
'C:\\Program Files\\flist\\flist.exe'
} else {
} $else {
'/usr/local/bin/flist'
}
const docker_cmd = $if windows {
'docker'
} $else {
'sudo docker'
}
const info_msg = $if windows {
'Note: Docker Desktop must be running to use the push function.\nInstall and uninstall functions require PowerShell with administrator privileges.\nOther functions require PowerShell (without admin privileges).\n'
} $else $if linux {
'Note: Docker Engine must be running to use the push function.\n'
} $else $if macos {
'Note: Docker Desktop must be running to use the push function.\n'
}
const flist_repo_folder = (' # Run this line in the Flist CLI repo folder')
struct FlistItem {
name string
}
@ -23,6 +41,64 @@ struct Response {
payload Payload
}
fn add_path_windows() {
// Define the new directory path to add
new_path := r'C:\Program Files\flist'
// Get the current PATH environment variable
current_path := os.getenv('PATH')
// Check if the new_path is already in the current PATH
if current_path.contains(new_path) {
println('The directory is already in the PATH.')
return
}
// Construct the new PATH by appending the new_path
new_env_path := '${current_path};${new_path}'
// Prepare the command to set the new PATH
cmd := r'setx PATH "' + new_env_path + '"'
// Execute the command to update the PATH
exit_code := os.system(cmd)
if exit_code == 0 {
success_message('\nFlist CLI directory added to the path. \nMake sure to load a new admin PowerShell to use the CLI.')
} else {
error_message('\nFailed to add the Flist CLI to the PATH. Please try running the script as an administrator.')
}
}
fn remove_path_windows() {
// Define the directory path to remove
path_to_remove := r'C:\Program Files\flist'
// Get the current PATH environment variable
current_path := os.getenv('PATH')
// Check if the path_to_remove is in the current PATH
if !current_path.contains(path_to_remove) {
println('The directory is not in the PATH.')
return
}
// Remove specified directory from the PATH
new_env_path := current_path.split(';').filter(it != path_to_remove).join(';')
// Prepare the command to set the new PATH
cmd := r'setx PATH "' + new_env_path + '"'
// Execute the command to update the PATH
exit_code := os.system(cmd)
if exit_code == 0 {
success_message('\nThe Flist CLI directory has been removed from the path.')
} else {
error_message('\nFailed to remove the Flist CLI from the PATH. Please try running the script as an administrator.')
}
}
fn error_message(msg string) {
println(term.red('\nError: ') + msg)
println(term.yellow("Run 'flist help' for usage information.\n"))
@ -33,7 +109,7 @@ fn success_message(msg string) {
}
fn info_message(msg string) {
println(term.blue('\n' + msg + '\n'))
println(term.cyan('\n' + msg + '\n'))
}
fn create_box(content []string, padding int) string {
@ -47,17 +123,17 @@ fn create_box(content []string, padding int) string {
max_width += padding * 2
separator := '━'.repeat(max_width + 2) // +2 for left and right borders
mut box_content := term.blue('${separator}') + '\n'
mut box_content := term.cyan('${separator}') + '\n'
for line in content {
clean_line := term.strip_ansi(line)
padding_left := ' '.repeat(padding)
padding_right := ' '.repeat(max_width - clean_line.len)
box_content += term.blue('┃') + padding_left + line + padding_right + term.blue('┃') +
box_content += term.cyan('┃') + padding_left + line + padding_right + term.cyan('┃') +
'\n'
}
box_content += term.blue('${separator}')
box_content += term.cyan('${separator}')
return box_content
}
@ -65,11 +141,23 @@ fn install() {
info_message('Installing Flist CLI...')
current_exe := os.executable()
if os.exists(current_exe) {
os.mkdir_all(os.dir(binary_location)) or { panic(err) }
os.cp(current_exe, binary_location) or { panic(err) }
os.chmod(binary_location, 0o755) or { panic(err) }
os.mkdir_all(os.dir(binary_location)) or {
error_message('Failed to create directory for binary: ${err}')
exit(1)
}
os.cp(current_exe, binary_location) or {
error_message('Failed to copy binary to path: ${err}')
exit(1)
}
os.chmod(binary_location, 0o755) or {
error_message('Failed to change permissions to binary at path: ${err}')
exit(1)
}
$if windows {
add_path_windows()
}
success_message('Flist CLI has been installed to ' + binary_location)
info_message("You can now use it by running 'flist help'")
info_message("Run 'flist help' to see all commands.")
} else {
error_message('Cannot find the executable file')
exit(1)
@ -78,113 +166,95 @@ fn install() {
fn uninstall() {
info_message('Uninstalling Flist CLI...')
if os.exists(binary_location) {
os.rm(binary_location) or { panic(err) }
// Remove the binary file
os.rm(binary_location) or {
error_message('Failed to remove the binary at path: ${err}')
exit(1)
}
success_message('Flist CLI has been removed from ' + binary_location)
} else {
info_message('Flist CLI is not installed at ' + binary_location)
}
$if windows {
remove_path_windows()
}
}
fn login() {
mut token_exists := os.exists(token_file)
os.mkdir_all(config_dir) or {
error_message('Failed to create config folder for token and Docker username files: ${err}')
exit(1)
}
if !token_exists {
tfhub_token := os.input('Please enter your tfhub token: ')
os.write_file(token_file, tfhub_token) or { panic(err) }
success_message('Token saved in ' + token_file)
tfhub_token := os.input('Please enter your TF Hub token: ')
os.write_file(token_file, tfhub_token) or {
error_message('Failed to write TF Hub token to file: ${err}')
exit(1)
}
success_message('TF Hub token saved in ' + token_file)
} else {
info_message('Your Flist Hub token is already saved.')
info_message('Your TF Hub token is already saved.')
}
result := os.system('sudo docker login')
mut dockername_exists := os.exists(docker_username_file)
mut docker_username := ''
if result == 0 {
info_message('\nYou are already logged in to Docker.')
if !dockername_exists {
docker_username = os.input('Please enter your Docker username: ')
os.write_file(docker_username_file, docker_username) or {
error_message('Failed to write Docker username to file: ${err}')
exit(1)
}
success_message('Docker username saved in ' + docker_username_file)
}
success_message('Login process completed.')
docker_username = os.read_file(docker_username_file) or {
error_message('Failed to read the Docker username from file: ${err}')
exit(1)
}
info_message('Enter your Docker password')
os.system('${docker_cmd} login -u ${docker_username}')
success_message('TF Hub and Docker Hub login process completed.')
}
fn logout() {
if os.exists(token_file) {
os.rm(token_file) or { panic(err) }
success_message('Your Flist Hub Token has been removed')
os.rm(token_file) or {
error_message('Failed to remove TF Hub token file at config directory: ${err}')
exit(1)
}
success_message('Your TF Hub token has been removed')
} else {
info_message('Your Flist Hub Token was already not present.')
info_message('Your TF Hub token was already not present.')
}
exit_code := os.system('sudo docker logout')
if os.exists(docker_username_file) {
os.rm(docker_username_file) or {
error_message('Failed to remove Docker username file in config folder: ${err}')
exit(1)
}
success_message('Your Docker username has been removed from the config folder.')
} else {
info_message('Your Docker username was already not present in the config folder.')
}
exit_code := os.system('${docker_cmd} logout')
if exit_code != 0 {
error_message('Failed to log out from Docker Hub.')
}
success_message('You are now logged out of Docker Hub and your Flist Hub token has been removed.')
}
fn get_docker_credential() !string {
// Try to get the Docker credential automatically
credential := get_docker_credential_auto() or {
// If automatic retrieval fails, prompt the user for input
println(term.yellow("\nCouldn't find your Docker username automatically."))
username := os.input('Please enter your Docker username and press ENTER: ')
if username.trim_space() == '' {
return error('No Docker username provided')
}
return username.trim_space()
}
return credential
}
fn get_docker_credential_auto() !string {
// First, try to get the Docker username using the system info command
system_info_result := os.execute("sudo docker system info | grep 'Username' | cut -d ' ' -f 3")
if system_info_result.exit_code == 0 && system_info_result.output.trim_space() != '' {
return system_info_result.output.trim_space()
}
// If the above method fails, proceed with the current method
// Read the Docker config file
config_path := os.join_path(os.home_dir(), '.docker', 'config.json')
config_content := os.read_file(config_path) or {
return error('Failed to read Docker config file: ${err}')
}
// Parse the JSON content
config := json2.raw_decode(config_content) or {
return error('Failed to parse Docker config: ${err}')
}
// Extract the credsStore value
creds_store := config.as_map()['credsStore'] or {
return error('credsStore not found in Docker config')
}.str()
// Execute the docker-credential command
cred_helper := 'docker-credential-${creds_store}'
cred_output := os.execute('${cred_helper} list')
if cred_output.exit_code != 0 {
return error('Failed to execute ${cred_helper}: ${cred_output.output}')
}
// Parse the credential list
cred_list := json2.raw_decode(cred_output.output) or {
return error('Failed to parse credential list: ${err}')
}
// Find the first docker.io entry
for key, value in cred_list.as_map() {
if key.contains('docker.io') {
return value.str()
}
}
return error('No docker.io credential found')
success_message('You are now logged out of Docker Hub and your TF Hub token has been removed.')
}
fn push(tag string) {
docker_user := get_docker_credential() or {
error_message('Failed to get Docker username: ${err}')
docker_user := os.read_file(docker_username_file) or {
error_message("No Docker username found. Please run 'flist login' first.")
exit(1)
}
@ -193,18 +263,18 @@ fn push(tag string) {
full_tag := '${docker_user}/${tag}'
tfhub_token := os.read_file(token_file) or {
error_message("No token found. Please run 'flist login' first.")
error_message("No TF Hub token found. Please run 'flist login' first.")
exit(1)
}
info_message('Starting Docker build')
if os.system('sudo docker buildx build -t ${full_tag} .') != 0 {
if os.system('${docker_cmd} buildx build -t ${full_tag} .') != 0 {
error_message('Docker build failed')
exit(1)
}
info_message('Finished local Docker build, now pushing to Docker Hub')
if os.system('sudo docker push ${full_tag}') != 0 {
if os.system('${docker_cmd} push ${full_tag}') != 0 {
error_message('Docker push failed')
exit(1)
}
@ -236,7 +306,7 @@ fn push(tag string) {
if response.status_code == 200 {
hub_user := get_hub_username(tfhub_token) or {
error_message('Failed to get hub username')
error_message('Failed to get TF Hub username')
exit(1)
}
@ -254,9 +324,9 @@ fn push(tag string) {
'',
'You can access your Flist using the URL above.',
'To manage your Flists, use the following commands:',
term.yellow(' flist ls ') + '- List all your Flists',
term.yellow(' flist delete') + '- Delete an Flist',
term.yellow(' flist rename') + '- Rename an Flist',
term.yellow(' flist ls ') + ' - List all your Flists',
term.yellow(' flist delete') + ' - Delete an Flist',
term.yellow(' flist rename') + ' - Rename an Flist',
]
println(create_box(success_content, 2))
@ -270,7 +340,7 @@ fn push(tag string) {
fn delete(flist_name string) {
tfhub_token := os.read_file(token_file) or {
error_message("No token found. Please run 'flist login' first.")
error_message("No TF Hub token found. Please run 'flist login' first.")
exit(1)
}
@ -296,7 +366,7 @@ fn delete(flist_name string) {
fn rename(flist_name string, new_flist_name string) {
tfhub_token := os.read_file(token_file) or {
error_message("No token found. Please run 'flist login' first.")
error_message("No TF Hub token found. Please run 'flist login' first.")
exit(1)
}
@ -357,7 +427,7 @@ fn get_hub_username(tfhub_token string) ?string {
fn ls(show_url bool) {
tfhub_token := os.read_file(token_file) or {
error_message("No token found. Please run 'flist login' first.")
error_message("No TF Hub token found. Please run 'flist login' first.")
exit(1)
}
@ -409,21 +479,30 @@ fn help() {
println(create_box([welcome_msg], 2))
println('This tool turns Dockerfiles and Docker images directly into Flists on the TF Flist Hub, passing by the Docker Hub.\n')
println(term.cyan(info_msg))
println(term.bold('Available commands:'))
println(term.blue(' install ') + '- Install the Flist CLI')
println(term.blue(' uninstall ') + '- Uninstall the Flist CLI')
println(term.blue(' login ') + '- Log in to Docker Hub and save the Flist Hub token')
println(term.blue(' logout ') + '- Log out of Docker Hub and remove the Flist Hub token')
println(term.blue(' push ') +
'- Build and push a Docker image to Docker Hub, then convert and push it as an Flist to Flist Hub')
println(term.blue(' delete ') + '- Delete an Flist from Flist Hub')
println(term.blue(' rename ') + '- Rename an Flist in Flist Hub')
println(term.blue(' ls ') + '- List all Flists of the current user')
println(term.blue(' ls url ') + '- List all Flists of the current user with full URLs')
println(term.blue(' help ') + '- Display this help message\n')
println(term.cyan(' install ') + ' - Install the Flist CLI')
println(term.cyan(' uninstall') + ' - Uninstall the Flist CLI')
println(term.cyan(' login ') + ' - Log in to Docker Hub and save the Flist Hub token')
println(term.cyan(' logout ') + ' - Log out of Docker Hub and remove the Flist Hub token')
println(term.cyan(' push ') +
' - Build and push a Docker image to Docker Hub, then convert and push it as an Flist to Flist Hub')
println(term.cyan(' delete ') + ' - Delete an Flist from Flist Hub')
println(term.cyan(' rename ') + ' - Rename an Flist in Flist Hub')
println(term.cyan(' ls ') + ' - List all Flists of the current user')
println(term.cyan(' ls url ') + ' - List all Flists of the current user with full URLs')
println(term.cyan(' help ') + ' - Display this help message\n')
println(term.bold('Usage:'))
println(term.yellow(' sudo ./flist install'))
println(term.yellow(' sudo flist uninstall'))
$if linux {
println(term.yellow(' sudo ./flist install') + term.cyan(flist_repo_folder))
println(term.yellow(' sudo flist uninstall'))
} $else $if macos {
println(term.yellow(' sudo ./flist install') + term.cyan(flist_repo_folder))
println(term.yellow(' flist uninstall'))
} $else $if windows {
println(term.yellow(' ./flist.exe install') + term.cyan(flist_repo_folder))
println(term.yellow(' ./flist.exe uninstall') + term.cyan(flist_repo_folder))
}
println(term.yellow(' flist login'))
println(term.yellow(' flist logout'))
println(term.yellow(' flist push <image>:<tag>'))