Advertisement
Guest User

Python Pip Module dependency resolver

a guest
May 11th, 2023
161
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Perl 2.93 KB | Source Code | 0 0
  1. #!/usr/bin/env perl
  2. use strict;
  3. use warnings;
  4.  
  5. # This script is a (probably naive) attempt at writing a recursive dependency resolver for the Python package index (PyPi)
  6. # A list of (space seperated) Python Package names provided on the command line are the starting point
  7. # Each package in that list is added to a graph, then every node(vertex) in that graph has edges defined between the node itself
  8. # and each of it's dependencies (which become their own nodes as a result)
  9. # Every node in the graph is iterated through, has it's dependencies(edges) defined, and the process is repeated until
  10. # the graph stops changing. Once there are no more dependencies to find, it prints out a (alphabetically sorted) list
  11. # of every package that would be required to install every package given as an argument to this script. Note that this list
  12. # WILL INCLUDE the packages that were initially provided as part of the list.
  13.  
  14. use JSON;
  15. use Graph;
  16.  
  17. # Our main dependency graph objects
  18. # We need two so we can check if the graph changed between dependency runs
  19. # When the two graphs stay the same after a dependency run, we know our graph is complete
  20. my $Agraph = Graph->new();
  21. my $Bgraph = Graph->new();
  22.  
  23. # Accepts a list of python packages to check dependencies for
  24. # Returns a list of python packages the arguments depend upon
  25. # Note that this function is NOT RECURSIVE. It ONLY provides the direct dependencies.
  26. sub get_deps {
  27.     my $ret = [];
  28.     my $json = JSON->new;
  29.     foreach my $package ( @_ ) {
  30.         my $curl = `curl -s "https://pypi.org/pypi/$package/json"`;
  31.         my $reqs = $json->decode($curl)->{info}->{requires_dist};
  32.         if (defined($reqs)) {
  33.             foreach my $dep (@$reqs) {
  34.                 $dep =~ s/[^a-zA-Z0-9-].*$//;
  35.                 push(@$ret, $dep);
  36.             }
  37.         }
  38.     }
  39.     return $ret;
  40. }
  41.  
  42. # @ARGV is a list of packages we need to find all dependencies for and is the roots of our dependency graph
  43. foreach my $package (@ARGV) {
  44.     $Agraph->add_vertex($package);
  45. }
  46.  
  47. # A list of packages we have already gotten dependnecies for so we don't check twice
  48. my $checked = [];
  49.  
  50. # Loop until our graphs stop changing between dependency runs
  51. while ( $Agraph ne $Bgraph ) {
  52.     $Bgraph = $Agraph->deep_copy();
  53.  
  54.     # Check every single vertice in our graph
  55.     my @vertlist = $Agraph->vertices;
  56.     foreach my $package (@vertlist) {
  57.         # If we haven't checked this package before, get it added to the graph with all of it's dependencies
  58.         if (! grep( /^$package$/, @$checked )) {
  59.             my $deplist = get_deps($package);
  60.             foreach my $dep (@$deplist) {
  61.                 $Agraph->add_edge($package, $dep);
  62.             }
  63.             # Add this package to our list of already checked packages so we don't waste time
  64.             push(@$checked, $package);
  65.         }
  66.     }
  67. }
  68.  
  69. my @fulldeplist = sort $Agraph->vertices;
  70. foreach my $package (@fulldeplist) {
  71.     print "$package\n";
  72. }
  73.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement