99from dataclasses import dataclass
1010from pathlib import Path
1111from urllib import request
12- from urllib .error import URLError
1312from urllib .parse import urlsplit
1413import configparser
15- import json
1614import os
1715import shutil
1816import subprocess
1917import sys
20- import time
2118from typing import Literal
19+ import logging
2220
2321
2422CWD = Path ('.generation/' )
2523
2624
27- def eprint (* args , ** kwargs ):
28- '''Print to stderr.'''
29- print (* args , file = sys .stderr , ** kwargs )
30-
31-
3225class ProgramArgs (argparse .Namespace ):
3326 '''Typed command line arguments.'''
3427 language : Literal ['python' , 'typescript' ]
@@ -55,18 +48,17 @@ def parse_arguments() -> ProgramArgs:
5548class ConfigArgs ():
5649 '''Typed config.ini arguments.'''
5750 # Backend version
58- ge_backend_tag : str
51+ ge_backend_commit : str
5952
6053 # General
6154 github_url : str
55+ package_version : str
6256
6357 # Python package name
6458 python_package_name : str
65- python_package_version : str
6659
6760 # TypeScript package name
6861 typescript_package_name : str
69- typescript_package_version : str
7062
7163 @staticmethod
7264 def parse_config () -> ConfigArgs :
@@ -76,66 +68,32 @@ def parse_config() -> ConfigArgs:
7668 parsed .read (CWD / 'config.ini' )
7769
7870 return ConfigArgs (
79- ge_backend_tag = parsed ['input' ]['backendTag ' ],
71+ ge_backend_commit = parsed ['input' ]['backendCommit ' ],
8072 github_url = parsed ['general' ]['githubUrl' ],
73+ package_version = parsed ['general' ]['version' ],
8174 python_package_name = parsed ['python' ]['name' ],
82- python_package_version = parsed ['python' ]['version' ],
8375 typescript_package_name = parsed ['typescript' ]['name' ],
84- typescript_package_version = parsed ['typescript' ]['version' ],
8576 )
8677
8778
88- def fetch_spec (* , ge_backend_tag : str ) -> None :
79+ def fetch_spec (* , ge_backend_commit : str ) -> None :
8980 '''
90- Generate the openapi.json file.
91-
92- Imitating manually fetching it, e.g.
93-
94- ```bash
95- wget http://localhost:3030/api/api-docs/openapi.json -O - \
96- | python -m json.tool --indent 2 > .generation/input/openapi.json
97- ```
81+ Copy the openapi.json file from the backend repo.
9882 '''
99- eprint ("Starting Geo Engine backend." )
100-
101- ge_process = subprocess .Popen (
102- [
103- "podman" , "run" ,
104- "--rm" , # remove the container after running
105- "--network=host" , # port 8080 by default
106- # "-p", "3030:8080",
107- f"quay.io/geoengine/geoengine:{ ge_backend_tag } " ,
108- ],
109- env = {
110- 'GEOENGINE__POSTGRES__CLEAR_DATABASE_ON_START' : 'true' ,
111- 'PATH' : os .environ ['PATH' ],
112- },
113- )
114-
115- for _ in range (180 ): # <3 minutes
116- eprint ("Requesting `openapi.json`…." )
117- try :
118- with request .urlopen (
119- "http://localhost:8080/api/api-docs/openapi.json" ,
120- timeout = 10 ,
121- ) as w :
122- api_json = json .load (w )
12383
124- with open (CWD / "input/openapi.json" , "w" , encoding = 'utf-8' ) as f :
125- json .dump (api_json , f , indent = 2 )
84+ request_url = f"https://raw.githubusercontent.com/geo-engine/geoengine/{ ge_backend_commit } /openapi.json"
12685
127- eprint ("Stored `openapi.json`." )
128- break
129- except URLError as _e :
130- pass # try again
131- time .sleep (1 ) # 1 second
86+ logging .info (f"Requesting `openapi.json` at `{ request_url } `…." )
87+ with request .urlopen (request_url , timeout = 10 ) as w , \
88+ open (CWD / "input/openapi.json" , "w" , encoding = 'utf-8' ) as f :
89+ f .write (w .read ().decode ('utf-8' ))
13290
133- eprint ("Stopping Geo Engine backend." )
134- ge_process .kill ()
91+ logging .info ("Stored `openapi.json`." )
13592
13693
13794def build_container ():
13895 '''Build the patched generator image'''
96+ logging .info ("Building patched generator image…" )
13997 subprocess .run (
14098 [
14199 "podman" , "build" ,
@@ -144,12 +102,15 @@ def build_container():
144102 ],
145103 check = True ,
146104 )
105+ logging .info ("Patched generator image built." )
147106
148107
149108def clean_dirs (* , language : Literal ['python' , 'typescript' ]):
150109 '''Remove some directories because they are not be overwritten by the generator.'''
151110
152111 dirs_to_remove = [
112+ 'node_modules' ,
113+ '.mypy_cache' ,
153114 Path (language ) / 'test'
154115 ]
155116
@@ -158,20 +119,25 @@ def clean_dirs(*, language: Literal['python', 'typescript']):
158119 dirs_to_remove .extend ([
159120 Path (language ) / 'src' ,
160121 Path (language ) / 'dist' ,
122+ Path (language ) / 'node_modules' ,
161123 ])
162124 case 'python' :
163125 dirs_to_remove .extend ([
164126 Path (language ) / 'geoengine_openapi_client' ,
165127 ])
166128
129+ logging .info (f"Removing directories:" )
130+
167131 for the_dir in dirs_to_remove :
168132 if not os .path .isdir (the_dir ):
169133 continue
134+ logging .info (f" - { the_dir } " )
170135 shutil .rmtree (the_dir )
171136
172137
173138def generate_python_code (* , package_name : str , package_version : str , package_url : str ):
174139 '''Run the generator.'''
140+
175141 subprocess .run (
176142 [
177143 "podman" , "run" ,
@@ -242,43 +208,53 @@ def generate_typescript_code(*, npm_name: str, npm_version: str, repository_url:
242208
243209def main ():
244210 '''The entry point of the program'''
211+
212+ # Set up logging
213+ logging .basicConfig (
214+ level = logging .INFO ,
215+ format = '[%(levelname)s] %(message)s'
216+ )
217+
245218 args = ProgramArgs .parse_arguments ()
246219 config = ConfigArgs .parse_config ()
247220
248221 if args .fetch_spec :
249- fetch_spec (ge_backend_tag = config .ge_backend_tag )
222+ fetch_spec (ge_backend_commit = config .ge_backend_commit )
250223
251224 if args .build_container :
252225 build_container ()
253226
254227 clean_dirs (language = args .language )
255228
256229 if args .language == 'python' :
230+ logging .info ("Generating Python client…" )
257231 generate_python_code (
258232 package_name = config .python_package_name ,
259- package_version = config .python_package_version ,
233+ package_version = config .package_version ,
260234 package_url = config .github_url ,
261235 )
262236 elif args .language == 'typescript' :
237+ logging .info ("Generating TypeScript client…" )
263238 generate_typescript_code (
264239 npm_name = config .typescript_package_name ,
265- npm_version = config .typescript_package_version ,
240+ npm_version = config .package_version ,
266241 repository_url = config .github_url ,
267242 )
268243
269244 # Create dist files.
270245 # This is necessary for using the package directly from the git repo for development.
246+ logging .info ("Creating dist files…" )
271247 subprocess .run (
272- [
273- "podman" , "run" ,
274- "--rm" , # remove the container after running
275- "-v" , f"{ os .getcwd ()} :/local" ,
276- "--workdir=/local/typescript" , # set working directory
277- "docker.io/node:lts-alpine3.19 " ,
278- "npm" , "install" ,
279- ],
280- check = True ,
281- )
248+ [
249+ "podman" , "run" ,
250+ "--rm" , # remove the container after running
251+ "-v" , f"{ os .getcwd ()} /typescript :/local/typescript " ,
252+ "--workdir=/local/typescript" , # set working directory
253+ "docker.io/node:lts-alpine3.20 " ,
254+ "npm" , "install" ,
255+ ],
256+ check = True ,
257+ )
282258 else :
283259 raise RuntimeError (f'Unknown language { args .language } .' )
284260
0 commit comments