| 
									
										
										
										
											2020-09-29 22:30:48 -06:00
										 |  |  | #!/usr/bin/env python3 | 
					
						
							| 
									
										
										
										
											2019-05-30 11:53:41 -07:00
										 |  |  | # | 
					
						
							|  |  |  | # This script figures the order in which workspace crates must be published to | 
					
						
							|  |  |  | # crates.io.  Along the way it also ensures there are no circular dependencies | 
					
						
							|  |  |  | # that would cause a |cargo publish| to fail. | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | # On success an ordered list of Cargo.toml files is written to stdout | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import os | 
					
						
							|  |  |  | import json | 
					
						
							|  |  |  | import subprocess | 
					
						
							|  |  |  | import sys; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def load_metadata(): | 
					
						
							|  |  |  |     return json.loads(subprocess.Popen( | 
					
						
							|  |  |  |         'cargo metadata --no-deps --format-version=1', | 
					
						
							|  |  |  |         shell=True, stdout=subprocess.PIPE).communicate()[0]) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def get_packages(): | 
					
						
							|  |  |  |     metadata = load_metadata() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     manifest_path = dict() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # Build dictionary of packages and their immediate solana-only dependencies | 
					
						
							|  |  |  |     dependency_graph = dict() | 
					
						
							|  |  |  |     for pkg in metadata['packages']: | 
					
						
							|  |  |  |         manifest_path[pkg['name']] = pkg['manifest_path']; | 
					
						
							| 
									
										
										
										
											2019-05-30 13:44:27 -07:00
										 |  |  |         dependency_graph[pkg['name']] = [x['name'] for x in pkg['dependencies'] if x['name'].startswith('solana')]; | 
					
						
							| 
									
										
										
										
											2019-05-30 11:53:41 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |     # Check for direct circular dependencies | 
					
						
							|  |  |  |     circular_dependencies = set() | 
					
						
							|  |  |  |     for package, dependencies in dependency_graph.items(): | 
					
						
							|  |  |  |         for dependency in dependencies: | 
					
						
							|  |  |  |             if dependency in dependency_graph and package in dependency_graph[dependency]: | 
					
						
							|  |  |  |                 circular_dependencies.add(' <--> '.join(sorted([package, dependency]))) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     for dependency in circular_dependencies: | 
					
						
							|  |  |  |         sys.stderr.write('Error: Circular dependency: {}\n'.format(dependency)) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if len(circular_dependencies) != 0: | 
					
						
							|  |  |  |         sys.exit(1) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # Order dependencies | 
					
						
							|  |  |  |     sorted_dependency_graph = [] | 
					
						
							|  |  |  |     max_iterations = pow(len(dependency_graph),2) | 
					
						
							| 
									
										
										
										
											2020-10-12 15:06:14 -06:00
										 |  |  |     while dependency_graph: | 
					
						
							|  |  |  |         deleted_packages = [] | 
					
						
							| 
									
										
										
										
											2019-05-30 11:53:41 -07:00
										 |  |  |         if max_iterations == 0: | 
					
						
							| 
									
										
										
										
											2019-10-21 22:25:06 -07:00
										 |  |  |             # One day be more helpful and find the actual cycle for the user... | 
					
						
							| 
									
										
										
										
											2019-12-04 11:03:24 -08:00
										 |  |  |             sys.exit('Error: Circular dependency suspected between these packages: \n {}\n'.format('\n '.join(dependency_graph.keys()))) | 
					
						
							| 
									
										
										
										
											2019-05-30 11:53:41 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |         max_iterations -= 1 | 
					
						
							| 
									
										
										
										
											2020-09-29 22:30:48 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-05-30 11:53:41 -07:00
										 |  |  |         for package, dependencies in dependency_graph.items(): | 
					
						
							| 
									
										
										
										
											2020-10-12 15:06:14 -06:00
										 |  |  |             if package in deleted_packages: | 
					
						
							|  |  |  |                 continue | 
					
						
							| 
									
										
										
										
											2019-05-30 11:53:41 -07:00
										 |  |  |             for dependency in dependencies: | 
					
						
							|  |  |  |                 if dependency in dependency_graph: | 
					
						
							|  |  |  |                     break | 
					
						
							|  |  |  |             else: | 
					
						
							| 
									
										
										
										
											2020-10-12 15:06:14 -06:00
										 |  |  |                 deleted_packages.append(package) | 
					
						
							| 
									
										
										
										
											2019-05-30 11:53:41 -07:00
										 |  |  |                 sorted_dependency_graph.append((package, manifest_path[package])) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-12 15:06:14 -06:00
										 |  |  |         dependency_graph = {p: d for p, d in dependency_graph.items() if not p in deleted_packages } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-05-30 11:53:41 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |     return sorted_dependency_graph | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | for package, manifest in get_packages(): | 
					
						
							| 
									
										
										
										
											2020-09-29 22:30:48 -06:00
										 |  |  |     print(os.path.relpath(manifest)) |