11import logging
22import os
3- import yaml
43
54from utils .config import Config
6-
5+ from utils .plane import PlaneEnum
6+ from utils .readme_helper import parse_readme_file
7+ from ps .model import PSModuleConfig
8+ from swagger .controller .specs_manager import SwaggerSpecsManager
9+ from swagger .model .specs import SwaggerModule
10+ from command .controller .specs_manager import AAZSpecsManager
11+ from swagger .model .specs import OpenAPIResourceProvider
12+ from swagger .utils .tools import resolve_path_to_uri
713logger = logging .getLogger ('backend' )
814
915
@@ -12,6 +18,20 @@ class PSModuleManager:
1218 def __init__ (self ):
1319 module_folder = self ._find_module_folder ()
1420 self .folder = module_folder
21+ self ._aaz_specs = None
22+ self ._swagger_specs = None
23+
24+ @property
25+ def aaz_specs (self ):
26+ if not self ._aaz_specs :
27+ self ._aaz_specs = AAZSpecsManager ()
28+ return self ._aaz_specs
29+
30+ @property
31+ def swagger_specs (self ):
32+ if not self ._swagger_specs :
33+ self ._swagger_specs = SwaggerSpecsManager ()
34+ return self ._swagger_specs
1535
1636 def _find_module_folder (self ):
1737 powershell_folder = Config .POWERSHELL_PATH
@@ -48,12 +68,8 @@ def load_module(self, module_names):
4868 folder = os .path .join (self .folder , * module_names )
4969 if not os .path .exists (folder ):
5070 raise ValueError (f"Module folder not found: '{ folder } '" )
51- autorest_config = self .load_autorest_config (module_names )
52- return {
53- ** autorest_config ,
54- "name" : "/" .join (module_names ),
55- "folder" : folder
56- }
71+ config = self .load_module_config (module_names )
72+ return config
5773
5874 def load_autorest_config (self , module_names ):
5975 if isinstance (module_names , str ):
@@ -62,33 +78,96 @@ def load_autorest_config(self, module_names):
6278 readme_file = os .path .join (folder , "README.md" )
6379 if not os .path .exists (readme_file ):
6480 raise ValueError (f"README.md not found in: '{ readme_file } '" )
65- with open (readme_file , "r" ) as f :
66- content = f .readlines ()
67- autorest_config = []
68- in_autorest_config_section = False
69- in_yaml_section = False
70- for line in content :
71- if line .strip ().startswith ("### AutoRest Configuration" ):
72- in_autorest_config_section = True
73- elif in_autorest_config_section :
74- if line .strip ().startswith ("###" ):
75- break
76- if line .strip ().startswith ("```" ) and 'yaml' in line :
77- in_yaml_section = True
78- elif in_yaml_section :
79- if line .strip ().startswith ("```" ):
80- in_yaml_section = False
81- else :
82- if line .strip ():
83- autorest_config .append (line )
84- else :
85- autorest_config .append ("" )
86- autorest_config_raw = "\n " .join (autorest_config )
81+ content = parse_readme_file (readme_file )
82+ return content ['config' ], content ['title' ]
83+
84+ def load_module_config (self , module_names ):
8785 try :
88- yaml_config = yaml .load (autorest_config_raw , Loader = yaml .FullLoader )
89- except Exception as e :
90- raise ValueError (f"Failed to parse autorest config: { e } for readme_file: { readme_file } " )
91- return {
92- "autorest_config" : yaml_config ,
93- # "raw": autorest_config_raw # can be used for directive merging
94- }
86+ autorest_config , readme_title = self .load_autorest_config (module_names )
87+ except :
88+ logger .error (f"Failed to load autorest config for module: { module_names } , error: { e } " )
89+ raise
90+
91+ config = PSModuleConfig ()
92+ config .name = "/" .join (module_names )
93+ config .folder = self .folder
94+ if not autorest_config :
95+ raise ValueError (f"autorest config not found in README.md for module: { config .name } " )
96+
97+ # config.swagger = autorest_config
98+ repo = autorest_config .get ('repo' , "https://github.com/Azure/azure-rest-api-specs/blob/$(commit)" )
99+ if commit := autorest_config .get ('commit' ):
100+ repo = repo .replace ("$(commit)" , commit )
101+ if "$(commit)" in repo :
102+ # make sure the repo is valid https link or valid folder path
103+ raise ValueError (f"commit is not defined in autorest config for module: { config .name } " )
104+ config .repo = repo
105+
106+ readme_file = None
107+ for required_file in autorest_config ['require' ]:
108+ if required_file .startswith ('$(repo)/' ) and required_file .endswith ('/readme.md' ):
109+ readme_file = required_file .replace ('$(repo)/' , '' )
110+ break
111+
112+ if not readme_file :
113+ # search the readme.md in the swagger specs folder
114+ for input_file in autorest_config .get ('input-file' , []):
115+ if "/specification/" in input_file :
116+ folder_names = input_file .split ("/specification/" )[1 ].split ("/" )[:- 1 ]
117+ path = os .path .join (self .swagger_specs .specs .spec_folder_path , * folder_names )
118+ while path != self .swagger_specs .specs .spec_folder_path :
119+ if os .path .exists (os .path .join (path , "readme.md" )):
120+ readme_file = os .path .join (path , "readme.md" )
121+ break
122+ path = os .path .dirname (path )
123+ if readme_file :
124+ readme_file = resolve_path_to_uri (readme_file )
125+ break
126+ if not readme_file :
127+ raise ValueError (f"swagger readme.md not defined in autorest config for module: { config .name } " )
128+
129+ # use the local swagger specs to find the resource provider even the repo is in remote
130+ # we can always suppose the local swagger specs will always be newer than the used commit in submitted azure.powershell code
131+ rp = None
132+ readme_config = None
133+ plane = PlaneEnum .Mgmt if "resource-manager" in readme_file else PlaneEnum ._Data
134+ for module in self .swagger_specs .get_modules (plane ):
135+ module_relative_path = resolve_path_to_uri (module .folder_path ) + "/"
136+ if readme_file .startswith (module_relative_path ):
137+ for resource_provider in module .get_resource_providers ():
138+ if not isinstance (resource_provider , OpenAPIResourceProvider ):
139+ continue
140+ readme_config = resource_provider .load_readme_config (readme_file )
141+ if readme_config :
142+ rp = resource_provider
143+ break
144+ if rp :
145+ break
146+ if not rp :
147+ raise ValueError (f"Resource provider not found in autorest config for module: { config .name } " )
148+ config .rp = rp
149+ config .swagger = str (rp )
150+
151+ if tag := autorest_config .get ('tag' ):
152+ config .tag = tag
153+ if input_files := autorest_config .get ('input-file' ):
154+ config .input_files = []
155+ for input_file in input_files :
156+ if input_file .startswith ('$(repo)/' ):
157+ input_file = input_file .replace ('$(repo)/' , '' )
158+ config .input_files .append (input_file )
159+ if not config .input_files and not config .tag :
160+ config .tag = readme_config .get ('tag' , None )
161+
162+ if readme_title .startswith ("Az." ):
163+ config .service_name = readme_title .split ("." )[1 ]
164+ if title := autorest_config .get ('title' ):
165+ config .title = title
166+ else :
167+ # get title from swagger readme
168+ config .title = readme_config .get ('title' , None )
169+
170+ if not config .title :
171+ raise ValueError (f"Title not found in autorest config or swagger readme for module: { config .name } " )
172+
173+ return config
0 commit comments