157 lines
3.3 KiB
Python
157 lines
3.3 KiB
Python
|
|
import os
|
||
|
|
|
||
|
|
|
||
|
|
class DependencyResolutionError(Exception):
|
||
|
|
pass
|
||
|
|
|
||
|
|
|
||
|
|
class DependencyItem:
|
||
|
|
def __init__(self):
|
||
|
|
self.__target = None
|
||
|
|
self.__dep_list = None
|
||
|
|
|
||
|
|
|
||
|
|
def name(self):
|
||
|
|
return None
|
||
|
|
|
||
|
|
|
||
|
|
def target(self):
|
||
|
|
return self.__target
|
||
|
|
|
||
|
|
|
||
|
|
def dependencies(self):
|
||
|
|
return None
|
||
|
|
|
||
|
|
|
||
|
|
def dependency_list(self):
|
||
|
|
return self.__dep_list
|
||
|
|
|
||
|
|
|
||
|
|
def publish(self):
|
||
|
|
return None
|
||
|
|
|
||
|
|
|
||
|
|
def reset_resolution(self):
|
||
|
|
self.__dep_list = None
|
||
|
|
|
||
|
|
|
||
|
|
def resolve(self, **kwargs):
|
||
|
|
if self.__dep_list is not None:
|
||
|
|
return self.__dep_list
|
||
|
|
|
||
|
|
ctx = None
|
||
|
|
dep_list = None
|
||
|
|
if 'ctx' in kwargs:
|
||
|
|
ctx = kwargs['ctx']
|
||
|
|
else:
|
||
|
|
ctx = {}
|
||
|
|
|
||
|
|
if 'dep_list' in kwargs:
|
||
|
|
dep_list = kwargs['dep_list']
|
||
|
|
else:
|
||
|
|
dep_list = []
|
||
|
|
|
||
|
|
if self.name() in ctx:
|
||
|
|
return
|
||
|
|
|
||
|
|
ctx[self.name()] = self
|
||
|
|
|
||
|
|
deps = self.dependencies()
|
||
|
|
if deps is None:
|
||
|
|
return
|
||
|
|
|
||
|
|
for d in deps.values():
|
||
|
|
d_value = d.resolve_self()
|
||
|
|
if d_value is not None:
|
||
|
|
d_value.resolve(ctx=ctx, dep_list=dep_list)
|
||
|
|
|
||
|
|
dep_list.append(self)
|
||
|
|
return dep_list
|
||
|
|
|
||
|
|
|
||
|
|
class Dependency:
|
||
|
|
def __init__(self, parent):
|
||
|
|
self.__parent = parent
|
||
|
|
|
||
|
|
|
||
|
|
def name(self, parent):
|
||
|
|
return None
|
||
|
|
|
||
|
|
|
||
|
|
def parent_name(self):
|
||
|
|
return self.__parent
|
||
|
|
|
||
|
|
|
||
|
|
def resolve_self(self):
|
||
|
|
return None
|
||
|
|
|
||
|
|
|
||
|
|
def is_resolved(self):
|
||
|
|
return False
|
||
|
|
|
||
|
|
|
||
|
|
class SeedDependency(Dependency):
|
||
|
|
def __init__(self, **kwargs):
|
||
|
|
self.__target_seed = None
|
||
|
|
if 'name' in kwargs:
|
||
|
|
self.__name = kwargs['name']
|
||
|
|
if 'parent' in kwargs:
|
||
|
|
super().__init__(kwargs['parent'])
|
||
|
|
|
||
|
|
|
||
|
|
def name(self):
|
||
|
|
return self.__name
|
||
|
|
|
||
|
|
|
||
|
|
def target(self):
|
||
|
|
return self.__target_seed
|
||
|
|
|
||
|
|
|
||
|
|
def resolve_self(self):
|
||
|
|
from seed import Seed
|
||
|
|
if self.__target_seed is not None:
|
||
|
|
return self.__target_seed
|
||
|
|
|
||
|
|
target = Seed.get(self.__name)
|
||
|
|
if target is None:
|
||
|
|
raise DependencyResolutionError(
|
||
|
|
'{} depends on seed "{}", but the required seed cannot be found'.format(self.parent_name(), self.__name))
|
||
|
|
|
||
|
|
self.__target_seed = target
|
||
|
|
return self.__target_seed
|
||
|
|
|
||
|
|
|
||
|
|
def is_resolved(self):
|
||
|
|
return self.__target_seed is not None
|
||
|
|
|
||
|
|
|
||
|
|
class ProgramDependency(Dependency):
|
||
|
|
def __init__(self, **kwargs):
|
||
|
|
if 'name' in kwargs:
|
||
|
|
self.__name = kwargs['name']
|
||
|
|
if 'parent' in kwargs:
|
||
|
|
super().__init__(kwargs['parent'])
|
||
|
|
|
||
|
|
|
||
|
|
def __is_exe(self, fpath):
|
||
|
|
return os.path.isfile(fpath) and os.access(fpath, os.X_OK)
|
||
|
|
|
||
|
|
|
||
|
|
def name(self):
|
||
|
|
return self.__name
|
||
|
|
|
||
|
|
|
||
|
|
def resolve_self(self):
|
||
|
|
if self.__is_exe(self.__name):
|
||
|
|
return None
|
||
|
|
|
||
|
|
path_string = os.environ['PATH']
|
||
|
|
path_list = path_string.split(':')
|
||
|
|
for d in path_list:
|
||
|
|
exe_path = os.path.join(d, self.__name)
|
||
|
|
if self.__is_exe(exe_path):
|
||
|
|
return None
|
||
|
|
|
||
|
|
raise DependencyResolutionError(f'{self.parent_name()} depends on command `{self.__name}`, but the command cannot be found. Make sure that the named command exists, the containing directory is in $PATH if necessary, and the executable file has the correct permissions.')
|
||
|
|
|