Send patches - preferably formatted by git format-patch - to patches at archlinux32 dot org.
summaryrefslogtreecommitdiff
path: root/archinstall
diff options
context:
space:
mode:
Diffstat (limited to 'archinstall')
-rw-r--r--archinstall/__main__.py6
-rw-r--r--archinstall/lib/profiles.py157
-rw-r--r--archinstall/lib/storage.py2
3 files changed, 76 insertions, 89 deletions
diff --git a/archinstall/__main__.py b/archinstall/__main__.py
index dcf61f58..63c2f715 100644
--- a/archinstall/__main__.py
+++ b/archinstall/__main__.py
@@ -12,6 +12,9 @@ def run_as_a_module():
This function and the file __main__ acts as a entry point.
"""
+ # Add another path for finding profiles, so that list_profiles() in Script() can find guided.py, unattended.py etc.
+ archinstall.storage['PROFILE_PATH'].append(os.path.abspath(f'{os.path.dirname(__file__)}/examples'))
+
if len(sys.argv) == 1:
sys.argv.append('guided')
@@ -22,6 +25,9 @@ def run_as_a_module():
sys.exit(1)
os.chdir(os.path.abspath(os.path.dirname(__file__)))
+
+ # Remove the example directory from the PROFILE_PATH, to avoid guided.py etc shows up in user input questions.
+ archinstall.storage['PROFILE_PATH'].pop()
script.execute()
if __name__ == '__main__':
diff --git a/archinstall/lib/profiles.py b/archinstall/lib/profiles.py
index e83e8346..f9aa206c 100644
--- a/archinstall/lib/profiles.py
+++ b/archinstall/lib/profiles.py
@@ -15,7 +15,7 @@ def grab_url_data(path):
response = urllib.request.urlopen(safe_path, context=ssl_context)
return response.read()
-def list_profiles(filter_irrelevant_macs=True):
+def list_profiles(filter_irrelevant_macs=True, subpath=''):
# TODO: Grab from github page as well, not just local static files
if filter_irrelevant_macs:
local_macs = list_interfaces()
@@ -23,7 +23,7 @@ def list_profiles(filter_irrelevant_macs=True):
cache = {}
# Grab all local profiles found in PROFILE_PATH
for PATH_ITEM in storage['PROFILE_PATH']:
- for root, folders, files in os.walk(os.path.abspath(os.path.expanduser(PATH_ITEM))):
+ for root, folders, files in os.walk(os.path.abspath(os.path.expanduser(PATH_ITEM+subpath))):
for file in files:
if os.path.splitext(file)[1] == '.py':
tailored = False
@@ -43,7 +43,7 @@ def list_profiles(filter_irrelevant_macs=True):
# Grab profiles from upstream URL
if storage['PROFILE_DB']:
- profiles_url = os.path.join(storage["UPSTREAM_URL"], storage['PROFILE_DB'])
+ profiles_url = os.path.join(storage["UPSTREAM_URL"]+subpath, storage['PROFILE_DB'])
try:
profile_list = json.loads(grab_url_data(profiles_url))
except urllib.error.HTTPError as err:
@@ -61,33 +61,31 @@ def list_profiles(filter_irrelevant_macs=True):
continue
tailored = True
- cache[profile[:-3]] = {'path' : os.path.join(storage["UPSTREAM_URL"], profile), 'description' : profile_list[profile], 'tailored' : tailored}
+ cache[profile[:-3]] = {'path' : os.path.join(storage["UPSTREAM_URL"]+subpath, profile), 'description' : profile_list[profile], 'tailored' : tailored}
return cache
-class Imported():
- def __init__(self, spec, imported):
- self.spec = spec
- self.imported = imported
+class Script():
+ def __init__(self, profile, installer=None):
+ # profile: https://hvornum.se/something.py
+ # profile: desktop
+ # profile: /path/to/profile.py
+ self.profile = profile
+ self.installer = installer
+ self.converted_path = None
+ self.spec = None
+ self.examples = None
+ self.namespace = os.path.splitext(os.path.basename(self.path))[0]
def __enter__(self, *args, **kwargs):
- self.spec.loader.exec_module(self.imported)
- return self.imported
+ self.execute()
+ return sys.modules[self.namespace]
def __exit__(self, *args, **kwargs):
# TODO: https://stackoverflow.com/questions/28157929/how-to-safely-handle-an-exception-inside-a-context-manager
if len(args) >= 2 and args[1]:
raise args[1]
-
-class Script():
- def __init__(self, profile):
- # profile: https://hvornum.se/something.py
- # profile: desktop
- # profile: /path/to/profile.py
- self.profile = profile
- self.converted_path = None
-
def localize_path(self, profile_path):
if (url := urllib.parse.urlparse(profile_path)).scheme and url.scheme in ('https', 'http'):
if not self.converted_path:
@@ -107,101 +105,84 @@ class Script():
# The Profile was not a direct match on a remote URL
if not parsed_url.scheme:
# Try to locate all local or known URL's
- examples = list_profiles()
+ if not self.examples:
+ self.examples = list_profiles()
- if f"{self.profile}" in examples:
- return self.localize_path(examples[self.profile]['path'])
+ if f"{self.profile}" in self.examples:
+ return self.localize_path(self.examples[self.profile]['path'])
# TODO: Redundant, the below block shouldnt be needed as profiles are stripped of their .py, but just in case for now:
- elif f"{self.profile}.py" in examples:
- return self.localize_path(examples[f"{self.profile}.py"]['path'])
+ elif f"{self.profile}.py" in self.examples:
+ return self.localize_path(self.examples[f"{self.profile}.py"]['path'])
# Path was not found in any known examples, check if it's an abolute path
if os.path.isfile(self.profile):
- return os.path.basename(self.profile)
+ return self.profile
- raise ProfileNotFound(f"File {self.profile} does not exist in {examples}")
+ raise ProfileNotFound(f"File {self.profile} does not exist in {storage['PROFILE_PATH']}")
elif parsed_url.scheme in ('https', 'http'):
return self.localize_path(self.profile)
else:
raise ProfileNotFound(f"Cannot handle scheme {parsed_url.scheme}")
+ def load_instructions(self, namespace=None):
+ if namespace:
+ self.namespace = namespace
+
+ self.spec = importlib.util.spec_from_file_location(self.namespace, self.path)
+ imported = importlib.util.module_from_spec(self.spec)
+ sys.modules[self.namespace] = imported
+
+ return self
+
def execute(self):
- spec = importlib.util.spec_from_file_location(
- "tempscript",
- self.path
- )
- imported_path = importlib.util.module_from_spec(spec)
- spec.loader.exec_module(imported_path)
- sys.modules["tempscript"] = imported_path
-
-class Profile():
+ if not self.namespace in sys.modules or self.spec is None:
+ self.load_instructions()
+
+ __builtins__['installation'] = self.installer # TODO: Replace this with a import archinstall.session instead
+ self.spec.loader.exec_module(sys.modules[self.namespace])
+
+ return sys.modules[self.namespace]
+
+class Profile(Script):
def __init__(self, installer, path, args={}):
- self._path = Script(path)
- self.installer = installer
+ super(Profile, self).__init__(path, installer)
self._cache = None
- self.args = args
def __dump__(self, *args, **kwargs):
return {'path' : self.path}
def __repr__(self, *args, **kwargs):
- return f'Profile({self.path})'
-
- @property
- def path(self, *args, **kwargs):
- return self._path.path
-
- def load_instructions(self, namespace=None):
- if (absolute_path := self.path):
- if os.path.splitext(absolute_path)[1] == '.py':
- if not namespace:
- namespace = os.path.splitext(os.path.basename(absolute_path))[0]
- spec = importlib.util.spec_from_file_location(namespace, absolute_path)
- imported = importlib.util.module_from_spec(spec)
- sys.modules[namespace] = imported
- return Imported(spec, imported)
- else:
- raise ProfileError(f'Extension {os.path.splitext(absolute_path)[1]} is not a supported profile model. Only .py is supported.')
-
- raise ProfileError(f'No such profile ({self.path}) was found either locally or in {storage["UPSTREAM_URL"]}')
+ return f'Profile({os.path.basename(self.profile)})'
def install(self):
- # To avoid profiles importing the wrong 'archinstall',
- # we need to ensure that this current archinstall is in sys.path
- archinstall_path = os.path.abspath(f'{os.path.dirname(__file__)}/../../')
- if archinstall_path not in sys.path:
- sys.path.insert(0, archinstall_path)
-
- instructions = self.load_instructions()
- if type(instructions) == Imported:
- # There's no easy way to give the imported profile the installer instance unless we require the profile-programmer to create a certain function that must be the same for all..
- # Which is a bit inconvenient so we'll make a a truly global installer for now, in the future archinstall main __init__.py should setup the 'installation' variable..
- # but to avoid circular imports and other traps, this works for now.
- # TODO: Remove
- __builtins__['installation'] = self.installer
- with instructions as runtime:
- log(f'{self} finished successfully.', bg='black', fg='green', level=LOG_LEVELS.Info, file=storage.get('logfile', None))
-
- return True
+ return self.execute()
class Application(Profile):
def __repr__(self, *args, **kwargs):
- return f'Application({self._path} <"{self.path}">)'
+ return f'Application({os.path.basename(self.profile)})'
@property
- def path(self, *args, **kwargs):
- if os.path.isfile(f'{self._path}'):
- return os.path.abspath(f'{self._path}')
+ def path(self):
+ parsed_url = urllib.parse.urlparse(self.profile)
- for path in ['./applications', './profiles/applications', '/etc/archinstall/applications', '/etc/archinstall/profiles/applications', os.path.abspath(f'{os.path.dirname(__file__)}/../profiles/applications')]:
- if os.path.isfile(f'{path}/{self._path}.py'):
- return os.path.abspath(f'{path}/{self._path}.py')
+ # The Profile was not a direct match on a remote URL
+ if not parsed_url.scheme:
+ # Try to locate all local or known URL's
+ if not self.examples:
+ self.examples = list_profiles(subpath='/applications')
- try:
- if (cache := grab_url_data(f'{storage["UPSTREAM_URL"]}/applications/{self._path}.py')):
- self._cache = cache
- return f'{storage["UPSTREAM_URL"]}/applications/{self._path}.py'
- except urllib.error.HTTPError:
- pass
+ if f"{self.profile}" in self.examples:
+ return self.localize_path(self.examples[self.profile]['path'])
+ # TODO: Redundant, the below block shouldnt be needed as profiles are stripped of their .py, but just in case for now:
+ elif f"{self.profile}.py" in self.examples:
+ return self.localize_path(self.examples[f"{self.profile}.py"]['path'])
+
+ # Path was not found in any known examples, check if it's an abolute path
+ if os.path.isfile(self.profile):
+ return os.path.basename(self.profile)
- return None \ No newline at end of file
+ raise ProfileNotFound(f"Application file {self.profile} does not exist in {storage['PROFILE_PATH']}")
+ elif parsed_url.scheme in ('https', 'http'):
+ return self.localize_path(self.profile)
+ else:
+ raise ProfileNotFound(f"Application cannot handle scheme {parsed_url.scheme}") \ No newline at end of file
diff --git a/archinstall/lib/storage.py b/archinstall/lib/storage.py
index 7c2c2661..3af15153 100644
--- a/archinstall/lib/storage.py
+++ b/archinstall/lib/storage.py
@@ -12,7 +12,7 @@ storage = {
'./profiles',
'~/.config/archinstall/profiles',
os.path.join(os.path.dirname(os.path.abspath(__file__)), 'profiles'),
- os.path.abspath(f'{os.path.dirname(__file__)}/../examples')
+ #os.path.abspath(f'{os.path.dirname(__file__)}/../examples')
],
'UPSTREAM_URL' : 'https://raw.githubusercontent.com/Torxed/archinstall/master/profiles',
'PROFILE_DB' : None # Used in cases when listing profiles is desired, not mandatory for direct profile grabing.