Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Multy cli support #16

Merged
merged 20 commits into from
Oct 22, 2024
Merged
Show file tree
Hide file tree
Changes from 17 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@ name: Generate source build
on:
push:
branches: [ master ]
pull_request:
branches: [ master ]


jobs:
build:
Expand All @@ -16,7 +19,7 @@ jobs:
run: |
sudo snap install yq
sudo apt-get update --fix-missing
sudo apt-get install -y -f -o Acquire::Retries=3 libfuse2
sudo apt-get install -y -f -o Acquire::Retries=3 libfuse2 jq libjson-c-dev libcurl4-openssl-dev pkg-config

- name: configure
run: ./configure --wget-json-search --yq-go --compile-json-c
Expand All @@ -25,6 +28,7 @@ jobs:
run: |
sudo chsh -s $(which bash) $(whoami)
make main.c osc_sdk.c osc_sdk.h oapi-cli-completion.bash
make oapi-cli-x86_64.AppImage
# tar c osc_sdk.c osc_sdk.h main.c oapi-cli-completion.bash > build-src.tar

# commented, because uploading generated source is made in oapi-cli/osc-sdk-c projects
Expand Down
4 changes: 2 additions & 2 deletions oapi-cli.AppDir/AppRun → AppRun
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@

for opt in "$@"; do
if [ "${opt}" == "--bash-completion" ]; then
cat "${APPDIR}/usr/bin/oapi-cli-completion.bash"
cat "${APPDIR}/usr/bin/____cli_name____-completion.bash"
exit 0
fi
done

export COGNAC_HELP_APPEND="$(echo -en '\t--bash-completion\tprint bash completion(appimage only)\n\t--appimage-help\t\tappimage helps')"

LD_LIBRARY_PATH=${APPDIR}/usr/lib/ "${APPDIR}/usr/bin/oapi-cli" "$@"
LD_LIBRARY_PATH=${APPDIR}/usr/lib/ "${APPDIR}/usr/bin/____cli_name____" "$@"
29 changes: 29 additions & 0 deletions HACKING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# Do You Want To Know More?

*Essential Information for Hacking COGNAC*

## Unix Philosophy and COGNAC Paradigms.

Most people have heard the phrase "Do One Thing and Do It Well" and associate it with the Unix philosophy. It’s said that this is how Unix operates and how it should be.

Personally, I used to wonder how much truth there was to this statement, or whether it was even a good idea. Like many others, I would nod along, pretending to understand it, but I didn’t really get it. Now, though, I feel I have a much better understanding of what it truly means.

ow, you ask? By reading the source code of some Unix-based OSes.
When I read a complete [shell](https://github.com/dspinellis/unix-history-repo/blob/BSD-1-Snapshot-Development/s1/sh.c), the whole source of [ls](https://github.com/dspinellis/unix-history-repo/blob/BSD-1-Snapshot-Development/s6/ls.c), or a fully running [cat](https://github.com/klange/toaruos/blob/master/apps/cat.c), I had a realization: most of these programs are written in far fewer lines of code than I would need just to write half of an object interface in a modern language.

It started to make sense. These programs were built to interact with each other. While we tend to view programs as entire projects nowadays, in Unix, a program was designed to do just one thing—and do it well. Modularity wasn’t a priority. Why create a complex interface when writing an entirely new program could be faster? In Unix, programs like cat, grep, and wc are almost like objects in an object-oriented system, inheriting basic text-handling class.

COGNAC is based on Bash, and it follows a similar philosophy.

It uses a lot of small programs that interact with each other and is supplemented by a few utilities in the bin/ directory that handle text processing tasks.

The Makefile was originally created to "make" files, and COGNAC uses it in that way.

The scripts used by the Makefile handle the actual file creation, while the Makefile itself checks if files need to be rebuilt or not.

## Templating

COGNAC’s templating system is homemade. It reads SRC files and generates DEST files. It uses several keywords, each surrounded by four underscores (e.g., `____api_version____`).
For example, you can check out [lib.h](./lib.h) or [main_tpl.c](./main_tpl.c)

Some rules support multiple languages, like `____func_code____`, which generates function calls. Others, like `____functions_proto____`, currently support only C.
27 changes: 15 additions & 12 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,29 +1,35 @@
# COGNAC for: Code Outscale Generator New Automatic Creator
# you can find a better name if you want.

all: oapi-cli-completion.bash oapi-cli
all: make_cli

config.mk:
@echo "config.mk is not present"
@echo "use './configure --help' for information, on how to make it"
@exit 1

OAPI_RULE_DEPEDENCIES=main.c osc_sdk.h osc_sdk.c main-helper.h
OAPI_APPIMAGE_RULE_DEPEDENCIES=oapi-cli-completion.bash
OAPI_APPIMAGE_RULE_DEPEDENCIES=$(CLI_NAME)-completion.bash

list_api_version:
curl -s https://api.github.com/repos/outscale/osc-api/tags | $(JSON_SEARCH) -R name

include config.mk

help:
@echo "Available targets:"
@echo "- osc_sdk.c/osc_sdk.h/main.c/oapi-cli-completion.bash: make the file"
@echo "- osc_sdk.c/osc_sdk.h/main.c/$(CLI_NAME)-completion.bash: make the file"
@echo "- list_api_version: list all version avable on github"
@echo "- clean: remove every generated files"

include config.mk

include oapi-cli.mk

osc-api.json::
./bin/osc-api-seems-valid.sh osc-api.json "need_remove"

make_cli: $(CLI_NAME) $(CLI_NAME)-completion.bash

bin/funclist: bin/funclist.c
$(CC) -O3 bin/funclist.c $(JSON_C_LDFLAGS) $(JSON_C_CFLAGS) -o bin/funclist

Expand All @@ -39,16 +45,13 @@ osc_sdk.c: bin/line_check osc-api.json call_list arguments-list.json config.sh l
osc_sdk.h: bin/line_check osc-api.json call_list arguments-list.json config.sh lib.h cognac_gen.sh mk_args.c.sh
./cognac_gen.sh lib.h osc_sdk.h c

oapi-cli-completion.bash: bin/line_check osc-api.json call_list arguments-list.json config.sh oapi-cli-completion-tpl.bash cognac_gen.sh
./cognac_gen.sh oapi-cli-completion-tpl.bash oapi-cli-completion.bash bash
$(CLI_NAME)-completion.bash: bin/line_check osc-api.json call_list arguments-list.json config.sh oapi-cli-completion-tpl.bash cognac_gen.sh
./cognac_gen.sh oapi-cli-completion-tpl.bash $(CLI_NAME)-completion.bash bash

config.sh:
echo "alias json-search=$(JSON_SEARCH)" > config.sh
echo $(SED_ALIAS) >> config.sh

osc-api.json:
curl -s https://raw.githubusercontent.com/outscale/osc-api/$(API_VERSION)/outscale.yaml \
| yq $(YQ_ARG) > osc-api.json
echo "export CLI_NAME=$(CLI_NAME)" >> config.sh

arguments-list.json: osc-api.json
$(JSON_SEARCH) -s Request osc-api.json | $(JSON_SEARCH) -K properties \
Expand All @@ -61,7 +64,7 @@ call_list: osc-api.json bin/funclist


clean:
rm -vf osc-api.json call_list osc_sdk.c arguments-list.json osc_sdk.h main.c oapi-cli config.sh oapi-cli-completion.bash bin/line_check
rm -vf osc-api.json call_list osc_sdk.c arguments-list.json osc_sdk.h main.c $(CLI_NAME) config.sh $(CLI_NAME)-completion.bash bin/line_check bin/funclist

.PHONY: clean list_api_version help
.PHONY: clean list_api_version help make_cli

87 changes: 81 additions & 6 deletions README.md

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The "Do You Want To Know More?" should be in another file (hacking.md)

Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,96 @@

## Usage

configure COGNAC using `./configure`, then use either `cognac_gen.sh SOURCE DEST LANGUAGE` directly, or the Makefile.
*note: The primary purpose of this repository is to generate source code. If your goal is to compile osc-sdk-c or oapi-cli, please refer to their respective repositories, which handle the code generation process for you.*

*note: The main purpose of this repository is to generate source code. If your goal is to compile osc-sdk-c or oapi-cli, please use their respective repositories, which handle the code generation process for you.*
### Brief

## Dependency
To configure the COGNAC Makefile, use `./configure.`
You can use `cognac_gen.sh SOURCE DEST LANGUAGE` to generate files from a template.
The Makefile is designed to help you generate all the required files.
If you want to generate everything, simply run `make`.

Non exaustive list:
### Generated Files

COGNAC generates four main files:
- main.c: Source code for the CLI.
- osc_sdk.h: Header file for the C library.
- osc_sdk.c: Source code for the C library.
- $(CLI_NAME)-completion.bash: Autocompletion file for the CLI.

### cognac_gen.sh

cognac_gen.sh is the script responsible for generating all the necessary files. It’s a shell script that calls sub-shell scripts and executes a few C binaries, which are compiled by the Makefile (see bin/).

It takes three arguments: a source file, a destination file, and a language.
The language argument is crucial as certain keywords might be interpreted differently depending on the target language.

The script uses a file called osc-api.json, which represents the OpenAPI specification in JSON format.
For the Outscale API, the YAML source is converted to JSON using yq.

When generating API calls, COGNAC assumes that the OpenAPI file contains components named CallRequest.
For example, if the API has a call named `CreatePony`, the corresponding component should be located at `#/components/schemas/CreatePonyRequest`.

*Note: There are two versions of yq: one written in Python and one in Go. The default version depends on your distribution. On Arch-based distributions, the Python version is typically the default, whereas on Debian-based distributions, the Go version is default. COGNAC supports both, but to use the Go version, you need to pass `--yq-go` to `./configure`.*

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are two versions of yq: one written in Python and one in Go. The default version depends on your distribution. On Arch-based distributions, the Python version is typically the default, whereas on Debian-based distributions, the Go version is default. COGNAC supports both, but to use the Go version, you need to pass --yq-go to ./configure.

### Example: Generating a CLI for a New API

Let’s say you have an API that is not the Outscale API, and you want to generate a CLI for it.
You have a URL to a YAML file, such as `https://ponyapi.yolo/`, and the API request components are named `XInput` instead of `XRequest`.

To configure the Makefile to generate the CLI with the name `pony-cli`, and adjust the component naming convention, follow these steps:

Run the following command:
```bash
./configure --cli-name=pony-cli --api-script='curl -s https://ponyapi.yolo | yq $(YQ_ARG) | sed "s/Input/Request/" > osc-api.json'
```

`-cli-name=pony-cli` set the generated binary name to `pony-cli`

```bash
--api-script='curl -s https://ponyapi.yolo | yq $(YQ_ARG) | sed "s/Input/Request/" > osc-api.json'
```
This script is used to fetch the API file.


Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here’s what the script does:

Here’s what the script does:

1. Retrieves the API in YAML format using curl -s `https://ponyapi.yolo/.`
2. Converts the YAML to JSON using yq `$(YQ_ARG)`. *Note the usage of `$(YQ_ARG)`, so ./configure can handle go version of yq*
3. Renames all components named `XInput` to `XRequest`.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • --compile-json-c: Ensures a recent version of json-c is compiled, required for color support.

Once this setup is complete, you can now use the Makefile. It's also a good idea to run ./configure --help, as it contains several useful options.
- `--wget-json-search`: Helps with downloading `json-search`, which can be tricky to install, **If unsure, we recommend using this by default**
- `--compile-json-c`: Ensures a recent version of `json-c` is compiled, required for color support. **If unsure, we recommend using this by default**

Now, simply run `make` to generate all necessary files and compile the CLI. This will also create a C SDK, consisting of two files: `osc-sdk.c` and `osc-sdk.h`.

If you want more control over the generation process, you can manually invoke specific Makefile rules:
```bash
make main.c osc_sdk.c osc_sdk.h pony-cli-completion.bash pony-cli
```

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

make main.c osc_sdk.c osc_sdk.h pony-cli-completion.bash pony-cli


## Dependencies

Here’s a non-exhaustive list of required dependencies:
- GNU sed
- bash
- jq
- [json-search](https://github.com/cosmo-ray/json-search)
- make
- pkg-config
- C Compiller
- C Compiler

### Optional Dependencies
- libfuse2 (require if building appimage or with `--wget-json-search`)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • GNU sed
  • bash
  • jq
  • json-search
  • make
  • pkg-config
  • C Compiler

## contribution

## Contribution

Open Pull Requests and Issues are welcome.

If you want to add binaries to the bin/ directory, please ensure they are easy to compile.
This means avoiding additional dependencies that are not already required by the CLI.

For more information about cognac code, see [HACKING.md](./HACKING.md)
File renamed without changes
12 changes: 10 additions & 2 deletions bin/funclist.c
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,15 @@ int main(int ac, char **av)
{
struct json_object *j_file = json_object_from_file(av[1]);

struct json_object *compo = json_object_object_get(j_file, "components");
struct json_object *schema = json_object_object_get(compo, "schemas");
struct json_object *compo;
struct json_object *schema;
int ret = 0;
ret = json_object_object_get_ex(j_file, "components", &compo);
if (!ret)
return 1;
json_object_object_get_ex(compo, "schemas", &schema);
if (!ret)
return 1;
int first = 1;

json_object_object_foreach(schema, k, v_) {
Expand All @@ -23,4 +30,5 @@ int main(int ac, char **av)
free(new_k);
}
json_object_put(j_file);
return 0;
}
19 changes: 19 additions & 0 deletions bin/osc-api-seems-valid.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
#!/bin/bash

# check if $1 is valide, if $2 is present, remove invalide file
config_path=$(realpath $(dirname $0))/../config.sh

shopt -s expand_aliases
source $config_path

test=$(json-search -sn Request $1 | json-search -n properties)
test_ret=$?

if [ "$test_ret" == "1" -o "$test" == "null" ]; then
echo "$1 is invalide" >&2
if [ "$#" -gt 1 ]; then
rm $1
fi
fi


4 changes: 2 additions & 2 deletions oapi-cli.AppDir/oapi-cli.desktop → cli.desktop
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[Desktop Entry]
Type=Application
Name=oapi-cli
Exec=oapi-cli
Name=____cli_name____
Exec=____cli_name____
Comment=CLI-of Outscale Granting Net Accessible Calls
Categories=Development;Network;
Terminal=true
Expand Down
27 changes: 22 additions & 5 deletions cognac_gen.sh
Original file line number Diff line number Diff line change
Expand Up @@ -207,8 +207,6 @@ replace_args()
SDK_VERSION=$(cat sdk-version)
while IFS= read -r line
do
#check ____args____ here

arg_check=$(bin/line_check ____args____ ____func_code____ ____functions_proto____ ____cli_parser____ ____complex_struct_func_parser____ ____complex_struct_to_string_func____ ____call_list_dec____ ____call_list_descriptions____ ____call_list_args_descriptions____ <<< "$line")

if [ "$arg_check" == "____args____" ]; then
Expand Down Expand Up @@ -306,7 +304,8 @@ EOF
#for s in "skip"; do
struct_name=$(to_snakecase <<< $s)

A_LST=$(jq .components.schemas.$s < osc-api.json | json-search -Kn properties | tr -d '",[]')
local componant=$(jq .components.schemas.$s < osc-api.json)
A_LST=$(json-search -Kn properties <<< $componant | tr -d '",[]')
if [ "$A_LST" != "null" ]; then
echo "int ${struct_name}_parser(void *v_s, char *str, char *aa, struct ptr_array *pa) {"

Expand All @@ -319,12 +318,30 @@ EOF
echo " if ((aret = argcmp(str, \"$a\")) == 0 || aret == '=' || aret == '.') {"
cli_c_type_parser "$a" "$t" " "
done
cat <<EOF
aditional=$(json-search -n additionalProperties <<< $componant)

if [ "$aditional" == "null" -o "$aditional" == "false" ]; then

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if [ "$aditional" == "null" || "$aditional" == "false" ]; then

cat <<EOF
{
fprintf(stderr, "'%s' not an argumemt of '$s'\n", str);
return -1;
}
EOF
else
# no type check are made here, the aditional stuff is assumed to be a string

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no type checks are made here, the additional stuff is assumed to be a string

cat <<EOF
{
struct additional_strings *elem = malloc(sizeof *elem);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if (!elem) {
   fprintf(stderr, "Memory allocation failed");
   return -1;
}

(void)aret;
ptr_array_append(pa, elem);

SET_NEXT(s->additional_strs, elem, pa);
elem->key = str;
elem->val = aa;
}
EOF
fi

echo " return 0;"
echo -e '}\n'
fi
Expand Down Expand Up @@ -465,7 +482,7 @@ EOF
done < function.${lang}
done
else
sed "s/____call_list____/${CALL_LIST}/g;s/____piped_call_list____/${PIPED_CALL_LIST}/;s/____api_version____/${API_VERSION}/g;s/____sdk_version____/${SDK_VERSION}/g;s/____cli_version____/$(cat cli-version)/g" <<< "$line";
sed "s/____call_list____/${CALL_LIST}/g;s/____piped_call_list____/${PIPED_CALL_LIST}/;s/____api_version____/${API_VERSION}/g;s/____sdk_version____/${SDK_VERSION}/g;s/____cli_version____/$(cat cli-version)/g;s/____cli_name____/${CLI_NAME}/" <<< "$line";
fi
done < $1
}
Expand Down
Loading
Loading