We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
MATLAB easyblock doesn't handle errors during install
The matlab installer script always returns 0, even if it fails due to, e.g. specifying the wrong key. 
There is no way to view the reason why, because the installer doesn't output anything to stdout. I had to run the install command myself with a modified with a outputFile specified, which contained the actual errors.

We should minimum just specify the outputFile argument so that the error logs appear *somewhere*, and possibly check for any errors inside this file. 

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `easybuild/easyblocks/m/matlab.py`
Content:
```
1 ##
2 # Copyright 2009-2023 Ghent University
3 #
4 # This file is part of EasyBuild,
5 # originally created by the HPC team of Ghent University (http://ugent.be/hpc/en),
6 # with support of Ghent University (http://ugent.be/hpc),
7 # the Flemish Supercomputer Centre (VSC) (https://www.vscentrum.be),
8 # Flemish Research Foundation (FWO) (http://www.fwo.be/en)
9 # and the Department of Economy, Science and Innovation (EWI) (http://www.ewi-vlaanderen.be/en).
10 #
11 # https://github.com/easybuilders/easybuild
12 #
13 # EasyBuild is free software: you can redistribute it and/or modify
14 # it under the terms of the GNU General Public License as published by
15 # the Free Software Foundation v2.
16 #
17 # EasyBuild is distributed in the hope that it will be useful,
18 # but WITHOUT ANY WARRANTY; without even the implied warranty of
19 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20 # GNU General Public License for more details.
21 #
22 # You should have received a copy of the GNU General Public License
23 # along with EasyBuild.  If not, see <http://www.gnu.org/licenses/>.
24 ##
25 """
26 EasyBuild support for installing MATLAB, implemented as an easyblock
27 
28 @author: Stijn De Weirdt (Ghent University)
29 @author: Dries Verdegem (Ghent University)
30 @author: Kenneth Hoste (Ghent University)
31 @author: Pieter De Baets (Ghent University)
32 @author: Jens Timmerman (Ghent University)
33 @author: Fotis Georgatos (Uni.Lu, NTUA)
34 """
35 import re
36 import os
37 import stat
38 import tempfile
39 
40 from distutils.version import LooseVersion
41 
42 from easybuild.easyblocks.generic.packedbinary import PackedBinary
43 from easybuild.framework.easyconfig import CUSTOM
44 from easybuild.tools.build_log import EasyBuildError
45 from easybuild.tools.filetools import adjust_permissions, change_dir, copy_file, read_file, write_file
46 from easybuild.tools.py2vs3 import string_type
47 from easybuild.tools.run import run_cmd
48 
49 
50 class EB_MATLAB(PackedBinary):
51     """Support for installing MATLAB."""
52 
53     def __init__(self, *args, **kwargs):
54         """Add extra config options specific to MATLAB."""
55         super(EB_MATLAB, self).__init__(*args, **kwargs)
56         self.comp_fam = None
57         self.configfile = os.path.join(self.builddir, 'my_installer_input.txt')
58 
59     @staticmethod
60     def extra_options():
61         extra_vars = {
62             'java_options': ['-Xmx256m', "$_JAVA_OPTIONS value set for install and in module file.", CUSTOM],
63             'key': [None, "Installation key(s), make one install for each key. Single key or a list of keys", CUSTOM],
64         }
65         return PackedBinary.extra_options(extra_vars)
66 
67     def configure_step(self):
68         """Configure MATLAB installation: create license file."""
69 
70         licfile = self.cfg['license_file']
71         if licfile is None:
72             licserv = self.cfg['license_server']
73             if licserv is None:
74                 licserv = os.getenv('EB_MATLAB_LICENSE_SERVER', 'license.example.com')
75             licport = self.cfg['license_server_port']
76             if licport is None:
77                 licport = os.getenv('EB_MATLAB_LICENSE_SERVER_PORT', '00000')
78             # create license file
79             lictxt = '\n'.join([
80                 "SERVER %s 000000000000 %s" % (licserv, licport),
81                 "USE_SERVER",
82             ])
83 
84             licfile = os.path.join(self.builddir, 'matlab.lic')
85             write_file(licfile, lictxt)
86 
87         try:
88             copy_file(os.path.join(self.cfg['start_dir'], 'installer_input.txt'), self.configfile)
89             adjust_permissions(self.configfile, stat.S_IWUSR)
90 
91             # read file in binary mode to avoid UTF-8 encoding issues when using Python 3,
92             # due to non-UTF-8 characters...
93             config = read_file(self.configfile, mode='rb')
94 
95             # use raw byte strings (must be 'br', not 'rb'),
96             # required when using Python 3 because file was read in binary mode
97             regdest = re.compile(br"^# destinationFolder=.*", re.M)
98             regagree = re.compile(br"^# agreeToLicense=.*", re.M)
99             regmode = re.compile(br"^# mode=.*", re.M)
100             reglicpath = re.compile(br"^# licensePath=.*", re.M)
101 
102             # must use byte-strings here when using Python 3, see above
103             config = regdest.sub(b"destinationFolder=%s" % self.installdir.encode('utf-8'), config)
104             config = regagree.sub(b"agreeToLicense=Yes", config)
105             config = regmode.sub(b"mode=silent", config)
106             config = reglicpath.sub(b"licensePath=%s" % licfile.encode('utf-8'), config)
107 
108             write_file(self.configfile, config)
109 
110         except IOError as err:
111             raise EasyBuildError("Failed to create installation config file %s: %s", self.configfile, err)
112 
113         self.log.debug('configuration file written to %s:\n %s', self.configfile, config)
114 
115     def install_step(self):
116         """MATLAB install procedure using 'install' command."""
117 
118         src = os.path.join(self.cfg['start_dir'], 'install')
119 
120         # make sure install script is executable
121         adjust_permissions(src, stat.S_IXUSR)
122 
123         if LooseVersion(self.version) >= LooseVersion('2016b'):
124             perm_dirs = [os.path.join(self.cfg['start_dir'], 'bin', 'glnxa64')]
125             if LooseVersion(self.version) < LooseVersion('2021b'):
126                 jdir = os.path.join(self.cfg['start_dir'], 'sys', 'java', 'jre', 'glnxa64', 'jre', 'bin')
127                 perm_dirs.append(jdir)
128             for perm_dir in perm_dirs:
129                 adjust_permissions(perm_dir, stat.S_IXUSR)
130 
131         # make sure $DISPLAY is not defined, which may lead to (hard to trace) problems
132         # this is a workaround for not being able to specify --nodisplay to the install scripts
133         if 'DISPLAY' in os.environ:
134             os.environ.pop('DISPLAY')
135 
136         if '_JAVA_OPTIONS' not in self.cfg['preinstallopts']:
137             java_opts = 'export _JAVA_OPTIONS="%s" && ' % self.cfg['java_options']
138             self.cfg['preinstallopts'] = java_opts + self.cfg['preinstallopts']
139         if LooseVersion(self.version) >= LooseVersion('2016b'):
140             change_dir(self.builddir)
141 
142         # Build the cmd string
143         cmdlist = [
144             self.cfg['preinstallopts'],
145             src,
146             '-inputFile',
147             self.configfile,
148         ]
149         if LooseVersion(self.version) < LooseVersion('2020a'):
150             # MATLAB installers < 2020a ignore $TMPDIR (always use /tmp) and might need a large tmpdir
151             tmpdir = tempfile.mkdtemp()
152             cmdlist.extend([
153                 '-v',
154                 '-tmpdir',
155                 tmpdir,
156             ])
157         cmdlist.append(self.cfg['installopts'])
158         cmd = ' '.join(cmdlist)
159 
160         keys = self.cfg['key']
161         if keys is None:
162             try:
163                 keys = os.environ['EB_MATLAB_KEY']
164             except KeyError:
165                 raise EasyBuildError("The MATLAB install key is not set. This can be set either with the environment "
166                                      "variable EB_MATLAB_KEY or by the easyconfig variable 'key'.")
167         if isinstance(keys, string_type):
168             keys = keys.split(',')
169 
170         # Compile the installation key regex outside of the loop
171         regkey = re.compile(br"^(# )?fileInstallationKey=.*", re.M)
172 
173         # Run an install for each key
174         for i, key in enumerate(keys):
175 
176             self.log.info('Installing MATLAB with key %s of %s', i + 1, len(keys))
177 
178             try:
179                 config = read_file(self.configfile, mode='rb')
180                 config = regkey.sub(b"fileInstallationKey=%s" % key.encode('utf-8'), config)
181                 write_file(self.configfile, config)
182 
183             except IOError as err:
184                 raise EasyBuildError("Failed to update config file %s: %s", self.configfile, err)
185 
186             (out, _) = run_cmd(cmd, log_all=True, simple=False)
187 
188             # check installer output for known signs of trouble
189             patterns = [
190                 "Error: You have entered an invalid File Installation Key",
191             ]
192 
193             for pattern in patterns:
194                 regex = re.compile(pattern, re.I)
195                 if regex.search(out):
196                     raise EasyBuildError("Found error pattern '%s' in output of installation command '%s': %s",
197                                          regex.pattern, cmd, out)
198 
199     def sanity_check_step(self):
200         """Custom sanity check for MATLAB."""
201         custom_paths = {
202             'files': ["bin/matlab", "bin/glnxa64/MATLAB", "toolbox/local/classpath.txt"],
203             'dirs': ["java/jar"],
204         }
205         super(EB_MATLAB, self).sanity_check_step(custom_paths=custom_paths)
206 
207     def make_module_extra(self):
208         """Extend PATH and set proper _JAVA_OPTIONS (e.g., -Xmx)."""
209         txt = super(EB_MATLAB, self).make_module_extra()
210 
211         # make MATLAB runtime available
212         if LooseVersion(self.version) >= LooseVersion('2017a'):
213             for ldlibdir in ['runtime', 'bin', os.path.join('sys', 'os')]:
214                 libdir = os.path.join(ldlibdir, 'glnxa64')
215                 txt += self.module_generator.prepend_paths('LD_LIBRARY_PATH', libdir)
216         if self.cfg['java_options']:
217             txt += self.module_generator.set_environment('_JAVA_OPTIONS', self.cfg['java_options'])
218         return txt
219
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/easybuild/easyblocks/m/matlab.py b/easybuild/easyblocks/m/matlab.py
--- a/easybuild/easyblocks/m/matlab.py
+++ b/easybuild/easyblocks/m/matlab.py
@@ -55,6 +55,7 @@
         super(EB_MATLAB, self).__init__(*args, **kwargs)
         self.comp_fam = None
         self.configfile = os.path.join(self.builddir, 'my_installer_input.txt')
+        self.outputfile = os.path.join(self.builddir, 'my_installer_output.txt')
 
     @staticmethod
     def extra_options():
@@ -98,12 +99,14 @@
             regagree = re.compile(br"^# agreeToLicense=.*", re.M)
             regmode = re.compile(br"^# mode=.*", re.M)
             reglicpath = re.compile(br"^# licensePath=.*", re.M)
+            regoutfile = re.compile(br"^# outputFile=.*", re.M)
 
             # must use byte-strings here when using Python 3, see above
             config = regdest.sub(b"destinationFolder=%s" % self.installdir.encode('utf-8'), config)
             config = regagree.sub(b"agreeToLicense=Yes", config)
             config = regmode.sub(b"mode=silent", config)
             config = reglicpath.sub(b"licensePath=%s" % licfile.encode('utf-8'), config)
+            config = regoutfile.sub(b"outputFile=%s" % self.outputfile.encode('utf-8'), config)
 
             write_file(self.configfile, config)
 
@@ -188,6 +191,12 @@
             # check installer output for known signs of trouble
             patterns = [
                 "Error: You have entered an invalid File Installation Key",
+                "Not a valid key",
+                "All selected products are already installed",
+                "The application encountered an unexpected error and needs to close",
+                "Error: Unable to write to",
+                "Exiting with status -\\d",
+                "End - Unsuccessful",
             ]
 
             for pattern in patterns:
@@ -195,6 +204,10 @@
                 if regex.search(out):
                     raise EasyBuildError("Found error pattern '%s' in output of installation command '%s': %s",
                                          regex.pattern, cmd, out)
+                with open(self.outputfile) as f:
+                    if regex.search(f.read()):
+                        raise EasyBuildError("Found error pattern '%s' in output file of installer",
+                                             regex.pattern)
 
     def sanity_check_step(self):
         """Custom sanity check for MATLAB."""

{"golden_diff": "diff --git a/easybuild/easyblocks/m/matlab.py b/easybuild/easyblocks/m/matlab.py\n--- a/easybuild/easyblocks/m/matlab.py\n+++ b/easybuild/easyblocks/m/matlab.py\n@@ -55,6 +55,7 @@\n         super(EB_MATLAB, self).__init__(*args, **kwargs)\n         self.comp_fam = None\n         self.configfile = os.path.join(self.builddir, 'my_installer_input.txt')\n+        self.outputfile = os.path.join(self.builddir, 'my_installer_output.txt')\n \n     @staticmethod\n     def extra_options():\n@@ -98,12 +99,14 @@\n             regagree = re.compile(br\"^# agreeToLicense=.*\", re.M)\n             regmode = re.compile(br\"^# mode=.*\", re.M)\n             reglicpath = re.compile(br\"^# licensePath=.*\", re.M)\n+            regoutfile = re.compile(br\"^# outputFile=.*\", re.M)\n \n             # must use byte-strings here when using Python 3, see above\n             config = regdest.sub(b\"destinationFolder=%s\" % self.installdir.encode('utf-8'), config)\n             config = regagree.sub(b\"agreeToLicense=Yes\", config)\n             config = regmode.sub(b\"mode=silent\", config)\n             config = reglicpath.sub(b\"licensePath=%s\" % licfile.encode('utf-8'), config)\n+            config = regoutfile.sub(b\"outputFile=%s\" % self.outputfile.encode('utf-8'), config)\n \n             write_file(self.configfile, config)\n \n@@ -188,6 +191,12 @@\n             # check installer output for known signs of trouble\n             patterns = [\n                 \"Error: You have entered an invalid File Installation Key\",\n+                \"Not a valid key\",\n+                \"All selected products are already installed\",\n+                \"The application encountered an unexpected error and needs to close\",\n+                \"Error: Unable to write to\",\n+                \"Exiting with status -\\\\d\",\n+                \"End - Unsuccessful\",\n             ]\n \n             for pattern in patterns:\n@@ -195,6 +204,10 @@\n                 if regex.search(out):\n                     raise EasyBuildError(\"Found error pattern '%s' in output of installation command '%s': %s\",\n                                          regex.pattern, cmd, out)\n+                with open(self.outputfile) as f:\n+                    if regex.search(f.read()):\n+                        raise EasyBuildError(\"Found error pattern '%s' in output file of installer\",\n+                                             regex.pattern)\n \n     def sanity_check_step(self):\n         \"\"\"Custom sanity check for MATLAB.\"\"\"\n", "issue": "MATLAB easyblock doesn't handle errors during install\nThe matlab installer script always returns 0, even if it fails due to, e.g. specifying the wrong key. \r\nThere is no way to view the reason why, because the installer doesn't output anything to stdout. I had to run the install command myself with a modified with a outputFile specified, which contained the actual errors.\r\n\r\nWe should minimum just specify the outputFile argument so that the error logs appear *somewhere*, and possibly check for any errors inside this file. \n", "before_files": [{"content": "##\n# Copyright 2009-2023 Ghent University\n#\n# This file is part of EasyBuild,\n# originally created by the HPC team of Ghent University (http://ugent.be/hpc/en),\n# with support of Ghent University (http://ugent.be/hpc),\n# the Flemish Supercomputer Centre (VSC) (https://www.vscentrum.be),\n# Flemish Research Foundation (FWO) (http://www.fwo.be/en)\n# and the Department of Economy, Science and Innovation (EWI) (http://www.ewi-vlaanderen.be/en).\n#\n# https://github.com/easybuilders/easybuild\n#\n# EasyBuild is free software: you can redistribute it and/or modify\n# it under the terms of the GNU General Public License as published by\n# the Free Software Foundation v2.\n#\n# EasyBuild is distributed in the hope that it will be useful,\n# but WITHOUT ANY WARRANTY; without even the implied warranty of\n# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n# GNU General Public License for more details.\n#\n# You should have received a copy of the GNU General Public License\n# along with EasyBuild.  If not, see <http://www.gnu.org/licenses/>.\n##\n\"\"\"\nEasyBuild support for installing MATLAB, implemented as an easyblock\n\n@author: Stijn De Weirdt (Ghent University)\n@author: Dries Verdegem (Ghent University)\n@author: Kenneth Hoste (Ghent University)\n@author: Pieter De Baets (Ghent University)\n@author: Jens Timmerman (Ghent University)\n@author: Fotis Georgatos (Uni.Lu, NTUA)\n\"\"\"\nimport re\nimport os\nimport stat\nimport tempfile\n\nfrom distutils.version import LooseVersion\n\nfrom easybuild.easyblocks.generic.packedbinary import PackedBinary\nfrom easybuild.framework.easyconfig import CUSTOM\nfrom easybuild.tools.build_log import EasyBuildError\nfrom easybuild.tools.filetools import adjust_permissions, change_dir, copy_file, read_file, write_file\nfrom easybuild.tools.py2vs3 import string_type\nfrom easybuild.tools.run import run_cmd\n\n\nclass EB_MATLAB(PackedBinary):\n    \"\"\"Support for installing MATLAB.\"\"\"\n\n    def __init__(self, *args, **kwargs):\n        \"\"\"Add extra config options specific to MATLAB.\"\"\"\n        super(EB_MATLAB, self).__init__(*args, **kwargs)\n        self.comp_fam = None\n        self.configfile = os.path.join(self.builddir, 'my_installer_input.txt')\n\n    @staticmethod\n    def extra_options():\n        extra_vars = {\n            'java_options': ['-Xmx256m', \"$_JAVA_OPTIONS value set for install and in module file.\", CUSTOM],\n            'key': [None, \"Installation key(s), make one install for each key. Single key or a list of keys\", CUSTOM],\n        }\n        return PackedBinary.extra_options(extra_vars)\n\n    def configure_step(self):\n        \"\"\"Configure MATLAB installation: create license file.\"\"\"\n\n        licfile = self.cfg['license_file']\n        if licfile is None:\n            licserv = self.cfg['license_server']\n            if licserv is None:\n                licserv = os.getenv('EB_MATLAB_LICENSE_SERVER', 'license.example.com')\n            licport = self.cfg['license_server_port']\n            if licport is None:\n                licport = os.getenv('EB_MATLAB_LICENSE_SERVER_PORT', '00000')\n            # create license file\n            lictxt = '\\n'.join([\n                \"SERVER %s 000000000000 %s\" % (licserv, licport),\n                \"USE_SERVER\",\n            ])\n\n            licfile = os.path.join(self.builddir, 'matlab.lic')\n            write_file(licfile, lictxt)\n\n        try:\n            copy_file(os.path.join(self.cfg['start_dir'], 'installer_input.txt'), self.configfile)\n            adjust_permissions(self.configfile, stat.S_IWUSR)\n\n            # read file in binary mode to avoid UTF-8 encoding issues when using Python 3,\n            # due to non-UTF-8 characters...\n            config = read_file(self.configfile, mode='rb')\n\n            # use raw byte strings (must be 'br', not 'rb'),\n            # required when using Python 3 because file was read in binary mode\n            regdest = re.compile(br\"^# destinationFolder=.*\", re.M)\n            regagree = re.compile(br\"^# agreeToLicense=.*\", re.M)\n            regmode = re.compile(br\"^# mode=.*\", re.M)\n            reglicpath = re.compile(br\"^# licensePath=.*\", re.M)\n\n            # must use byte-strings here when using Python 3, see above\n            config = regdest.sub(b\"destinationFolder=%s\" % self.installdir.encode('utf-8'), config)\n            config = regagree.sub(b\"agreeToLicense=Yes\", config)\n            config = regmode.sub(b\"mode=silent\", config)\n            config = reglicpath.sub(b\"licensePath=%s\" % licfile.encode('utf-8'), config)\n\n            write_file(self.configfile, config)\n\n        except IOError as err:\n            raise EasyBuildError(\"Failed to create installation config file %s: %s\", self.configfile, err)\n\n        self.log.debug('configuration file written to %s:\\n %s', self.configfile, config)\n\n    def install_step(self):\n        \"\"\"MATLAB install procedure using 'install' command.\"\"\"\n\n        src = os.path.join(self.cfg['start_dir'], 'install')\n\n        # make sure install script is executable\n        adjust_permissions(src, stat.S_IXUSR)\n\n        if LooseVersion(self.version) >= LooseVersion('2016b'):\n            perm_dirs = [os.path.join(self.cfg['start_dir'], 'bin', 'glnxa64')]\n            if LooseVersion(self.version) < LooseVersion('2021b'):\n                jdir = os.path.join(self.cfg['start_dir'], 'sys', 'java', 'jre', 'glnxa64', 'jre', 'bin')\n                perm_dirs.append(jdir)\n            for perm_dir in perm_dirs:\n                adjust_permissions(perm_dir, stat.S_IXUSR)\n\n        # make sure $DISPLAY is not defined, which may lead to (hard to trace) problems\n        # this is a workaround for not being able to specify --nodisplay to the install scripts\n        if 'DISPLAY' in os.environ:\n            os.environ.pop('DISPLAY')\n\n        if '_JAVA_OPTIONS' not in self.cfg['preinstallopts']:\n            java_opts = 'export _JAVA_OPTIONS=\"%s\" && ' % self.cfg['java_options']\n            self.cfg['preinstallopts'] = java_opts + self.cfg['preinstallopts']\n        if LooseVersion(self.version) >= LooseVersion('2016b'):\n            change_dir(self.builddir)\n\n        # Build the cmd string\n        cmdlist = [\n            self.cfg['preinstallopts'],\n            src,\n            '-inputFile',\n            self.configfile,\n        ]\n        if LooseVersion(self.version) < LooseVersion('2020a'):\n            # MATLAB installers < 2020a ignore $TMPDIR (always use /tmp) and might need a large tmpdir\n            tmpdir = tempfile.mkdtemp()\n            cmdlist.extend([\n                '-v',\n                '-tmpdir',\n                tmpdir,\n            ])\n        cmdlist.append(self.cfg['installopts'])\n        cmd = ' '.join(cmdlist)\n\n        keys = self.cfg['key']\n        if keys is None:\n            try:\n                keys = os.environ['EB_MATLAB_KEY']\n            except KeyError:\n                raise EasyBuildError(\"The MATLAB install key is not set. This can be set either with the environment \"\n                                     \"variable EB_MATLAB_KEY or by the easyconfig variable 'key'.\")\n        if isinstance(keys, string_type):\n            keys = keys.split(',')\n\n        # Compile the installation key regex outside of the loop\n        regkey = re.compile(br\"^(# )?fileInstallationKey=.*\", re.M)\n\n        # Run an install for each key\n        for i, key in enumerate(keys):\n\n            self.log.info('Installing MATLAB with key %s of %s', i + 1, len(keys))\n\n            try:\n                config = read_file(self.configfile, mode='rb')\n                config = regkey.sub(b\"fileInstallationKey=%s\" % key.encode('utf-8'), config)\n                write_file(self.configfile, config)\n\n            except IOError as err:\n                raise EasyBuildError(\"Failed to update config file %s: %s\", self.configfile, err)\n\n            (out, _) = run_cmd(cmd, log_all=True, simple=False)\n\n            # check installer output for known signs of trouble\n            patterns = [\n                \"Error: You have entered an invalid File Installation Key\",\n            ]\n\n            for pattern in patterns:\n                regex = re.compile(pattern, re.I)\n                if regex.search(out):\n                    raise EasyBuildError(\"Found error pattern '%s' in output of installation command '%s': %s\",\n                                         regex.pattern, cmd, out)\n\n    def sanity_check_step(self):\n        \"\"\"Custom sanity check for MATLAB.\"\"\"\n        custom_paths = {\n            'files': [\"bin/matlab\", \"bin/glnxa64/MATLAB\", \"toolbox/local/classpath.txt\"],\n            'dirs': [\"java/jar\"],\n        }\n        super(EB_MATLAB, self).sanity_check_step(custom_paths=custom_paths)\n\n    def make_module_extra(self):\n        \"\"\"Extend PATH and set proper _JAVA_OPTIONS (e.g., -Xmx).\"\"\"\n        txt = super(EB_MATLAB, self).make_module_extra()\n\n        # make MATLAB runtime available\n        if LooseVersion(self.version) >= LooseVersion('2017a'):\n            for ldlibdir in ['runtime', 'bin', os.path.join('sys', 'os')]:\n                libdir = os.path.join(ldlibdir, 'glnxa64')\n                txt += self.module_generator.prepend_paths('LD_LIBRARY_PATH', libdir)\n        if self.cfg['java_options']:\n            txt += self.module_generator.set_environment('_JAVA_OPTIONS', self.cfg['java_options'])\n        return txt\n", "path": "easybuild/easyblocks/m/matlab.py"}], "after_files": [{"content": "##\n# Copyright 2009-2023 Ghent University\n#\n# This file is part of EasyBuild,\n# originally created by the HPC team of Ghent University (http://ugent.be/hpc/en),\n# with support of Ghent University (http://ugent.be/hpc),\n# the Flemish Supercomputer Centre (VSC) (https://www.vscentrum.be),\n# Flemish Research Foundation (FWO) (http://www.fwo.be/en)\n# and the Department of Economy, Science and Innovation (EWI) (http://www.ewi-vlaanderen.be/en).\n#\n# https://github.com/easybuilders/easybuild\n#\n# EasyBuild is free software: you can redistribute it and/or modify\n# it under the terms of the GNU General Public License as published by\n# the Free Software Foundation v2.\n#\n# EasyBuild is distributed in the hope that it will be useful,\n# but WITHOUT ANY WARRANTY; without even the implied warranty of\n# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n# GNU General Public License for more details.\n#\n# You should have received a copy of the GNU General Public License\n# along with EasyBuild.  If not, see <http://www.gnu.org/licenses/>.\n##\n\"\"\"\nEasyBuild support for installing MATLAB, implemented as an easyblock\n\n@author: Stijn De Weirdt (Ghent University)\n@author: Dries Verdegem (Ghent University)\n@author: Kenneth Hoste (Ghent University)\n@author: Pieter De Baets (Ghent University)\n@author: Jens Timmerman (Ghent University)\n@author: Fotis Georgatos (Uni.Lu, NTUA)\n\"\"\"\nimport re\nimport os\nimport stat\nimport tempfile\n\nfrom distutils.version import LooseVersion\n\nfrom easybuild.easyblocks.generic.packedbinary import PackedBinary\nfrom easybuild.framework.easyconfig import CUSTOM\nfrom easybuild.tools.build_log import EasyBuildError\nfrom easybuild.tools.filetools import adjust_permissions, change_dir, copy_file, read_file, write_file\nfrom easybuild.tools.py2vs3 import string_type\nfrom easybuild.tools.run import run_cmd\n\n\nclass EB_MATLAB(PackedBinary):\n    \"\"\"Support for installing MATLAB.\"\"\"\n\n    def __init__(self, *args, **kwargs):\n        \"\"\"Add extra config options specific to MATLAB.\"\"\"\n        super(EB_MATLAB, self).__init__(*args, **kwargs)\n        self.comp_fam = None\n        self.configfile = os.path.join(self.builddir, 'my_installer_input.txt')\n        self.outputfile = os.path.join(self.builddir, 'my_installer_output.txt')\n\n    @staticmethod\n    def extra_options():\n        extra_vars = {\n            'java_options': ['-Xmx256m', \"$_JAVA_OPTIONS value set for install and in module file.\", CUSTOM],\n            'key': [None, \"Installation key(s), make one install for each key. Single key or a list of keys\", CUSTOM],\n        }\n        return PackedBinary.extra_options(extra_vars)\n\n    def configure_step(self):\n        \"\"\"Configure MATLAB installation: create license file.\"\"\"\n\n        licfile = self.cfg['license_file']\n        if licfile is None:\n            licserv = self.cfg['license_server']\n            if licserv is None:\n                licserv = os.getenv('EB_MATLAB_LICENSE_SERVER', 'license.example.com')\n            licport = self.cfg['license_server_port']\n            if licport is None:\n                licport = os.getenv('EB_MATLAB_LICENSE_SERVER_PORT', '00000')\n            # create license file\n            lictxt = '\\n'.join([\n                \"SERVER %s 000000000000 %s\" % (licserv, licport),\n                \"USE_SERVER\",\n            ])\n\n            licfile = os.path.join(self.builddir, 'matlab.lic')\n            write_file(licfile, lictxt)\n\n        try:\n            copy_file(os.path.join(self.cfg['start_dir'], 'installer_input.txt'), self.configfile)\n            adjust_permissions(self.configfile, stat.S_IWUSR)\n\n            # read file in binary mode to avoid UTF-8 encoding issues when using Python 3,\n            # due to non-UTF-8 characters...\n            config = read_file(self.configfile, mode='rb')\n\n            # use raw byte strings (must be 'br', not 'rb'),\n            # required when using Python 3 because file was read in binary mode\n            regdest = re.compile(br\"^# destinationFolder=.*\", re.M)\n            regagree = re.compile(br\"^# agreeToLicense=.*\", re.M)\n            regmode = re.compile(br\"^# mode=.*\", re.M)\n            reglicpath = re.compile(br\"^# licensePath=.*\", re.M)\n            regoutfile = re.compile(br\"^# outputFile=.*\", re.M)\n\n            # must use byte-strings here when using Python 3, see above\n            config = regdest.sub(b\"destinationFolder=%s\" % self.installdir.encode('utf-8'), config)\n            config = regagree.sub(b\"agreeToLicense=Yes\", config)\n            config = regmode.sub(b\"mode=silent\", config)\n            config = reglicpath.sub(b\"licensePath=%s\" % licfile.encode('utf-8'), config)\n            config = regoutfile.sub(b\"outputFile=%s\" % self.outputfile.encode('utf-8'), config)\n\n            write_file(self.configfile, config)\n\n        except IOError as err:\n            raise EasyBuildError(\"Failed to create installation config file %s: %s\", self.configfile, err)\n\n        self.log.debug('configuration file written to %s:\\n %s', self.configfile, config)\n\n    def install_step(self):\n        \"\"\"MATLAB install procedure using 'install' command.\"\"\"\n\n        src = os.path.join(self.cfg['start_dir'], 'install')\n\n        # make sure install script is executable\n        adjust_permissions(src, stat.S_IXUSR)\n\n        if LooseVersion(self.version) >= LooseVersion('2016b'):\n            perm_dirs = [os.path.join(self.cfg['start_dir'], 'bin', 'glnxa64')]\n            if LooseVersion(self.version) < LooseVersion('2021b'):\n                jdir = os.path.join(self.cfg['start_dir'], 'sys', 'java', 'jre', 'glnxa64', 'jre', 'bin')\n                perm_dirs.append(jdir)\n            for perm_dir in perm_dirs:\n                adjust_permissions(perm_dir, stat.S_IXUSR)\n\n        # make sure $DISPLAY is not defined, which may lead to (hard to trace) problems\n        # this is a workaround for not being able to specify --nodisplay to the install scripts\n        if 'DISPLAY' in os.environ:\n            os.environ.pop('DISPLAY')\n\n        if '_JAVA_OPTIONS' not in self.cfg['preinstallopts']:\n            java_opts = 'export _JAVA_OPTIONS=\"%s\" && ' % self.cfg['java_options']\n            self.cfg['preinstallopts'] = java_opts + self.cfg['preinstallopts']\n        if LooseVersion(self.version) >= LooseVersion('2016b'):\n            change_dir(self.builddir)\n\n        # Build the cmd string\n        cmdlist = [\n            self.cfg['preinstallopts'],\n            src,\n            '-inputFile',\n            self.configfile,\n        ]\n        if LooseVersion(self.version) < LooseVersion('2020a'):\n            # MATLAB installers < 2020a ignore $TMPDIR (always use /tmp) and might need a large tmpdir\n            tmpdir = tempfile.mkdtemp()\n            cmdlist.extend([\n                '-v',\n                '-tmpdir',\n                tmpdir,\n            ])\n        cmdlist.append(self.cfg['installopts'])\n        cmd = ' '.join(cmdlist)\n\n        keys = self.cfg['key']\n        if keys is None:\n            try:\n                keys = os.environ['EB_MATLAB_KEY']\n            except KeyError:\n                raise EasyBuildError(\"The MATLAB install key is not set. This can be set either with the environment \"\n                                     \"variable EB_MATLAB_KEY or by the easyconfig variable 'key'.\")\n        if isinstance(keys, string_type):\n            keys = keys.split(',')\n\n        # Compile the installation key regex outside of the loop\n        regkey = re.compile(br\"^(# )?fileInstallationKey=.*\", re.M)\n\n        # Run an install for each key\n        for i, key in enumerate(keys):\n\n            self.log.info('Installing MATLAB with key %s of %s', i + 1, len(keys))\n\n            try:\n                config = read_file(self.configfile, mode='rb')\n                config = regkey.sub(b\"fileInstallationKey=%s\" % key.encode('utf-8'), config)\n                write_file(self.configfile, config)\n\n            except IOError as err:\n                raise EasyBuildError(\"Failed to update config file %s: %s\", self.configfile, err)\n\n            (out, _) = run_cmd(cmd, log_all=True, simple=False)\n\n            # check installer output for known signs of trouble\n            patterns = [\n                \"Error: You have entered an invalid File Installation Key\",\n                \"Not a valid key\",\n                \"All selected products are already installed\",\n                \"The application encountered an unexpected error and needs to close\",\n                \"Error: Unable to write to\",\n                \"Exiting with status -\\\\d\",\n                \"End - Unsuccessful\",\n            ]\n\n            for pattern in patterns:\n                regex = re.compile(pattern, re.I)\n                if regex.search(out):\n                    raise EasyBuildError(\"Found error pattern '%s' in output of installation command '%s': %s\",\n                                         regex.pattern, cmd, out)\n                with open(self.outputfile) as f:\n                    if regex.search(f.read()):\n                        raise EasyBuildError(\"Found error pattern '%s' in output file of installer\",\n                                             regex.pattern)\n\n    def sanity_check_step(self):\n        \"\"\"Custom sanity check for MATLAB.\"\"\"\n        custom_paths = {\n            'files': [\"bin/matlab\", \"bin/glnxa64/MATLAB\", \"toolbox/local/classpath.txt\"],\n            'dirs': [\"java/jar\"],\n        }\n        super(EB_MATLAB, self).sanity_check_step(custom_paths=custom_paths)\n\n    def make_module_extra(self):\n        \"\"\"Extend PATH and set proper _JAVA_OPTIONS (e.g., -Xmx).\"\"\"\n        txt = super(EB_MATLAB, self).make_module_extra()\n\n        # make MATLAB runtime available\n        if LooseVersion(self.version) >= LooseVersion('2017a'):\n            for ldlibdir in ['runtime', 'bin', os.path.join('sys', 'os')]:\n                libdir = os.path.join(ldlibdir, 'glnxa64')\n                txt += self.module_generator.prepend_paths('LD_LIBRARY_PATH', libdir)\n        if self.cfg['java_options']:\n            txt += self.module_generator.set_environment('_JAVA_OPTIONS', self.cfg['java_options'])\n        return txt\n", "path": "easybuild/easyblocks/m/matlab.py"}]}