Skip to content

Commit bc3cbb0

Browse files
diningPhilosopher64Prabhakar Kumar
authored and
Prabhakar Kumar
committed
Introduces environment variable MWI_CUSTOM_MATLAB_ROOT to instruct matlab-proxy to use specified MATLAB instead of using the MATLAB found on the system PATH.
fixes #3 fixes mathworks/jupyter-matlab-proxy#37
1 parent 62d5bcf commit bc3cbb0

File tree

8 files changed

+337
-49
lines changed

8 files changed

+337
-49
lines changed

Advanced-Usage.md

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# Advanced Usage
2-
Copyright (c) 2020-2022 The MathWorks, Inc. All rights reserved.
2+
Copyright (c) 2020-2023 The MathWorks, Inc. All rights reserved.
33

44
This page lists some of the advanced manuevers that may be of specific interest to help configure the package for use in your environment.
55

@@ -29,6 +29,47 @@ The following table describes all the environment variables that you can set to
2929
| **MWI_ENABLE_TOKEN_AUTH** | string | `"True"` | When set to `True`, matlab-proxy will require users to provide the security token to access the proxy. <br />The default value is `False` . See [Token-Based Authentication](./SECURITY.md#token-based-authentication) for more information.|
3030
| **MWI_AUTH_TOKEN** | string (optional) | `"AnyURLSafeToken"` | Optionally, provide a custom `token` for use with `MWI_ENABLE_TOKEN_AUTH`. A token can safely contain any combination of alpha numeric text along with the following permitted characters: `- . _ ~`.<br />When absent matlab-proxy will generate a random URL safe token. |
3131
| **MWI_USE_EXISTING_LICENSE** | string (optional) | `"True"` | When set to True, matlab-proxy will not ask you for additional licensing information and will try to launch an already activated MATLAB on your system PATH.
32+
| **MWI_CUSTOM_MATLAB_ROOT** | string (optional) | `"/path/to/matlab/root/"` | Optionally, provide a custom path to MATLAB root. For more information see [Adding MATLAB to System Path](#adding-matlab-to-system-path) |
33+
34+
## Adding MATLAB to System Path
35+
36+
When `matlab-proxy` starts, it expects the `matlab` executable to be present on system PATH in the environment from which it was spawned.
37+
38+
`matlab-proxy` will error out if it is unable to find `matlab` on the PATH.
39+
40+
One can add it to the system PATH using the following commands:
41+
```bash
42+
# On Linux & MacOS
43+
sudo ln -fs ${MATLAB_ROOT}/bin/matlab /usr/bin/matlab
44+
45+
# On Windows environments
46+
setx PATH "${MATLAB_ROOT}\bin;%PATH%"
47+
```
48+
Where `MATLAB_ROOT` points to the folder in which MATLAB was installed.
49+
Example values of `MATLAB_ROOT` on various platforms are:
50+
```
51+
On linux: /usr/local/MATLAB/R2023a
52+
On MacOS: /Applications/MATLAB_R2023a.app
53+
On Windows: C:\Program Files\MATLAB\R2023a
54+
```
55+
56+
### Custom MATLAB Root
57+
58+
Use the environment variable `MWI_CUSTOM_MATLAB_ROOT` to specify the location of `MATLAB_ROOT`.
59+
60+
When this environment variable is set, `matlab-proxy` will not search the system PATH for MATLAB.
61+
62+
This might be useful in the following situations:
63+
64+
1. Changes to the system PATH are not possible or desirable.
65+
2. There are multiple MATLAB installations on a system, and you want to use `matlab-proxy` with a particular installation of MATLAB.
66+
3. The existing `matlab` executable on PATH is a user defined script as explained in this [issue](https://github.com/mathworks/matlab-proxy/issues/3).
67+
68+
Example usage:
69+
```bash
70+
env MWI_CUSTOM_MATLAB_ROOT=/opt/software/matlab/r2023a matlab-proxy-app
71+
```
72+
3273

3374

3475
## Custom HTTP Headers

matlab_proxy/app.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Copyright (c) 2020-2022 The MathWorks, Inc.
1+
# Copyright (c) 2020-2023 The MathWorks, Inc.
22

33
import asyncio
44
import json
@@ -19,7 +19,7 @@
1919
from matlab_proxy.util import list_servers, mwi
2020
from matlab_proxy.util.mwi import environment_variables as mwi_env
2121
from matlab_proxy.util.mwi import token_auth
22-
from matlab_proxy.util.mwi.exceptions import AppError, LicensingError, InvalidTokenError
22+
from matlab_proxy.util.mwi.exceptions import AppError, InvalidTokenError, LicensingError
2323

2424
mimetypes.add_type("font/woff", ".woff")
2525
mimetypes.add_type("font/woff2", ".woff2")

matlab_proxy/constants.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1-
"""This module defines project-level constants"""
1+
# Copyright (c) 2023 The MathWorks, Inc.
22

3+
"""This module defines project-level constants"""
34
CONNECTOR_SECUREPORT_FILENAME = "connector.securePort"
5+
VERSION_INFO_FILE_NAME = "VersionInfo.xml"

matlab_proxy/settings.py

Lines changed: 50 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -11,28 +11,68 @@
1111
from pathlib import Path
1212

1313
import matlab_proxy
14+
from matlab_proxy.constants import VERSION_INFO_FILE_NAME
1415
from matlab_proxy.util import mwi, system
1516
from matlab_proxy.util.mwi import environment_variables as mwi_env
1617
from matlab_proxy.util.mwi import token_auth
1718

1819
logger = mwi.logger.get()
1920

2021

21-
def get_matlab_path():
22+
def get_matlab_root_path():
23+
"""Returns the path from the MWI_CUSTOM_MATLAB_ROOT environment variable if valid, else returns
24+
MATLAB root based on the matlab executable if found on the system path.
25+
26+
Returns:
27+
pathlib.Path: pathlib.Path object to MATLAB root.
28+
"""
29+
custom_matlab_root_path = os.environ.get(mwi_env.get_env_name_custom_matlab_root())
30+
31+
if custom_matlab_root_path and mwi.validators.validate_custom_matlab_root_path(
32+
Path(custom_matlab_root_path)
33+
):
34+
return custom_matlab_root_path
35+
2236
which_matlab = shutil.which("matlab")
23-
if which_matlab is None:
37+
38+
return Path(which_matlab).resolve().parent.parent if which_matlab else None
39+
40+
41+
def get_matlab_executable_path(matlab_root_path: Path):
42+
"""Returns path to the MATLAB executable based on the OS
43+
44+
Args:
45+
matlab_root_path (Path): Path to MATLAB Root
46+
47+
Returns:
48+
[Path | None]: Path to MATLAB executable if a valid MATLAB root path is supplied else return None
49+
"""
50+
if not matlab_root_path:
2451
return None
25-
return Path(which_matlab).resolve().parent.parent
52+
53+
return (
54+
matlab_root_path / "bin" / "matlab"
55+
if system.is_posix()
56+
else matlab_root_path / "bin" / "matlab.exe"
57+
)
2658

2759

28-
def get_matlab_version(matlab_path):
29-
"""Get the MATLAB Release version in this image"""
60+
def get_matlab_version(matlab_root_path):
61+
"""Returns MATLAB version from VersionInfo.xml file present at matlab_root_path
3062
31-
if matlab_path is None:
63+
Args:
64+
matlab_root_path (pathlib.Path): pathlib.Path to MATLAB root.
65+
66+
Returns:
67+
(str | None): Returns MATLAB version from VersionInfo.xml file.
68+
"""
69+
if matlab_root_path is None:
3270
return None
3371

34-
tree = ET.parse(matlab_path / "VersionInfo.xml")
72+
version_info_file_path = Path(matlab_root_path) / VERSION_INFO_FILE_NAME
73+
tree = ET.parse(version_info_file_path)
3574
root = tree.getroot()
75+
3676
return root.find("release").text
3777

3878

@@ -137,7 +177,8 @@ def get(config_name=matlab_proxy.get_default_config_name(), dev=False):
137177
matlab_startup_file = str(
138178
Path(__file__).resolve().parent / "matlab" / "startup.m"
139179
)
140-
matlab_path = get_matlab_path()
180+
matlab_path = get_matlab_root_path()
181+
matlab_executable_path = get_matlab_executable_path(Path(matlab_path))
141182
ws_env, ws_env_suffix = get_ws_env_settings()
142183

143184
ssl_key_file, ssl_cert_file = mwi.validators.validate_ssl_key_and_cert_file(
@@ -172,7 +213,7 @@ def get(config_name=matlab_proxy.get_default_config_name(), dev=False):
172213
"matlab_path": matlab_path,
173214
"matlab_version": get_matlab_version(matlab_path),
174215
"matlab_cmd": [
175-
"matlab",
216+
matlab_executable_path,
176217
"-nosplash",
177218
flag_to_hide_desktop,
178219
"-softwareopengl",

matlab_proxy/util/__init__.py

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
1-
# Copyright (c) 2020-2022 The MathWorks, Inc.
1+
# Copyright (c) 2020-2023 The MathWorks, Inc.
22
import argparse
33
import os
44
import socket
5-
import sys
5+
6+
from pathlib import Path
67

78
import matlab_proxy
89
from matlab_proxy.util import mwi, system
@@ -241,3 +242,16 @@ def get_access_url(app):
241242
url = f"{access_protocol}://{host_interface}:{port}{base_url}"
242243

243244
return url
245+
246+
247+
def is_valid_path(path: Path):
248+
"""Returns true if path supplied is a valid path to a file or directory
249+
250+
Args:
251+
path (pathlib.Path): pathlib.Path object of a file or directory
252+
253+
Returns:
254+
bool: True if a valid path is supplied else False
255+
"""
256+
path = Path(path)
257+
return path.is_dir() or path.is_file()

matlab_proxy/util/mwi/environment_variables.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Copyright (c) 2020-2022 The MathWorks, Inc.
1+
# Copyright (c) 2020-2023 The MathWorks, Inc.
22
"""This file lists and exposes the environment variables which are used by the integration."""
33

44
import os
@@ -145,3 +145,8 @@ def get_env_name_matlab_log_dir():
145145
def get_env_name_mwi_use_existing_license():
146146
"""Returns the environment variable name used to instruct matlab-proxy to use an existing license. Usually used by already activated MATLAB installations."""
147147
return "MWI_USE_EXISTING_LICENSE"
148+
149+
150+
def get_env_name_custom_matlab_root():
151+
"""User specified path to MATLAB root"""
152+
return "MWI_CUSTOM_MATLAB_ROOT"

matlab_proxy/util/mwi/validators.py

Lines changed: 57 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Copyright (c) 2020-2022 The MathWorks, Inc.
1+
# Copyright (c) 2020-2023 The MathWorks, Inc.
22
"""This file contains validators for various runtime artefacts.
33
A validator is defined as a function which verifies the input and
44
returns it unchanged if validation passes.
@@ -14,15 +14,23 @@
1414
import os
1515
import socket
1616
import sys
17+
from pathlib import Path
18+
19+
from typing import List
1720

1821
import pkg_resources
1922

2023
import matlab_proxy
24+
from matlab_proxy.constants import VERSION_INFO_FILE_NAME
2125

2226
from . import environment_variables as mwi_env
2327
from matlab_proxy.util import system
2428
from . import logger as mwi_logger
2529

30+
from matlab_proxy import util
31+
32+
from .exceptions import MatlabError
33+
2634
logger = mwi_logger.get()
2735

2836

@@ -276,3 +284,51 @@ def validate_use_existing_licensing(use_existing_license):
276284
bool: if use_existing_license is set to true
277285
"""
278286
return True if use_existing_license.casefold() == "true" else False
287+
288+
289+
def validate_paths(paths: List[Path]):
290+
"""Validates if paths of directories or files exists on the file system.
291+
292+
Args:
293+
paths ([pathlib.Path]): List of pathlib.Path's to directories or files
294+
295+
Raises:
296+
OSError: When an invalid path is supplied
297+
298+
Returns:
299+
[pathlib.Path] | None: [pathlib.Path] if valid paths are supplied else None
300+
"""
301+
for path in paths:
302+
if not util.is_valid_path(path):
303+
raise OSError(f"Supplied invalid path:{path}")
304+
305+
return paths
306+
307+
308+
def validate_custom_matlab_root_path(matlab_root: Path):
309+
"""Validate if path supplied is MATLAB_ROOT by checking for the existence of VersionInfo.xml file
310+
at matlab_root
311+
312+
Args:
313+
path (pathlib.Path): path to MATLAB root
314+
315+
Returns:
316+
pathlib.Path | None: pathlib.Path if a valid path to MATLAB root is supplied else None
317+
"""
318+
try:
319+
matlab_root = matlab_root
320+
validate_paths([matlab_root])
321+
logger.debug(f"Supplied valid MATLAB root path:{matlab_root}")
322+
except OSError as exc:
323+
logger.error(". ".join(exc.args))
324+
sys.exit(1)
325+
326+
version_info_file_path = matlab_root / VERSION_INFO_FILE_NAME
327+
328+
if not version_info_file_path.is_file():
329+
logger.error(
330+
f" {VERSION_INFO_FILE_NAME} file doesn't exist at the provided path :{matlab_root}"
331+
)
332+
sys.exit(1)
333+
334+
return matlab_root

0 commit comments

Comments
 (0)