1010import giturlparse
1111import requests
1212import rich
13+ from rich .align import Align
14+ from rich .columns import Columns
1315from rich .console import Console
1416from rich .markdown import Markdown
1517from rich .theme import Theme
@@ -113,7 +115,9 @@ def walk_path_nix_meta(nodes: dict, current_node_id: str, path: list[str]) -> st
113115
114116
115117# walk all the inputs recursively and collect only the ones pointing to runtimeverification repos
116- def parse_package_metadata (nodes : dict , current_node_id : str , root_level : bool = False ) -> Union [PackageMetadata , None ]:
118+ def parse_package_metadata (
119+ nodes : dict , current_node_id : str , root_level : bool = False , repo : str = ''
120+ ) -> Union [PackageMetadata , None ]:
117121 if not (
118122 'original' in nodes [current_node_id ]
119123 and 'owner' in nodes [current_node_id ]['original' ]
@@ -122,7 +126,6 @@ def parse_package_metadata(nodes: dict, current_node_id: str, root_level: bool =
122126 if not root_level :
123127 return None
124128 else :
125- repo = ''
126129 rev = ''
127130 org = 'runtimeverification'
128131 else :
@@ -161,7 +164,7 @@ def get_package_metadata(package: GithubPackage) -> PackageMetadata:
161164 meta = json .loads (result )
162165 root_id = meta ['locks' ]['root' ]
163166
164- res = parse_package_metadata (meta ['locks' ]['nodes' ], root_id , True )
167+ res = parse_package_metadata (meta ['locks' ]['nodes' ], root_id , True , package . repo )
165168 if not res :
166169 rich .print ('❗ [red]Could not parse package metadata!' )
167170 sys .exit (1 )
@@ -170,16 +173,38 @@ def get_package_metadata(package: GithubPackage) -> PackageMetadata:
170173
171174
172175# build a rich.Tree of inputs for the given package metadata
173- def package_metadata_tree (p : Union [PackageMetadata , Follows ], lbl : Union [str , None ] = None ) -> Tree :
176+ def package_metadata_tree (
177+ p : Union [PackageMetadata , Follows ], lbl : Union [str , None ] = None , show_status : bool = False
178+ ) -> Tree :
174179 if lbl is None :
175180 tree = Tree ('Inputs:' )
176181 else :
177182 rev = f' - github:{ p .org } /{ p .repo } ' if type (p ) == PackageMetadata else ''
178183 follows = (' - follows [green]' + '/' .join (p .follows )) if type (p ) == Follows else ''
179- tree = Tree (f'{ lbl } { rev } { follows } ' )
184+ status = ''
185+ if show_status and type (p ) == PackageMetadata :
186+ auth = {'Authorization' : f'Bearer { os .getenv ("GH_TOKEN" )} ' } if os .getenv ('GH_TOKEN' ) else {}
187+ commits = requests .get (f'https://api.github.com/repos/{ p .org } /{ p .repo } /commits' , headers = auth )
188+ if commits .ok :
189+ commits_list = [c ['sha' ] for c in commits .json ()]
190+ if p .rev in commits_list :
191+ idx = commits_list .index (p .rev )
192+ if idx == 0 :
193+ status = ' 🟢 up to date '
194+ elif idx == 1 :
195+ status = f' 🟠 { idx } version behind master '
196+ elif idx < 10 :
197+ status = f' 🟠 { idx } versions behind master '
198+ else :
199+ status = f' 🔴 { idx } versions behind master'
200+
201+ if status != '' :
202+ tree = Tree (Columns ([Align (f'{ lbl } { rev } { follows } ' ), Align (status , align = 'right' )], expand = True ))
203+ else :
204+ tree = Tree (f'{ lbl } { rev } { follows } ' )
180205 if type (p ) == PackageMetadata :
181206 for k in p .inputs .keys ():
182- tree .add (package_metadata_tree (p .inputs [k ], k ))
207+ tree .add (package_metadata_tree (p .inputs [k ], k , show_status ))
183208 return tree
184209
185210
@@ -275,7 +300,7 @@ def highlight_row(condition: bool, xs: List[str]) -> List[str]:
275300 return xs
276301
277302
278- def list_package (package_name : str , show_inputs : bool ) -> None :
303+ def list_package (package_name : str , show_inputs : bool , show_status : bool ) -> None :
279304 reload_packages ()
280305 if package_name != 'all' :
281306 if package_name not in packages .keys ():
@@ -286,11 +311,17 @@ def list_package(package_name: str, show_inputs: bool) -> None:
286311 return
287312 listed_package = packages [package_name ]
288313
289- if show_inputs :
314+ if show_inputs or show_status :
290315 inputs = get_package_metadata (listed_package )
291- rich .print (package_metadata_tree (inputs ))
316+ rich .print (package_metadata_tree (inputs , show_status = show_status ))
292317 else :
293- auth = {'Authorization' : f'Bearer { listed_package .access_token } ' } if listed_package .access_token else {}
318+ auth = (
319+ {'Authorization' : f'Bearer { listed_package .access_token } ' }
320+ if listed_package .access_token
321+ else {'Authorization' : f'Bearer { os .getenv ("GH_TOKEN" )} ' }
322+ if os .getenv ('GH_TOKEN' )
323+ else {}
324+ )
294325 tags = requests .get (
295326 f'https://api.github.com/repos/{ listed_package .org } /{ listed_package .repo } /tags' , headers = auth
296327 )
@@ -533,7 +564,13 @@ def ping_nix_store(url: str, access_token: Optional[str] = None) -> Tuple[bool,
533564
534565
535566def check_github_api_accessible (org : str , repo : str , access_token : Optional [str ]) -> bool :
536- auth = {'Authorization' : f'Bearer { access_token } ' } if access_token else {}
567+ auth = (
568+ {'Authorization' : f'Bearer { access_token } ' }
569+ if access_token
570+ else {'Authorization' : f'Bearer { os .getenv ("GH_TOKEN" )} ' }
571+ if os .getenv ('GH_TOKEN' )
572+ else {}
573+ )
537574 commits = requests .get (f'https://api.github.com/repos/{ org } /{ repo } /commits' , headers = auth )
538575 return commits .ok
539576
@@ -817,6 +854,11 @@ def main() -> None:
817854 list = subparser .add_parser ('list' , help = 'show the active and installed K semantics' , add_help = False )
818855 list .add_argument ('package' , nargs = '?' , default = 'all' , type = str )
819856 list .add_argument ('--inputs' , action = 'store_true' , help = 'show the input dependencies of the selected package' )
857+ list .add_argument (
858+ '--status' ,
859+ action = 'store_true' ,
860+ help = 'show the input dependencies of the selected package and how stale they are compared to the default branch' ,
861+ )
820862 list .add_argument ('-h' , '--help' , action = _HelpListAction )
821863
822864 install = subparser .add_parser (
@@ -879,7 +921,7 @@ def main() -> None:
879921 package_name = PackageName .parse (args .package )
880922
881923 if args .command == 'list' :
882- list_package (package_name .base , args .inputs )
924+ list_package (package_name .base , args .inputs , args . status )
883925
884926 elif args .command == 'install' :
885927 install_package (package_name , args .version , args .override , args .verbose , args .refresh )
0 commit comments