2222import io
2323import os
2424import pathlib
25+ import re
2526from typing import IO , Any , Dict , List , Optional , Sequence , Tuple , Union
2627
2728import yaml
@@ -102,9 +103,16 @@ class Manifest:
102103
103104 CURRENT_VERSION = "0.0"
104105
105- def __init__ (self , manifest : ManifestDict ) -> None :
106+ def __init__ (
107+ self ,
108+ manifest : ManifestDict ,
109+ text : Optional [str ] = None ,
110+ path : Optional [Union [str , os .PathLike [str ]]] = None ,
111+ ) -> None :
106112 """Create the manifest."""
107113 self .__version : str = str (manifest .get ("version" , self .CURRENT_VERSION ))
114+ self .__text : str = str (text )
115+ self .__path : str = str (path )
108116
109117 self ._remotes , default_remotes = self ._determine_remotes (
110118 manifest .get ("remotes" , [])
@@ -180,7 +188,10 @@ def _determine_remotes(
180188 return (remotes , default_remotes )
181189
182190 @staticmethod
183- def from_yaml (text : Union [io .TextIOWrapper , str , IO [str ]]) -> "Manifest" :
191+ def from_yaml (
192+ text : Union [io .TextIOWrapper , str , IO [str ]],
193+ path : Optional [Union [str , os .PathLike [str ]]] = None ,
194+ ) -> "Manifest" :
184195 """Create a manifest from a file like object."""
185196 loaded_yaml = Manifest ._load_yaml (text )
186197
@@ -192,7 +203,11 @@ def from_yaml(text: Union[io.TextIOWrapper, str, IO[str]]) -> "Manifest":
192203 if not manifest :
193204 raise RuntimeError ("Missing manifest root element!" )
194205
195- return Manifest (manifest )
206+ if isinstance (text , (io .TextIOWrapper , IO )):
207+ text .seek (0 )
208+ text = text .read ()
209+
210+ return Manifest (manifest , text = text , path = path )
196211
197212 @staticmethod
198213 def _load_yaml (text : Union [io .TextIOWrapper , str , IO [str ]]) -> Any :
@@ -217,7 +232,12 @@ def from_file(path: str) -> "Manifest":
217232 FileNotFoundError: Given path was not a file.
218233 """
219234 with open (path , "r" , encoding = "utf-8" ) as opened_file :
220- return Manifest .from_yaml (opened_file )
235+ return Manifest .from_yaml (opened_file , path )
236+
237+ @property
238+ def path (self ) -> str :
239+ """Path to the manifest file."""
240+ return self .__path
221241
222242 @property
223243 def version (self ) -> str :
@@ -293,6 +313,25 @@ def dump(self, path: str) -> None:
293313 self ._as_dict (), manifest_file , Dumper = ManifestDumper , sort_keys = False
294314 )
295315
316+ def find_name_in_manifest (self , name : str ) -> Tuple [int , int , int ]:
317+ """Find the location of a project name in the manifest."""
318+ if not self .__text :
319+ raise FileNotFoundError ("No manifest text available" )
320+
321+ for line_nr , line in enumerate (self .__text .splitlines (), start = 1 ):
322+ match = re .search (rf"^\s+-\s*name:\s*(?P<name>{ name } )\s*$" , line )
323+
324+ if match :
325+ return (
326+ line_nr ,
327+ int (match .start ("name" )) + 1 ,
328+ int (match .end ("name" )),
329+ )
330+ raise RuntimeError (
331+ "An entry from the manifest was provided,"
332+ " that doesn't exist in the manifest!"
333+ )
334+
296335
297336def find_manifest () -> str :
298337 """Find a manifest."""
@@ -308,25 +347,22 @@ def find_manifest() -> str:
308347 return os .path .realpath (paths [0 ])
309348
310349
311- def get_manifest () -> Tuple [ Manifest , str ] :
350+ def get_manifest () -> Manifest :
312351 """Get manifest and its path."""
313352 logger .debug ("Looking for manifest" )
314353 manifest_path = find_manifest ()
315354 validate (manifest_path )
316355
317356 logger .debug (f"Using manifest { manifest_path } " )
318- return (
319- Manifest .from_file (manifest_path ),
320- manifest_path ,
321- )
357+ return Manifest .from_file (manifest_path )
322358
323359
324- def get_childmanifests (skip : Optional [List [str ]] = None ) -> List [Tuple [ Manifest , str ] ]:
360+ def get_childmanifests (skip : Optional [List [str ]] = None ) -> List [Manifest ]:
325361 """Get manifest and its path."""
326362 skip = skip or []
327363 logger .debug ("Looking for sub-manifests" )
328364
329- childmanifests : List [Tuple [ Manifest , str ] ] = []
365+ childmanifests : List [Manifest ] = []
330366 for path in find_file (DEFAULT_MANIFEST_NAME , "." ):
331367 path = os .path .realpath (path )
332368 if path not in skip :
@@ -335,8 +371,7 @@ def get_childmanifests(skip: Optional[List[str]] = None) -> List[Tuple[Manifest,
335371 pathlib .Path (path ).relative_to (os .path .dirname (os .getcwd ())).as_posix ()
336372 ):
337373 validate (path )
338- childmanifest = Manifest .from_file (path )
339- childmanifests += [(childmanifest , path )]
374+ childmanifests += [Manifest .from_file (path )]
340375
341376 return childmanifests
342377
0 commit comments