-
Notifications
You must be signed in to change notification settings - Fork 1
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
More cli support #18
base: master
Are you sure you want to change the base?
More cli support #18
Changes from 27 commits
65e1ce3
651460a
d6bad35
85afe61
2416cfe
8bcaa35
92945b2
9e45172
0927c7a
56e4c39
e4ddaa5
7377d15
311f5b4
21eddf5
11ecece
65b5cd3
a358f07
8a5cb45
855bff1
45fcbfc
18c75ac
3d9786e
f7e951c
a68744d
b6195ee
20bee6c
c51d577
7f9efba
d6d23e3
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,6 +2,13 @@ | |
|
||
*Essential Information for Hacking COGNAC* | ||
|
||
## Enabling debug | ||
|
||
To enable debug, use `--debug-mode` in `./configure` | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. To enable debug mode, use the --debug-mode option with the ./configure command |
||
|
||
then the `debug` commande in the shell script will print some information. | ||
without this option debug will print nothing | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Once enabled, the debug command in the shell script will print debug information. Without this option, the debug command will not output any information. |
||
|
||
## 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. | ||
|
@@ -35,6 +42,28 @@ A relatively easy way to add a feature in Cognac is to start by modifying the ge | |
|
||
For exemple, if you modify a function like `parse_thatarg()` in "osc_sdk.c", once the changes are working, you can then search (using a tool like grep) through the generator code to find where `parse_thatarg` is generated. From there, you can add modifications to the generator to make the change permanent and automated. | ||
|
||
## Example to add a new API, that doesn't work at first. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Example: Adding a New API That Initially Doesn't Work |
||
|
||
Let's say you ahve configure cognac like this | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Let's say you have configured Cognac like this: |
||
|
||
```sh | ||
./configure --sdk-name=myapi-sdk --cli-name=guru --api-script='cat myapi-api.json > osc-api.json' --debug-mode --from-path | ||
``` | ||
|
||
doing that you will use try to generate the api from path, with debug enable. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. By doing that, you will attempt to generate the API from the path with debug enabled. |
||
|
||
now let's say you have this output while calling `make`: | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Now, let's say you get this output while running make |
||
``` | ||
____complex_struct_func_parser____ | ||
nothing found____cli_parser____ | ||
nothing founderror in <stdin> jsonnothing founderror in <stdin> jsonnothing founderror in <stdin> jsonnothing founderror in <stdin> jsonnothing founderror in <stdin> jsonnothing founderror in <stdin> jsonnothing founderror in <stdin> json./cognac_gen.sh lib.h osc_sdk.h c | ||
debug mode is on | ||
``` | ||
|
||
This mean that durring `____complex_struct_func_parser____` `____cli_parser____`, the scripts fails to pasre some part of osc-api json. | ||
To debug it, you should look at what happen durring `____complex_struct_func_parser____` and `____cli_parser____` inside `cognac_gen.sh` | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This means that during 'complex_struct_func_parser' and 'cli_parser', the script fails to parse some parts of the osc-api JSON. |
||
|
||
|
||
## helpers.sh | ||
|
||
Most functions in helper.sh are documented, so read through it if you want to understand some of the most commonly used functions in cognac_gen. |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -28,14 +28,20 @@ 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. | ||
For the Outscale API, the YAML source is converted to JSON using `yq`: (https://kislyuk.github.io/yq/ or https://github.com/mikefarah/yq) | ||
|
||
When generating API calls, COGNAC assumes that the OpenAPI file contains components named CallRequest. | ||
When generating API calls, COGNAC by default 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`. | ||
|
||
You can modify the suffix of functions by using `--function-suffix=FUNCTION_SUFFIX` option with `./configure` command. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You can modify the function suffix by using the |
||
|
||
Or you can generate functions using what is inside `paths`, using `./configure --from-path` | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Alternatively, you can generate functions based on the contents of |
||
|
||
*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`.* | ||
|
||
### Example: Generating a CLI for a New API | ||
### Examples: Generating a CLI for a New API | ||
|
||
#### Configure cognac for an Api using elements in schema as entry point for API Calls | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Configure Cognac for an API using elements in the schema as entry points for API calls. |
||
|
||
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`. | ||
|
@@ -44,22 +50,45 @@ To configure the Makefile to generate the CLI with the name `pony-cli`, and adju | |
|
||
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' | ||
./configure --cli-name=pony-cli --function-suffix Input --api-script='curl -s https://ponyapi.yolo | yq $(YQ_ARG)" > 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' | ||
--function-suffix Input | ||
``` | ||
|
||
Search for functions named XInput instead of XRequest. | ||
```bash | ||
--api-script='curl -s https://ponyapi.yolo | yq $(YQ_ARG) > osc-api.json' | ||
``` | ||
|
||
|
||
This script is used to fetch the API file. | ||
|
||
|
||
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`. | ||
|
||
|
||
#### Configure cognac for an Api using elements in path as entry point for API Calls | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Configure Cognac for an API using elements in the path as entry points for API calls. |
||
|
||
For this example we will use [guru](https://apis.guru/api-doc/) | ||
|
||
Run the following commande | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Run the following command: |
||
``` | ||
./configure --sdk-name=guru-sdk --cli-name=guru --from-path --api-script='curl -s https://api.apis.guru/v2/openapi.yaml | yq $(YQ_ARG)" > osc-api.json' | ||
``` | ||
|
||
`--cli-name=guru` set the generated binary name to `guru` | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
`--sdk-name=guru-sdk` set the generate sdk name and UserAgent to `guru-sdk` | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
`--from-path` generate API calls from elements in `paths` instead of `components.schemas` | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
|
||
|
||
#### Generte the code | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Generate the Code |
||
|
||
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** | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -23,3 +23,112 @@ This is also much faster than multiple calls to grep. | |
# osc-api-seems-valid.sh | ||
|
||
This utility is used to check if osc-api.json has been generated correctly. It verifies that the file is a valid JSON and contains at least one API function. | ||
|
||
# path_to_snakecase | ||
snakecasise an object name. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Converts an object name to snake_case. |
||
example `ReadVms` become `read_vms` | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Examples:
|
||
`/my/{NAME}/getId` become `my_name_get_id` | ||
|
||
usage: | ||
``` | ||
./path_to_snakecase STRING | ||
``` | ||
|
||
# path_to_camelcase | ||
camelcasise an object name. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Converts an object name to camelCase. |
||
example `ReadVms` become `read_vms` | ||
`/my/{NAME}/getId` become `my_name_get_id` | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Examples:
|
||
|
||
usage: | ||
``` | ||
./path_to_camelcase STRING | ||
``` | ||
|
||
# get_argument_list | ||
|
||
Take an object componant in `paths` or in `components.schema`, and give a list of all it arguments. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Retrieves an object component from |
||
|
||
usage: | ||
``` | ||
./get_argument_list file.json componant_name | ||
``` | ||
|
||
# get_path_type | ||
|
||
usage: | ||
``` | ||
./bin/get_path_type osc-api.json PATH ARGUMENT_NAME | ||
``` | ||
|
||
example: | ||
|
||
``` | ||
$ ./bin/get_path_type osc-api.json /projects id | ||
int | ||
``` | ||
|
||
assuming id is of type int | ||
|
||
or | ||
|
||
usage: | ||
``` | ||
./bin/get_path_type JSON_ELEM ARGUMENT_NAME | ||
``` | ||
|
||
example: | ||
``` | ||
$ ./bin/get_path_type '{"post": {"parameters": [ {"name": "a", "type": "string"} ]}}' "a" | ||
string | ||
|
||
``` | ||
|
||
# get_path_description | ||
|
||
Just return "" so far, as the api I test this with, had no description in the path | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Returns an empty string "" for now, as the API I tested this with had no description in the path. |
||
|
||
usage: | ||
``` | ||
./get_path_description JSON_ELEM ARG | ||
``` | ||
|
||
example: | ||
``` | ||
./get_path_description "{...}" argument_named_titi | ||
``` | ||
|
||
# arg_placement | ||
|
||
return where the argument is used. | ||
`path`, if the argument is use in the path | ||
`header` if it is an http header | ||
`query` if it is in a query string | ||
`data` if it is use in post data | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Return where the argument is used:
|
||
|
||
|
||
usage: | ||
``` | ||
./arg_placement osc-api.json PATH ARGUMENT_NAME | ||
``` | ||
|
||
example: | ||
``` | ||
$ ./arg_placement osc-api.json /projects id | ||
query | ||
``` | ||
|
||
# construct_path | ||
|
||
generate the C code to create a osc_str that the path of the call. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Generate the C code to create an osc_str for the path of the call. |
||
|
||
example: | ||
|
||
``` | ||
$ ./construct_path /project/{id}/get | ||
|
||
osc_str_append_string(&end_call, "/project/"); | ||
osc_str_append_string(&end_call, args->id); | ||
osc_str_append_string(&end_call, "/get"); | ||
``` | ||
|
||
The code generated is not exhaustive, but you get the idea. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The generated code is not exhaustive, but it conveys the general idea. |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
#include <stdbool.h> | ||
#include <stdio.h> | ||
#include <string.h> | ||
#include "json.h" | ||
#define UNFOUND "data" | ||
#include "helper.h" | ||
|
||
int main(int ac, char **av) | ||
{ | ||
struct json_object *j_file = json_object_from_file(av[1]); | ||
char *componant_name = av[2]; | ||
char *arg_name = av[3]; | ||
int ret; | ||
struct json_object *path; | ||
struct json_object *post_or_get; | ||
struct json_object *parameters; | ||
|
||
path = get_path_from_file(j_file, componant_name); | ||
post_or_get = get_or_post_from_path(path); | ||
if (!post_or_get) | ||
goto err; | ||
|
||
OBJ_GET(post_or_get, "parameters", ¶meters); | ||
int len = json_object_array_length(parameters); | ||
for (int i = 0; i < len; ++i) { | ||
struct json_object *param = json_object_array_get_idx(parameters, i); | ||
struct json_object *name_obj; | ||
struct json_object *in; | ||
|
||
OBJ_GET(param, "name", &name_obj); | ||
const char *name = json_object_get_string(name_obj); | ||
struct json_object *type; | ||
struct json_object *schema; | ||
|
||
if (strcmp(name, arg_name)) | ||
continue; | ||
OBJ_GET(param, "in", &in); | ||
puts(json_object_get_string(in)); | ||
goto out; | ||
} | ||
out: | ||
err: | ||
json_object_put(j_file); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
#include <stdio.h> | ||
#include <string.h> | ||
|
||
|
||
int main(int ac, char **av) | ||
{ | ||
int buf_i; | ||
char *componant_name = av[1]; | ||
|
||
again: | ||
char *brk = strchr(componant_name, '{'); | ||
if (!brk) { | ||
printf("\tosc_str_append_string(&e->endpoint, \"%s\");\n", componant_name); | ||
return 0; | ||
} | ||
|
||
*brk = 0; | ||
printf("\tosc_str_append_string(&e->endpoint, \"%s\");\n", componant_name); | ||
|
||
printf("\tosc_str_append_string(&e->endpoint, e->"); | ||
for (++brk; *brk != '}'; ++brk) | ||
putchar(*brk); | ||
puts(");"); | ||
componant_name = brk + 1; | ||
goto again; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Enabling Debug Mode