33from __future__ import annotations
44
55import sys
6- import types
7- from pathlib import Path
86from typing import Iterator , Tuple
97
108from google .protobuf .compiler import plugin_pb2
119
1210from .enum_renderer import EnumRenderer
11+ from .options_runtime import get_arduino_opts_pb2
1312from .service_renderer import ServiceRenderer
1413from .service_model_builder import ServiceModelBuilder
1514from .request_context import RequestContext
1918]
2019
2120
22- def _load_arduino_opts_pb2 () -> types .ModuleType :
23- import importlib .util
24- import os
25- import re
26- import subprocess
27- import tempfile
28-
29- def patch_runtime_guard (pb2_path : Path ) -> None :
30- text = pb2_path .read_text (encoding = "utf-8" )
31- import_line = "from google.protobuf import runtime_version as _runtime_version\n "
32- import_guard = (
33- "try:\n "
34- " from google.protobuf import runtime_version as _runtime_version\n "
35- "except ImportError:\n "
36- " _runtime_version = None\n "
37- )
38- if import_line in text and import_guard not in text :
39- text = text .replace (import_line , import_guard )
40-
41- pattern = re .compile (
42- r"_runtime_version\.ValidateProtobufRuntimeVersion\(\n"
43- r"(?P<body>(?:\s+.*\n)+?)"
44- r"\)\n"
45- )
46- match = pattern .search (text )
47- if match and "if _runtime_version is not None:" not in text :
48- body = "" .join (f" { line } " for line in match .group ("body" ).splitlines (True ))
49- wrapped = (
50- "if _runtime_version is not None:\n "
51- " _runtime_version.ValidateProtobufRuntimeVersion(\n "
52- f"{ body } "
53- " )\n "
54- )
55- text = text [: match .start ()] + wrapped + text [match .end () :]
56-
57- pb2_path .write_text (text , encoding = "utf-8" )
58-
59- def generate_pb2_to_temp () -> Path :
60- proto_dir = Path (__file__ ).resolve ().parents [2 ] / "idl" / "proto"
61- proto_file = proto_dir / "arduino_opts.proto"
62- cache_dir = Path (tempfile .gettempdir ()) / "protoc_gen_arduinoif_pb2"
63- cache_dir .mkdir (parents = True , exist_ok = True )
64- pb2_path = cache_dir / "arduino_opts_pb2.py"
65-
66- should_generate = True
67- if pb2_path .exists ():
68- should_generate = pb2_path .stat ().st_mtime < proto_file .stat ().st_mtime
69-
70- if should_generate :
71- subprocess .run (
72- [
73- "protoc" ,
74- f"--proto_path={ proto_dir } " ,
75- f"--python_out={ cache_dir } " ,
76- str (proto_file ),
77- ],
78- check = True ,
79- )
80- patch_runtime_guard (pb2_path )
81-
82- return pb2_path
83-
84- pb2_path = os .environ .get ("PROTOC_GEN_ARDUINOIF_PB2" )
85- if pb2_path and Path (pb2_path ).exists ():
86- source_path = Path (pb2_path )
87- module_name = "_protoc_gen_arduinoif_arduino_opts_pb2"
88- else :
89- source_path = generate_pb2_to_temp ()
90- module_name = "_protoc_gen_arduinoif_arduino_opts_pb2_generated"
91-
92- spec = importlib .util .spec_from_file_location (module_name , source_path )
93- if spec is None or spec .loader is None :
94- raise RuntimeError (f"failed to load arduino_opts_pb2 from '{ source_path } '" )
95- module = importlib .util .module_from_spec (spec )
96- spec .loader .exec_module (module )
97- return module
98-
99-
10021def _iter_generated_files (
10122 request : plugin_pb2 .CodeGeneratorRequest ,
102- arduino_opts_pb2 : types .ModuleType ,
10323) -> Iterator [Tuple [str , str ]]:
104- ServiceModelBuilder .configure_options_module (arduino_opts_pb2 )
10524 context = RequestContext .build (request )
10625
10726 for proto_file in request .proto_file :
@@ -125,13 +44,13 @@ def _iter_generated_files(
12544
12645
12746def main () -> int :
128- arduino_opts_pb2 = _load_arduino_opts_pb2 ()
47+ get_arduino_opts_pb2 ()
12948 request = plugin_pb2 .CodeGeneratorRequest ()
13049 request .ParseFromString (sys .stdin .buffer .read ())
13150 response = plugin_pb2 .CodeGeneratorResponse ()
13251
13352 try :
134- for name , content in _iter_generated_files (request , arduino_opts_pb2 ):
53+ for name , content in _iter_generated_files (request ):
13554 output = response .file .add ()
13655 output .name = name
13756 output .content = content
0 commit comments