diff --git a/easybuild/easyblocks/a/abaqus.py b/easybuild/easyblocks/a/abaqus.py index b2fbf3cff58..92548382447 100644 --- a/easybuild/easyblocks/a/abaqus.py +++ b/easybuild/easyblocks/a/abaqus.py @@ -34,7 +34,6 @@ """ import glob import os -from collections import OrderedDict from easybuild.easyblocks.generic.binary import Binary from easybuild.framework.easyblock import EasyBlock @@ -44,7 +43,7 @@ from easybuild.tools.environment import setvar from easybuild.tools.filetools import change_dir, symlink, write_file from easybuild.tools.modules import get_software_root -from easybuild.tools.run import run_cmd_qa +from easybuild.tools.run import run_shell_cmd from easybuild.tools.systemtools import get_os_name @@ -107,14 +106,14 @@ def install_step(self): """Install ABAQUS using 'setup'.""" if LooseVersion(self.version) >= LooseVersion('2016'): change_dir(os.path.join(self.cfg['start_dir'], '1')) - qa = { - "Enter selection (default: Install):": '', - "Enter selection (default: Close):": '', - } + qa = [ + (r"Enter selection \(default: Install\):", ''), + (r"Enter selection \(default: Close\):", ''), + ] no_qa = [ - '___', + r"___", r"\(\d+\s*[KM]B\)", - r'\.\.\.$', + r"\.\.\.$", ] # Match string for continuing on with the selected items @@ -123,95 +122,93 @@ def install_step(self): # Allow for selection or deselection of components from lines of the form: # 5 [*] Tosca Fluid # This uses nextstr to make sure we only match the latest output in the Q&A process; - # negative lookahead (?!___) is used to exclude ___...___ lines, to avoid matching across questions - selectionstr = r"\s*(?P[-0-9]+) %%s %%s[ \w]*\n((?!%s)(?!___)[\S ]*\n)*%s$" % (nextstr, nextstr) - - # ensure question patterns are considered in order by using an OrderedDict instance, - # rather than a regular dictionary (where there's no guarantee on key order in general) - std_qa = OrderedDict() + # negative lookahead (?!___) is used to exclude ___...___ lines, to avoid matching across questions; + # *? to use non-greedy matching in combination with negative lookahead + # (to avoid excessive backtracking by regex engine) + selectionstr = r"\s*(?P[-0-9]+) %%s %%s.*\n((?!%s)(?!___).*\n)*?%s" % (nextstr, nextstr) - # Disable Extended Product Documentation because it has a troublesome Java dependency - std_qa[selectionstr % (r"\[*\]", "Extended Product Documentation")] = "%(nr)s" installed_docs = False # hard disabled, previous support was actually incomplete - # enable all ABAQUS components - std_qa[selectionstr % (r"\[ \]", "Abaqus.*")] = "%(nr)s" - std_qa[selectionstr % (r"\[ \]", "Cosimulation Services")] = "%(nr)s" - - # enable 3DSFlow Solver (used to be called "Abaqus/CFD Solver") - std_qa[selectionstr % (r"\[ \]", "3DSFlow Solver")] = "%(nr)s" + qa.extend([ + # disable Extended Product Documentation because it has a troublesome Java dependency + (selectionstr % (r"\[*\]", "Extended Product Documentation"), '%(nr)s'), + # enable all ABAQUS components + (selectionstr % (r"\[ \]", "Abaqus"), '%(nr)s'), + (selectionstr % (r"\[ \]", "Cosimulation Services"), '%(nr)s'), + # enable 3DSFlow Solver (used to be called "Abaqus/CFD Solver") + (selectionstr % (r"\[ \]", "3DSFlow Solver"), '%(nr)s'), + ]) # disable/enable fe-safe components if self.cfg['with_fe_safe']: - std_qa[selectionstr % (r"\[ \]", ".*fe-safe")] = "%(nr)s" + qa.append((selectionstr % (r"\[ \]", ".*fe-safe"), '%(nr)s')) else: - std_qa[selectionstr % (r"\[*\]", ".*fe-safe")] = "%(nr)s" + qa.append((selectionstr % (r"\[\*\]", ".*fe-safe"), '%(nr)s')) # Disable/enable Tosca if self.cfg['with_tosca']: - std_qa[selectionstr % (r"\[\ \]", "Tosca.*")] = "%(nr)s" + qa.append((selectionstr % (r"\[ \]", "Tosca.*"), '%(nr)s')) else: - std_qa[selectionstr % (r"\[\*\]", "Tosca.*")] = "%(nr)s" - - # disable CloudView - std_qa[r"(?P[0-9]+) \[X\] Search using CloudView\nEnter selection:"] = '%(cloudview)s\n\n' - # accept default port for documentation server - std_qa[r"Check that the port is free.\nDefault \[[0-9]+\]:"] = '\n' - - # disable feedback by users - std_qa[r"(?P[0-9]+) \[X\] Allow users to send feedback.\nEnter selection:"] = '%(feedback)s\n\n' - - # disable reverse proxy - std_qa[r"(?P[0-9]+) \[X\] Use a reverse proxy.\nEnter selection:"] = '%(proxy)s\n\n' - - # Disable Isight - std_qa[selectionstr % (r"\[\*\]", "Isight")] = "%(nr)s" - # Disable Search using EXALEAD - std_qa[r"\s*(?P[0-9]+) \[X\] Search using EXALEAD\nEnter selection:"] = '%(exalead)s\n\n' + qa.append((selectionstr % (r"\[\*\]", "Tosca.*"), '%(nr)s')) + + qa.extend([ + # disable CloudView + (r"(?P[0-9]+) \[X\] Search using CloudView\nEnter selection:", '%(cloudview)s\n\n'), + # accept default port for documentation server + (r"Check that the port is free.\nDefault \[[0-9]+\]:", '\n'), + # disable feedback by users + (r"(?P[0-9]+) \[X\] Allow users to send feedback.\nEnter selection:", '%(feedback)s\n\n'), + # disable reverse proxy + (r"(?P[0-9]+) \[X\] Use a reverse proxy.\nEnter selection:", '%(proxy)s\n\n'), + # Disable Isight + (selectionstr % (r"\[\*\]", "Isight"), '%(nr)s'), + # Disable Search using EXALEAD + (r"\s*(?P[0-9]+) \[X\] Search using EXALEAD\nEnter selection:", '%(exalead)s\n\n'), + ]) # Directories cae_subdir = os.path.join(self.installdir, 'cae') sim_subdir = os.path.join(self.installdir, 'sim') - std_qa[r"Default.*SIMULIA/EstProducts.*:"] = cae_subdir - std_qa[r"SIMULIA[0-9]*doc.*:"] = os.path.join(self.installdir, 'doc') # if docs are installed - std_qa[r"SimulationServices.*:"] = sim_subdir - std_qa[r"Choose the CODE installation directory.*:\n.*\n\n.*:"] = sim_subdir - std_qa[r"SIMULIA/CAE.*:"] = cae_subdir - std_qa[r"location of your Abaqus services \(solvers\).*(\n.*){8}:\s*"] = sim_subdir - std_qa[r"Default.*SIMULIA/Commands\]:\s*"] = os.path.join(self.installdir, 'Commands') - std_qa[r"Default.*SIMULIA/CAE/plugins.*:\s*"] = os.path.join(self.installdir, 'plugins') - std_qa[r"Default.*SIMULIA/Isight.*:\s*"] = os.path.join(self.installdir, 'Isight') - std_qa[r"Default.*SIMULIA/fe-safe/.*:"] = os.path.join(self.installdir, 'fe-safe') - std_qa[r"Default.*SIMULIA/Tosca.*:"] = os.path.join(self.installdir, 'tosca') - - # paths to STAR-CCM+, FLUENT are requested when Tosca is also installed; - # these do not strictly need to be specified at installation time, so we don't - std_qa[r"STAR-CCM.*\n((?!___)[\S ]*\n)*\nDefault \[\]:"] = '' - std_qa[r"FLUENT.*\n((?!___)[\S ]*\n)*\nDefault \[\]:"] = '' - - std_qa[r"location of your existing ANSA installation.*(\n.*){8}:"] = '' - std_qa[r"FLUENT Path.*(\n.*){7}:"] = '' - std_qa[r"working directory to be used by Tosca Fluid\s*(\n.*)*Default \[/usr/temp\]:\s*"] = '/tmp' - - # License server - std_qa[r"License Server [0-9]+\s*(\n.*){3}:"] = 'abaqusfea' # bypass value for license server - std_qa[r"License Server . \(redundant\)\s*(\n.*){3}:"] = '' - std_qa[r"License Server Configuration((?!___).*\n)*" + nextstr] = '' - - std_qa[r"Please choose an action:"] = '1' + qa.extend([ + (r"Default.*SIMULIA/EstProducts.*:", cae_subdir), + (r"SIMULIA[0-9]*doc.*:", os.path.join(self.installdir, 'doc')), # if docs are installed + (r"SimulationServices.*:", sim_subdir), + (r"Choose the CODE installation directory.*:\n.*\n\n.*:", sim_subdir), + (r"SIMULIA/CAE.*:", cae_subdir), + (r"location of your Abaqus services \(solvers\).*(\n.*){8}:\s*", sim_subdir), + (r"Default.*SIMULIA/Commands\]:\s*", os.path.join(self.installdir, 'Commands')), + (r"Default.*SIMULIA/CAE/plugins.*:\s*", os.path.join(self.installdir, 'plugins')), + (r"Default.*SIMULIA/Isight.*:\s*", os.path.join(self.installdir, 'Isight')), + (r"Default.*SIMULIA/fe-safe/.*:", os.path.join(self.installdir, 'fe-safe')), + (r"Default.*SIMULIA/Tosca.*:", os.path.join(self.installdir, 'tosca')), + # paths to STAR-CCM+, FLUENT are requested when Tosca is also installed; + # these do not strictly need to be specified at installation time, so we don't + (r"STAR-CCM.*\n((?!___).*\n)*?\nDefault \[\]:", ''), + (r"FLUENT.*\n((?!___).*\n)*?\nDefault \[\]:", ''), + (r"location of your existing ANSA installation.*(\n.*){8}:", ''), + (r"FLUENT Path.*(\n.*){7}:", ''), + (r"working directory to be used by Tosca Fluid\s*(\n.*)*Default \[/usr/temp\]:\s*", '/tmp'), + # License server + (r"License Server [0-9]+\s*(\n.*){3}:", 'abaqusfea'), # bypass value for license server + (r"License Server . \(redundant\)\s*(\n.*){3}:", ''), + (r"License Server Configuration((?!___).*\n)*?" + nextstr, ''), + (r"Please choose an action:", '1'), + ]) if LooseVersion(self.version) >= LooseVersion('2022') and installed_docs: java_root = get_software_root('Java') if java_root: - std_qa[r"Please enter .*Java Runtime Environment.* path.(\n.*)+Default \[\]:"] = java_root - std_qa[r"Please enter .*Java Runtime Environment.* path.(\n.*)+Default \[.+\]:"] = '' + qa.extend([ + (r"Please enter .*Java Runtime Environment.* path.(\n.*)+Default \[\]:", java_root), + (r"Please enter .*Java Runtime Environment.* path.(\n.*)+Default \[.+\]:", ''), + ]) else: raise EasyBuildError("Java is required for ABAQUS docs versions >= 2022, but it is missing") # Continue - std_qa[nextstr] = '' + qa.append((nextstr, '')) - run_cmd_qa('./StartTUI.sh', qa, no_qa=no_qa, std_qa=std_qa, log_all=True, simple=True, maxhits=1000) + run_shell_cmd('./StartTUI.sh', qa_patterns=qa, qa_wait_patterns=no_qa, qa_timeout=1000) else: change_dir(self.builddir) if self.cfg['install_cmd'] is None: @@ -240,11 +237,12 @@ def install_step(self): raise EasyBuildError("Failed to find expected subdir for hotfix: %s", subdirs) cwd = change_dir(os.path.join(subdir, '1')) - std_qa = OrderedDict() - std_qa[r"Enter selection \(default: Next\):"] = '' - std_qa["Choose the .*installation directory.*\n.*\n\n.*:"] = os.path.join(self.installdir, 'sim') - std_qa[r"Enter selection \(default: Install\):"] = '' - run_cmd_qa('./StartTUI.sh', {}, std_qa=std_qa, log_all=True, simple=True, maxhits=100) + qa = [ + (r"Enter selection \(default: Next\):", ''), + (r"Choose the .*installation directory.*\n.*\n\n.*:", os.path.join(self.installdir, 'sim')), + (r"Enter selection \(default: Install\):", ''), + ] + run_shell_cmd('./StartTUI.sh', qa_patterns=qa, qa_wait_patterns=no_qa, qa_timeout=1000) # F_CAASIMULIAComputeServicesBuildTime part change_dir(cwd) @@ -255,7 +253,7 @@ def install_step(self): raise EasyBuildError("Failed to find expected subdir for hotfix: %s", subdirs) cwd = change_dir(os.path.join(cwd, subdir, '1')) - run_cmd_qa('./StartTUI.sh', {}, std_qa=std_qa, log_all=True, simple=True, maxhits=100) + run_shell_cmd('./StartTUI.sh', qa_patterns=qa, qa_wait_patterns=no_qa, qa_timeout=1000) change_dir(cwd) # next install Part_SIMULIA_Abaqus_CAE hotfix (ABAQUS versions <= 2020) @@ -270,14 +268,15 @@ def install_step(self): raise EasyBuildError("Failed to find expected subdir for hotfix: %s", subdirs) cwd = change_dir(os.path.join(subdir, '1')) - std_qa = OrderedDict() - std_qa[r"Enter selection \(default: Next\):"] = '' - std_qa["Choose the .*installation directory.*\n.*\n\n.*:"] = os.path.join(self.installdir, 'cae') - std_qa[r"Enter selection \(default: Install\):"] = '' - std_qa[r"\[1\] Continue\n(?:.|\n)*Please choose an action:"] = '1' - std_qa[r"\[2\] Continue\n(?:.|\n)*Please choose an action:"] = '2' + qa = [ + (r"Enter selection \(default: Next\):", ''), + (r"Choose the .*installation directory.*\n.*\n\n.*:", os.path.join(self.installdir, 'cae')), + (r"Enter selection \(default: Install\):", ''), + (r"\[1\] Continue\n(?:.|\n)*Please choose an action:", '1'), + (r"\[2\] Continue\n(?:.|\n)*Please choose an action:", '2'), + ] no_qa = [r"Please be patient; it will take a few minutes to complete\.\n(\.)*"] - run_cmd_qa('./StartTUI.sh', {}, no_qa=no_qa, std_qa=std_qa, log_all=True, simple=True, maxhits=100) + run_shell_cmd('./StartTUI.sh', qa_patterns=qa, qa_wait_patterns=no_qa, qa_timeout=1000) change_dir(cwd) # install SIMULIA Established Products hotfix (ABAQUS versions > 2020) @@ -294,18 +293,19 @@ def install_step(self): cwd = change_dir(os.path.join(subdir, '1')) no_qa = [ - '___', - '...', + r'___', + r'\.\.\.', r'\(\d+[KM]B\)', ] - std_qa = OrderedDict() - std_qa[r"Enter selection \(default: Next\):"] = '' - std_qa["Choose the .*installation directory.*\n.*\n\n.*:"] = os.path.join(self.installdir, 'cae') - std_qa[r"Enter selection \(default: Install\):"] = '' - std_qa[r"The Abaqus commands directory.*:\n.*\n+Actions:\n.*\n_+\n\nPlease.*:"] = '1' - std_qa[r"Enter selection \(default: Close\):"] = '' - - run_cmd_qa('./StartTUI.sh', {}, no_qa=no_qa, std_qa=std_qa, log_all=True, simple=True, maxhits=100) + qa = [ + (r"Enter selection \(default: Next\):", ''), + (r"Choose the .*installation directory.*\n.*\n\n.*:", os.path.join(self.installdir, 'cae')), + (r"Enter selection \(default: Install\):", ''), + (r"The Abaqus commands directory.*:\n.*\n+Actions:\n.*\n_+\n\nPlease.*:", '1'), + (r"Enter selection \(default: Close\):", ''), + ] + + run_shell_cmd('./StartTUI.sh', qa_patterns=qa, qa_wait_patterns=no_qa, qa_timeout=1000) change_dir(cwd) # create 'abaqus' symlink for main command, which is not there anymore starting with ABAQUS 2022