Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -391,7 +391,7 @@ jobs:
- throw_exception
- uuid

args: [ '' ]
args: [ '', '-C' ]

runs-on: ubuntu-latest

Expand Down
87 changes: 67 additions & 20 deletions depinst/depinst.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ def module_for_header( h, x, gm ):
return None


def scan_header_dependencies( f, x, gm, deps ):
def scan_header_dependencies( f, x, gm, deps, dep_path ):

for line in f:

Expand All @@ -89,8 +89,13 @@ def scan_header_dependencies( f, x, gm, deps ):
vprint( 1, 'Adding dependency', mod )
deps[ mod ] = 0

elif len(dep_path) > 1 and mod == dep_path[0]:

def scan_directory( d, x, gm, deps ):
dep_path = dep_path + [ mod ]
raise DependencyCycle( 'Dependency cycle detected: ' + ' -> '.join(dep_path) )


def scan_directory( d, x, gm, deps, dep_path ):

vprint( 1, 'Scanning directory', d )

Expand All @@ -108,20 +113,20 @@ def scan_directory( d, x, gm, deps ):
if sys.version_info[0] < 3:

with open( fn, 'r' ) as f:
scan_header_dependencies( f, x, gm, deps )
scan_header_dependencies( f, x, gm, deps, dep_path )

else:

with open( fn, 'r', encoding='latin-1' ) as f:
scan_header_dependencies( f, x, gm, deps )
scan_header_dependencies( f, x, gm, deps, dep_path )


def scan_module_dependencies( m, x, gm, deps, dirs ):
def scan_module_dependencies( m, x, gm, deps, dirs, dep_path ):

vprint( 1, 'Scanning module', m )

for dir in dirs:
scan_directory( os.path.join( 'libs', m, dir ), x, gm, deps )
scan_directory( os.path.join( 'libs', m, dir ), x, gm, deps, dep_path )


def read_exceptions():
Expand Down Expand Up @@ -197,7 +202,7 @@ def install_modules( modules, git_args ):
raise Exception( "The command '%s' failed with exit code %d" % (command, r) )


def install_module_dependencies( deps, x, gm, git_args ):
def install_module_dependencies( deps, x, gm, git_args, dep_path ):

modules = []

Expand All @@ -214,11 +219,20 @@ def install_module_dependencies( deps, x, gm, git_args ):
install_modules( modules, git_args )

for m in modules:
scan_module_dependencies( m, x, gm, deps, [ 'include', 'src' ] )
next_dep_path = dep_path

if dep_path:
next_dep_path = dep_path + [m]

scan_module_dependencies( m, x, gm, deps, [ 'include', 'src' ], next_dep_path )

return len( modules )


class DependencyCycle(Exception):
pass


if( __name__ == "__main__" ):

parser = argparse.ArgumentParser( description='Installs the dependencies needed to test a Boost library.' )
Expand All @@ -230,6 +244,7 @@ def install_module_dependencies( deps, x, gm, git_args ):
parser.add_argument( '-I', '--include', help="additional subdirectory to scan; can be repeated", metavar='DIR', action='append', default=[] )
parser.add_argument( '-g', '--git_args', help="additional arguments to `git submodule update`", default='', action='store' )
parser.add_argument( '-u', '--update', help='update <library> before scanning', action='store_true' )
parser.add_argument( '-C', '--reject-cycles', help='abort if <library> has cyclical dependencies', action='store_true' )
parser.add_argument( 'library', help="name of library to scan ('libs/' will be prepended)" )

args = parser.parse_args()
Expand All @@ -239,6 +254,7 @@ def install_module_dependencies( deps, x, gm, git_args ):
vprint( 2, '-X:', args.exclude )
vprint( 2, '-I:', args.include )
vprint( 2, '-N:', args.ignore )
vprint( 2, '-C:', args.reject_cycles )

x = read_exceptions()
vprint( 2, 'Exceptions:', x )
Expand All @@ -257,26 +273,57 @@ def install_module_dependencies( deps, x, gm, git_args ):

m = args.library

deps = { m : 1 }

dirs = [ 'include', 'src', 'test' ]
main_dirs = [ 'include', 'src' ]
extra_dirs = [ 'test' ]

for dir in args.exclude:
dirs.remove( dir )
if dir in main_dirs:
main_dirs.remove( dir )

if dir in extra_dirs:
extra_dirs.remove( dir )

for dir in args.include:
dirs.append( dir )
extra_dirs.append( dir )

vprint( 1, 'Directories to scan:', *dirs )
vprint( 1, 'Directories to scan:', *(main_dirs + extra_dirs) )

scan_module_dependencies( m, x, gm, deps, dirs )
dep_path = []
if args.reject_cycles:
dep_path.append( m )

main_deps = { m : 1 }
scan_module_dependencies( m, x, gm, main_deps, main_dirs, dep_path )

extra_deps = { m : 1 }
scan_module_dependencies( m, x, gm, extra_deps, extra_dirs, [] )

for dep in args.ignore:
if dep in deps:
reported = False

if dep in main_deps:
vprint( 1, 'Ignoring dependency', dep )
del deps[dep]
reported = True
del main_deps[dep]

if dep in extra_deps:
if not reported:
vprint( 1, 'Ignoring dependency', dep )
reported = True
del extra_deps[dep]

all_deps = dict( **main_deps )
all_deps.update( extra_deps )
vprint( 2, 'Dependencies:', all_deps )

try:

while install_module_dependencies( main_deps, x, gm, args.git_args, dep_path ):
pass

vprint( 2, 'Dependencies:', deps )
while install_module_dependencies( extra_deps, x, gm, args.git_args, [] ):
pass

while install_module_dependencies( deps, x, gm, args.git_args ):
pass
except DependencyCycle as e:
print( e, file=sys.stderr )
sys.exit(1)
Loading