Skip to content
Open

Rust #49

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
2 changes: 1 addition & 1 deletion .generation/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# Patched version of openapi-generator-cli with python3 support

FROM docker.io/openapitools/openapi-generator-cli:v7.12.0
FROM docker.io/openapitools/openapi-generator-cli:v7.17.0

RUN apt-get update && apt-get install -y python3
4 changes: 2 additions & 2 deletions .generation/config.ini
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
[input]
backendCommit = a67f76af99b5b579fa0823bfa5908fae0049cb22
backendCommit = 9c2decb9f961cdce3d26f278291344bc269b4cbe

[general]
githubUrl = https://github.com/geo-engine/openapi-client
version = 0.0.27
version = 0.0.28

[python]
name = geoengine_openapi_client
Expand Down
127 changes: 103 additions & 24 deletions .generation/generate.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@
import os
import shutil
import subprocess
import sys
from typing import Literal
import logging

Expand All @@ -24,7 +23,7 @@

class ProgramArgs(argparse.Namespace):
'''Typed command line arguments.'''
language: Literal['python', 'typescript']
language: Literal['python', 'rust', 'typescript']
fetch_spec: bool
build_container: bool

Expand All @@ -37,10 +36,10 @@ def parse_arguments() -> ProgramArgs:
required=False, default=True)
parser.add_argument('--no-container-build', dest='build_container', action='store_false',
required=False, default=True)
parser.add_argument('language', choices=['python', 'typescript'],
parser.add_argument('language', choices=['python', 'rust', 'typescript'],
type=str)

parsed_args: ProgramArgs = parser.parse_args()
parsed_args: ProgramArgs = parser.parse_args() # type: ignore[assignment]
return parsed_args


Expand All @@ -51,7 +50,7 @@ class ConfigArgs():
ge_backend_commit: str

# General
github_url: str
github_repository: GitHubRepository
package_version: str

# Python package name
Expand All @@ -64,12 +63,13 @@ class ConfigArgs():
def parse_config() -> ConfigArgs:
'''Parse config.ini arguments.'''
parsed = configparser.ConfigParser()
parsed.optionxform = str # do not convert keys to lowercase
# do not convert keys to lowercase
parsed.optionxform = lambda optionstr: optionstr # type: ignore[method-assign]
parsed.read(CWD / 'config.ini')

return ConfigArgs(
ge_backend_commit=parsed['input']['backendCommit'],
github_url=parsed['general']['githubUrl'],
github_repository=GitHubRepository(parsed['general']['githubUrl']),
package_version=parsed['general']['version'],
python_package_name=parsed['python']['name'],
typescript_package_name=parsed['typescript']['name'],
Expand All @@ -83,7 +83,7 @@ def fetch_spec(*, ge_backend_commit: str) -> None:

request_url = f"https://raw.githubusercontent.com/geo-engine/geoengine/{ge_backend_commit}/openapi.json"

logging.info(f"Requesting `openapi.json` at `{request_url}`….")
logging.info("Requesting `openapi.json` at `%s`….", request_url)
with request.urlopen(request_url, timeout=10) as w, \
open(CWD / "input/openapi.json", "w", encoding='utf-8') as f:
f.write(w.read().decode('utf-8'))
Expand All @@ -108,9 +108,9 @@ def build_container():
def clean_dirs(*, language: Literal['python', 'typescript']):
'''Remove some directories because they are not be overwritten by the generator.'''

dirs_to_remove = [
'node_modules',
'.mypy_cache',
dirs_to_remove: list[Path] = [
Path('node_modules'),
Path('.mypy_cache'),
Path(language) / 'test'
]

Expand All @@ -126,12 +126,12 @@ def clean_dirs(*, language: Literal['python', 'typescript']):
Path(language) / 'geoengine_openapi_client',
])

logging.info(f"Removing directories:")
logging.info("Removing directories:")

for the_dir in dirs_to_remove:
if not os.path.isdir(the_dir):
continue
logging.info(f" - {the_dir}")
logging.info(" - %s", the_dir)
shutil.rmtree(the_dir)


Expand Down Expand Up @@ -165,14 +165,12 @@ def generate_python_code(*, package_name: str, package_version: str, package_url
shutil.rmtree(Path("python") / "docs")


def generate_typescript_code(*, npm_name: str, npm_version: str, repository_url: str):
def generate_typescript_code(*,
npm_name: str,
npm_version: str,
github_repository: GitHubRepository):
'''Run the generator.'''

parsed_url = urlsplit(repository_url)
(url_path, _url_ext) = os.path.splitext(parsed_url.path)
(url_path, git_repo_id) = os.path.split(url_path)
(url_path, git_user_id) = os.path.split(url_path)

subprocess.run(
[
"podman", "run",
Expand All @@ -189,9 +187,9 @@ def generate_typescript_code(*, npm_name: str, npm_version: str, repository_url:
f"npmName={npm_name}",
f"npmVersion={npm_version}",
]),
"--git-host", parsed_url.netloc,
"--git-user-id", git_user_id,
"--git-repo-id", git_repo_id,
"--git-host", github_repository.host,
"--git-user-id", github_repository.user,
"--git-repo-id", github_repository.repo,
"--enable-post-process-file",
"-o", "/local/typescript/",
"--openapi-normalizer", "REF_AS_PARENT_IN_ALLOF=true",
Expand All @@ -205,6 +203,80 @@ def generate_typescript_code(*, npm_name: str, npm_version: str, repository_url:
''')
shutil.rmtree(Path("typescript") / ".openapi-generator")

def generate_rust_code(*, package_name: str, package_version: str, git_repo: GitHubRepository):
'''Run the generator.'''

subprocess.run(
[
"podman", "run",
"--rm", # remove the container after running
"-v", f"{os.getcwd()}:/local",
f"--env-file={CWD / 'override.env'}",
# "docker.io/openapitools/openapi-generator-cli:v7.0.1",
"openapi-generator-cli:patched",
"generate",
"-i", f"{'/local' / CWD / 'input/openapi.json'}",
"-g", "rust",
"--additional-properties=" + ",".join([
f"packageName={package_name.replace('_', '-')}",
f"packageVersion={package_version}",
]),
"--git-host", git_repo.host,
"--git-user-id", git_repo.user,
"--git-repo-id", git_repo.repo,
"--enable-post-process-file",
"-o", "/local/rust/",
"--openapi-normalizer", "REF_AS_PARENT_IN_ALLOF=true",
],
check=True,
)

# Temporary solution because `RUST_POST_PROCESS_FILE` is not used by the generator
for rust_file in [
"apis/ogcwfs_api.rs",
"apis/ogcwms_api.rs",
"apis/projects_api.rs",
"apis/tasks_api.rs",
"apis/uploads_api.rs",
"models/spatial_partition2_d.rs",
"models/spatial_resolution.rs",
]:
subprocess.run(
[
"podman", "run",
"--rm", # remove the container after running
"-v", f"{os.getcwd()}:/local",
f"--env-file={CWD / 'override.env'}",
# "docker.io/openapitools/openapi-generator-cli:v7.0.1",
"openapi-generator-cli:patched",
"python3",
"/local/.generation/post-process/rust.py",
"/local/rust/src/" + rust_file,
],
check=True,
)

@dataclass
class GitHubRepository:
'''Git repository triplet.'''
host: str
user: str
repo: str

def __init__(self, url: str) -> None:
'''Create a GitHubRepository from a URL.'''
parsed_url = urlsplit(url)
(url_path, _url_ext) = os.path.splitext(parsed_url.path)
(url_path, git_repo_id) = os.path.split(url_path)
(url_path, git_user_id) = os.path.split(url_path)

self.host = parsed_url.netloc
self.user=git_user_id
self.repo=git_repo_id

def url(self) -> str:
'''Get the URL of the repository.'''
return f"https://{self.host}/{self.user}/{self.repo}"

def main():
'''The entry point of the program'''
Expand All @@ -231,14 +303,14 @@ def main():
generate_python_code(
package_name=config.python_package_name,
package_version=config.package_version,
package_url=config.github_url,
package_url=config.github_repository.url(),
)
elif args.language == 'typescript':
logging.info("Generating TypeScript client…")
generate_typescript_code(
npm_name=config.typescript_package_name,
npm_version=config.package_version,
repository_url=config.github_url,
github_repository=config.github_repository,
)

# Create dist files.
Expand All @@ -255,6 +327,13 @@ def main():
],
check=True,
)
elif args.language == 'rust':
logging.info("Generating Rust client…")
generate_rust_code(
package_name=config.python_package_name,
package_version=config.package_version,
git_repo=config.github_repository,
)
else:
raise RuntimeError(f'Unknown language {args.language}.')

Expand Down
1 change: 1 addition & 0 deletions .generation/override.env
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
PYTHON_POST_PROCESS_FILE=python3 /local/.generation/post-process/python.py
TS_POST_PROCESS_FILE=python3 /local/.generation/post-process/typescript.py
RUST_POST_PROCESS_FILE=python3 /local/.generation/post-process/rust.py
3 changes: 2 additions & 1 deletion .generation/post-process/python.py
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,8 @@ def layers_api_py(file_contents: List[str]) -> Generator[str, None, None]:

yield line

def ogc_xyz_api_py(ogc_api: Literal['wfs', 'wms']) -> Callable[[List[str]], Generator[str, None, None]]:
def ogc_xyz_api_py(
ogc_api: Literal['wfs', 'wms']) -> Callable[[List[str]], Generator[str, None, None]]:
'''Modify the ogc_xyz_api.py file.'''
def _ogc_xyz_api_py(file_contents: List[str]) -> Generator[str, None, None]:
'''Modify the ogc_wfs_api.py file.'''
Expand Down
Loading