From da23775c2524a3c544cbf4695316146f23644d05 Mon Sep 17 00:00:00 2001 From: Ondrej Samohel Date: Fri, 26 Mar 2021 16:45:15 +0100 Subject: [PATCH 1/5] win: run mongo script improvements --- tools/run_mongo.ps1 | 61 ++++++++++++++++++++++++--------------------- 1 file changed, 32 insertions(+), 29 deletions(-) diff --git a/tools/run_mongo.ps1 b/tools/run_mongo.ps1 index a72c8b1210..f04234d56a 100644 --- a/tools/run_mongo.ps1 +++ b/tools/run_mongo.ps1 @@ -37,37 +37,37 @@ function Exit-WithCode($exitcode) { function Find-Mongo { - Write-Host ">>> " -NoNewLine -ForegroundColor Green - Write-Host "Detecting MongoDB ... " -NoNewline - if (-not (Get-Command "mongod" -ErrorAction SilentlyContinue)) { - if(Test-Path 'C:\Program Files\MongoDB\Server\*\bin\mongod.exe' -PathType Leaf) { - # we have mongo server installed on standard Windows location - # so we can inject it to the PATH. We'll use latest version available. - $mongoVersions = Get-ChildItem -Directory 'C:\Program Files\MongoDB\Server' | Sort-Object -Property {$_.Name -as [int]} - if(Test-Path "$($mongoVersions[-1])\bin\mongod.exe" -PathType Leaf) { - $env:PATH="$($env:PATH);$($mongoVersions[-1])\bin\" - Write-Host "OK" -ForegroundColor Green - Write-Host " - auto-added from [ " -NoNewline - Write-Host "$($mongoVersions[-1])\bin\" -NoNewLine -ForegroundColor Cyan - Write-Host " ]" - } else { - Write-Host "FAILED " -NoNewLine -ForegroundColor Red - Write-Host "MongoDB not detected" -ForegroundColor Yellow - Write-Host "Tried to find it on standard location " -NoNewline -ForegroundColor Gray - Write-Host " [ " -NoNewline -ForegroundColor Cyan - Write-Host "$($mongoVersions[-1])\bin\" -NoNewline -ForegroundColor White - Write-Host " ] " -NonNewLine -ForegroundColor Cyan - Write-Host "but failed." -ForegroundColor Gray - Exit-WithCode 1 - } + $defaultPath = "C:\Program Files\MongoDB\Server" + Write-Host ">>> " -NoNewLine -ForegroundColor Green + Write-Host "Detecting MongoDB ... " -NoNewline + if (-not (Get-Command "mongod" -ErrorAction SilentlyContinue)) { + if(Test-Path "$($defaultPath)\*\bin\mongod.exe" -PathType Leaf) { + # we have mongo server installed on standard Windows location + # so we can inject it to the PATH. We'll use latest version available. + $mongoVersions = Get-ChildItem -Directory 'C:\Program Files\MongoDB\Server' | Sort-Object -Property {$_.Name -as [int]} + if(Test-Path "$($defaultPath)\$($mongoVersions[-1])\bin\mongod.exe" -PathType Leaf) { + $env:PATH="$($env:PATH);$($defaultPath)\$($mongoVersions[-1])\bin\" + Write-Host "OK" -ForegroundColor Green + Write-Host " - auto-added from [ " -NoNewline + Write-Host "$($defaultPath)\$($mongoVersions[-1])\bin\" -NoNewLine -ForegroundColor Cyan + Write-Host " ]" + } else { + Write-Host "FAILED " -NoNewLine -ForegroundColor Red + Write-Host "MongoDB not detected" -ForegroundColor Yellow + Write-Host "Tried to find it on standard location " -NoNewline -ForegroundColor Gray + Write-Host " [ " -NoNewline -ForegroundColor Cyan + Write-Host "$($defaultPath)\$($mongoVersions[-1])\bin\" -NoNewline -ForegroundColor White + Write-Host " ] " -NonNewLine -ForegroundColor Cyan + Write-Host "but failed." -ForegroundColor Gray + Exit-WithCode 1 + } } else { - Write-Host "FAILED " -NoNewLine -ForegroundColor Red - Write-Host "MongoDB not detected in PATH" -ForegroundColor Yellow - Exit-WithCode 1 + Write-Host "FAILED " -NoNewLine -ForegroundColor Red + Write-Host "MongoDB not detected in PATH" -ForegroundColor Yellow + Exit-WithCode 1 } - } else { - Write-Host "OK" -ForegroundColor Green + Write-Host "OK" -ForegroundColor Green } <# .SYNOPSIS @@ -90,4 +90,7 @@ $dbpath = (Get-Item $pype_root).parent.FullName + "\mongo_db_data" Find-Mongo $mongo = Get-Command "mongod" | Select-Object -ExpandProperty Definition -Start-Process -FilePath $mongo "--dbpath $($dbpath) --port $($port)" +$process = Start-Process -FilePath $mongo "--dbpath $($dbpath) --port $($port)" -PassThru -NoNewWindow -Wait +$process.WaitForExit() +Start-Process PowerShell -NoNewWindow -Wait + From b9a6e093abd0efe35b069b16d093948c1aa9f2da Mon Sep 17 00:00:00 2001 From: Ondrej Samohel Date: Fri, 26 Mar 2021 16:49:18 +0100 Subject: [PATCH 2/5] better handle connection errors to db --- start.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/start.py b/start.py index 8d60a14403..c231786797 100644 --- a/start.py +++ b/start.py @@ -100,6 +100,8 @@ import subprocess import site from pathlib import Path +from pymongo.errors import ServerSelectionTimeoutError + # add dependencies folder to sys.pat for frozen code if getattr(sys, 'frozen', False): frozen_libs = os.path.normpath( @@ -569,7 +571,13 @@ def boot(): # Get Pype path from database and set it to environment so Pype can # find its versions there and bootstrap them. - pype_path = get_pype_path_from_db(pype_mongo) + try: + pype_path = get_pype_path_from_db(pype_mongo) + except ServerSelectionTimeoutError as e: + print("!!! Can't connect to mongodb database server.") + print("!!! {}".format(e)) + sys.exit(1) + if not os.getenv("PYPE_PATH") and pype_path: os.environ["PYPE_PATH"] = pype_path From a427e96ecf34b6d03a9e71f35017c38af7c41836 Mon Sep 17 00:00:00 2001 From: Ondrej Samohel Date: Fri, 26 Mar 2021 17:04:27 +0100 Subject: [PATCH 3/5] fixed broken tests --- tests/igniter/test_bootstrap_repos.py | 16 ++++++++-------- tests/igniter/test_tools.py | 4 ---- 2 files changed, 8 insertions(+), 12 deletions(-) diff --git a/tests/igniter/test_bootstrap_repos.py b/tests/igniter/test_bootstrap_repos.py index 70edc5b89c..e1bdbffb30 100644 --- a/tests/igniter/test_bootstrap_repos.py +++ b/tests/igniter/test_bootstrap_repos.py @@ -145,18 +145,18 @@ def test_search_string_for_pype_version(printer): assert PypeVersion.version_in_str(ver_string[0])[0] == ver_string[1] +@pytest.mark.slow def test_install_live_repos(fix_bootstrap, printer): - rf = fix_bootstrap.create_version_from_live_code() + pype_version = fix_bootstrap.create_version_from_live_code() sep = os.path.sep expected_paths = [ - f"{rf}{sep}avalon-core", - f"{rf}{sep}avalon-unreal-integration", - f"{rf}{sep}maya-look-assigner", - f"{rf}{sep}pype" + f"{pype_version.path}{sep}avalon-core", + f"{pype_version.path}{sep}avalon-unreal-integration", + f"{pype_version.path}{sep}pype" ] printer("testing zip creation") - assert os.path.exists(rf), "zip archive was not created" - fix_bootstrap.add_paths_from_archive(rf) + assert os.path.exists(pype_version.path), "zip archive was not created" + fix_bootstrap.add_paths_from_archive(pype_version.path) for ep in expected_paths: assert ep in sys.path, f"{ep} not set correctly" @@ -168,7 +168,7 @@ def test_install_live_repos(fix_bootstrap, printer): print(pype.__file__) assert "pype" in sys.modules.keys(), "Pype not imported" assert sys.modules["pype"].__file__ == \ - f"{rf}{sep}pype{sep}pype{sep}__init__.py" + f"{pype_version.path}{sep}pype{sep}pype{sep}__init__.py" def test_find_pype(fix_bootstrap, tmp_path_factory, monkeypatch, printer): diff --git a/tests/igniter/test_tools.py b/tests/igniter/test_tools.py index b87900311a..0c7104f698 100644 --- a/tests/igniter/test_tools.py +++ b/tests/igniter/test_tools.py @@ -10,7 +10,3 @@ def test_validate_path_string(tmp_path): status2, _ = validate_path_string("booo" + str(uuid4())) assert status2 is False - # todo: change when Pype token is implemented - status3, reason = validate_path_string(str(uuid4())) - assert status3 is False - assert reason == "Not implemented yet" From 8d61529fb001c6aecdbb3b9c4903cf139ec8b721 Mon Sep 17 00:00:00 2001 From: Ondrej Samohel Date: Mon, 29 Mar 2021 13:55:43 +0200 Subject: [PATCH 4/5] mimic source hierarchy in zips for frozen and live code --- igniter/bootstrap_repos.py | 139 ++++++++++---------------- igniter/tools.py | 5 + start.py | 14 +-- tests/igniter/test_bootstrap_repos.py | 13 ++- 4 files changed, 71 insertions(+), 100 deletions(-) diff --git a/igniter/bootstrap_repos.py b/igniter/bootstrap_repos.py index 58d59afe88..2ef22ec4fa 100644 --- a/igniter/bootstrap_repos.py +++ b/igniter/bootstrap_repos.py @@ -242,7 +242,7 @@ class BootstrapRepos: self.registry = PypeSettingsRegistry() self.zip_filter = [".pyc", "__pycache__"] self.pype_filter = [ - "build", "docs", "tests", "repos", "tools", "venv" + "build", "docs", "tests", "tools", "venv", "coverage" ] self._message = message @@ -351,7 +351,7 @@ class BootstrapRepos: Path(temp_dir) / f"pype-v{version}.zip" self._print(f"creating zip: {temp_zip}") - self._create_pype_zip(temp_zip, repo_dir) + self._create_pype_zip(temp_zip, repo_dir.parent) if not os.path.exists(temp_zip): self._print("make archive failed.", LOG_ERROR) return None @@ -417,15 +417,14 @@ class BootstrapRepos: """ frozen_root = Path(sys.executable).parent - repo_dir = frozen_root / "repos" - repo_list = self._filter_dir( - repo_dir, self.zip_filter) # from frozen code we need igniter, pype, schema vendor pype_list = self._filter_dir( frozen_root / "pype", self.zip_filter) pype_list += self._filter_dir( frozen_root / "igniter", self.zip_filter) + pype_list += self._filter_dir( + frozen_root / "repos", self.zip_filter) pype_list += self._filter_dir( frozen_root / "schema", self.zip_filter) pype_list += self._filter_dir( @@ -443,17 +442,7 @@ class BootstrapRepos: with ZipFile(temp_zip, "w") as zip_file: progress = 0 - repo_inc = 48.0 / float(len(repo_list)) - file: Path - for file in repo_list: - progress += repo_inc - self._progress_callback(int(progress)) - - # archive name is relative to repos dir - arc_name = file.relative_to(repo_dir) - zip_file.write(file, arc_name) - - pype_inc = 48.0 / float(len(pype_list)) + pype_inc = 98.0 / float(len(pype_list)) file: Path for file in pype_list: progress += pype_inc @@ -463,17 +452,14 @@ class BootstrapRepos: # we need to replace first part of path which starts with # something like `exe.win/linux....` with `pype` as this # is expected by Pype in zip archive. - arc_name = Path("pype").joinpath(*arc_name.parts[1:]) + arc_name = Path().joinpath(*arc_name.parts[1:]) zip_file.write(file, arc_name) destination = self._move_zip_to_data_dir(temp_zip) return PypeVersion(version=version, path=destination) - def _create_pype_zip( - self, - zip_path: Path, include_dir: Path, - include_pype: bool = True) -> None: + def _create_pype_zip(self, zip_path: Path, pype_path: Path) -> None: """Pack repositories and Pype into zip. We are using :mod:`zipfile` instead :meth:`shutil.make_archive` @@ -482,70 +468,46 @@ class BootstrapRepos: and :attr:`pype_filter` on top level directory in Pype repository. Args: - zip_path (str): path to zip file. - include_dir (Path): repo directories to include. - include_pype (bool): add Pype module itself. + zip_path (Path): Path to zip file. + pype_path (Path): Path to Pype sources. """ - include_dir = include_dir.resolve() - pype_list = [] - # get filtered list of files in repositories (repos directory) - repo_list = self._filter_dir(include_dir, self.zip_filter) - # count them - repo_files = len(repo_list) - - # there must be some files, otherwise `include_dir` path is wrong - assert repo_files != 0, f"No repositories to include in {include_dir}" pype_inc = 0 - if include_pype: - # get filtered list of file in Pype repository - pype_list = self._filter_dir(include_dir.parent, self.zip_filter) - pype_files = len(pype_list) - repo_inc = 48.0 / float(repo_files) - pype_inc = 48.0 / float(pype_files) - else: - repo_inc = 98.0 / float(repo_files) + + # get filtered list of file in Pype repository + pype_list = self._filter_dir(pype_path, self.zip_filter) + pype_files = len(pype_list) + + pype_inc = 98.0 / float(pype_files) with ZipFile(zip_path, "w") as zip_file: progress = 0 + pype_root = pype_path.resolve() + # generate list of filtered paths + dir_filter = [pype_root / f for f in self.pype_filter] + file: Path - for file in repo_list: - progress += repo_inc + for file in pype_list: + progress += pype_inc self._progress_callback(int(progress)) - # archive name is relative to repos dir - arc_name = file.relative_to(include_dir) - zip_file.write(file, arc_name) + # if file resides in filtered path, skip it + is_inside = None + df: Path + for df in dir_filter: + try: + is_inside = file.resolve().relative_to(df) + except ValueError: + pass - # add pype itself - if include_pype: - pype_root = include_dir.parent.resolve() - # generate list of filtered paths - dir_filter = [pype_root / f for f in self.pype_filter] + if is_inside: + continue - file: Path - for file in pype_list: - progress += pype_inc - self._progress_callback(int(progress)) + processed_path = file + self._print(f"- processing {processed_path}") - # if file resides in filtered path, skip it - is_inside = None - df: Path - for df in dir_filter: - try: - is_inside = file.resolve().relative_to(df) - except ValueError: - pass - - if is_inside: - continue - - processed_path = file - self._print(f"- processing {processed_path}") - - zip_file.write(file, - "pype" / file.relative_to(pype_root)) + zip_file.write(file, file.relative_to(pype_root)) # test if zip is ok zip_file.testzip() @@ -553,10 +515,10 @@ class BootstrapRepos: @staticmethod def add_paths_from_archive(archive: Path) -> None: - """Add first-level directories as paths to :mod:`sys.path`. + """Add first-level directory and 'repos' as paths to :mod:`sys.path`. - This will enable Python to import modules is second-level directories - in zip file. + This will enable Python to import Pype and modules in `repos` + submodule directory in zip file. Adding to both `sys.path` and `PYTHONPATH`, skipping duplicates. @@ -574,21 +536,29 @@ class BootstrapRepos: name_list = zip_file.namelist() roots = [] + paths = [] for item in name_list: - root = item.split("/")[0] + if not item.startswith("repos/"): + continue + + root = item.split("/")[1] + if root not in roots: roots.append(root) - sys.path.insert(0, f"{archive}{os.path.sep}{root}") + paths.append( + f"{archive}{os.path.sep}repos{os.path.sep}{root}") + sys.path.insert(0, paths[-1]) + sys.path.insert(0, f"{archive}") pythonpath = os.getenv("PYTHONPATH", "") - paths = pythonpath.split(os.pathsep) - paths += roots + python_paths = pythonpath.split(os.pathsep) + python_paths += paths - os.environ["PYTHONPATH"] = os.pathsep.join(paths) + os.environ["PYTHONPATH"] = os.pathsep.join(python_paths) @staticmethod def add_paths_from_directory(directory: Path) -> None: - """Add first level directories as paths to :mod:`sys.path`. + """Add repos first level directories as paths to :mod:`sys.path`. This works the same as :meth:`add_paths_from_archive` but in specified directory. @@ -599,6 +569,8 @@ class BootstrapRepos: directory (Path): path to directory. """ + sys.path.insert(0, directory.as_posix()) + directory = directory / "repos" if not directory.exists() and not directory.is_dir(): raise ValueError("directory is invalid") @@ -937,8 +909,7 @@ class BootstrapRepos: try: # add one 'pype' level as inside dir there should # be many other repositories. - version_str = BootstrapRepos.get_version( - dir_item / "pype") + version_str = BootstrapRepos.get_version(dir_item) version_check = PypeVersion(version=version_str) except ValueError: self._print( @@ -979,7 +950,7 @@ class BootstrapRepos: try: with ZipFile(zip_item, "r") as zip_file: with zip_file.open( - "pype/pype/version.py") as version_file: + "pype/version.py") as version_file: zip_version = {} exec(version_file.read(), zip_version) version_check = PypeVersion( diff --git a/igniter/tools.py b/igniter/tools.py index 4ed4ae67f4..17e53a2b07 100644 --- a/igniter/tools.py +++ b/igniter/tools.py @@ -6,6 +6,7 @@ Functions ``compose_url()`` and ``decompose_url()`` are the same as in version is decided. """ +import sys from typing import Dict, Union from urllib.parse import urlparse, parse_qs from pathlib import Path @@ -244,6 +245,10 @@ def get_pype_path_from_db(url: str) -> Union[str, None]: try: client = MongoClient(**mongo_args) + except ServerSelectionTimeoutError as e: + print("!!! Can't connect to mongodb database server.") + print("!!! {}".format(e)) + return None except Exception: return None diff --git a/start.py b/start.py index c231786797..8553449489 100644 --- a/start.py +++ b/start.py @@ -100,7 +100,6 @@ import subprocess import site from pathlib import Path -from pymongo.errors import ServerSelectionTimeoutError # add dependencies folder to sys.pat for frozen code if getattr(sys, 'frozen', False): @@ -327,13 +326,12 @@ def _initialize_environment(pype_version: PypeVersion) -> None: # to same hierarchy from code and from frozen pype additional_paths = [ # add pype tools - os.path.join(os.environ["PYPE_ROOT"], "pype", "pype", "tools"), + os.path.join(os.environ["PYPE_ROOT"], "pype", "tools"), # add common pype vendor # (common for multiple Python interpreter versions) os.path.join( os.environ["PYPE_ROOT"], "pype", - "pype", "vendor", "python", "common" @@ -571,12 +569,10 @@ def boot(): # Get Pype path from database and set it to environment so Pype can # find its versions there and bootstrap them. - try: - pype_path = get_pype_path_from_db(pype_mongo) - except ServerSelectionTimeoutError as e: - print("!!! Can't connect to mongodb database server.") - print("!!! {}".format(e)) - sys.exit(1) + + pype_path = get_pype_path_from_db(pype_mongo) + if not pype_path: + print("*** Cannot get Pype path from database.") if not os.getenv("PYPE_PATH") and pype_path: os.environ["PYPE_PATH"] = pype_path diff --git a/tests/igniter/test_bootstrap_repos.py b/tests/igniter/test_bootstrap_repos.py index e1bdbffb30..75996b4026 100644 --- a/tests/igniter/test_bootstrap_repos.py +++ b/tests/igniter/test_bootstrap_repos.py @@ -150,9 +150,9 @@ def test_install_live_repos(fix_bootstrap, printer): pype_version = fix_bootstrap.create_version_from_live_code() sep = os.path.sep expected_paths = [ - f"{pype_version.path}{sep}avalon-core", - f"{pype_version.path}{sep}avalon-unreal-integration", - f"{pype_version.path}{sep}pype" + f"{pype_version.path}{sep}repos{sep}avalon-core", + f"{pype_version.path}{sep}repos{sep}avalon-unreal-integration", + f"{pype_version.path}" ] printer("testing zip creation") assert os.path.exists(pype_version.path), "zip archive was not created" @@ -165,10 +165,9 @@ def test_install_live_repos(fix_bootstrap, printer): import pype # noqa: F401 # test if pype is imported from specific location in zip - print(pype.__file__) assert "pype" in sys.modules.keys(), "Pype not imported" assert sys.modules["pype"].__file__ == \ - f"{pype_version.path}{sep}pype{sep}pype{sep}__init__.py" + f"{pype_version.path}{sep}pype{sep}__init__.py" def test_find_pype(fix_bootstrap, tmp_path_factory, monkeypatch, printer): @@ -252,7 +251,7 @@ def test_find_pype(fix_bootstrap, tmp_path_factory, monkeypatch, printer): def _create_valid_zip(path: Path, version: str): with ZipFile(path, "w") as zf: zf.writestr( - "pype/pype/version.py", f"__version__ = '{version}'\n\n") + "pype/version.py", f"__version__ = '{version}'\n\n") def _create_invalid_dir(path: Path): path.mkdir(parents=True, exist_ok=True) @@ -260,7 +259,7 @@ def test_find_pype(fix_bootstrap, tmp_path_factory, monkeypatch, printer): fp.write("invalid") def _create_valid_dir(path: Path, version: str): - pype_path = path / "pype" / "pype" + pype_path = path / "pype" version_path = pype_path / "version.py" pype_path.mkdir(parents=True, exist_ok=True) with open(version_path, "w") as fp: From 69962606eeece4da071ed47821e972ae98635f6c Mon Sep 17 00:00:00 2001 From: Ondrej Samohel Date: Mon, 29 Mar 2021 13:56:21 +0200 Subject: [PATCH 5/5] partially revert changes in run_mongo --- tools/run_mongo.ps1 | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/tools/run_mongo.ps1 b/tools/run_mongo.ps1 index f04234d56a..66bd2656b9 100644 --- a/tools/run_mongo.ps1 +++ b/tools/run_mongo.ps1 @@ -45,19 +45,20 @@ function Find-Mongo { # we have mongo server installed on standard Windows location # so we can inject it to the PATH. We'll use latest version available. $mongoVersions = Get-ChildItem -Directory 'C:\Program Files\MongoDB\Server' | Sort-Object -Property {$_.Name -as [int]} - if(Test-Path "$($defaultPath)\$($mongoVersions[-1])\bin\mongod.exe" -PathType Leaf) { - $env:PATH="$($env:PATH);$($defaultPath)\$($mongoVersions[-1])\bin\" + if(Test-Path "$($mongoVersions[-1])\bin\mongod.exe" -PathType Leaf) { + $env:PATH = "$($env:PATH);$($mongoVersions[-1])\bin\" Write-Host "OK" -ForegroundColor Green Write-Host " - auto-added from [ " -NoNewline - Write-Host "$($defaultPath)\$($mongoVersions[-1])\bin\" -NoNewLine -ForegroundColor Cyan + Write-Host "$($mongoVersions[-1])\bin\mongod.exe" -NoNewLine -ForegroundColor Cyan Write-Host " ]" + return "$($mongoVersions[-1])\bin\mongod.exe" } else { Write-Host "FAILED " -NoNewLine -ForegroundColor Red Write-Host "MongoDB not detected" -ForegroundColor Yellow Write-Host "Tried to find it on standard location " -NoNewline -ForegroundColor Gray Write-Host " [ " -NoNewline -ForegroundColor Cyan - Write-Host "$($defaultPath)\$($mongoVersions[-1])\bin\" -NoNewline -ForegroundColor White - Write-Host " ] " -NonNewLine -ForegroundColor Cyan + Write-Host "$($mongoVersions[-1])\bin\mongod.exe" -NoNewline -ForegroundColor White + Write-Host " ] " -NoNewLine -ForegroundColor Cyan Write-Host "but failed." -ForegroundColor Gray Exit-WithCode 1 } @@ -68,6 +69,7 @@ function Find-Mongo { } } else { Write-Host "OK" -ForegroundColor Green + return Get-Command "mongod" -ErrorAction SilentlyContinue } <# .SYNOPSIS @@ -88,9 +90,7 @@ $port = 2707 # path to database $dbpath = (Get-Item $pype_root).parent.FullName + "\mongo_db_data" -Find-Mongo -$mongo = Get-Command "mongod" | Select-Object -ExpandProperty Definition -$process = Start-Process -FilePath $mongo "--dbpath $($dbpath) --port $($port)" -PassThru -NoNewWindow -Wait -$process.WaitForExit() -Start-Process PowerShell -NoNewWindow -Wait +$mongoPath = Find-Mongo +Start-Process -FilePath $mongopath "--dbpath $($dbpath) --port $($port)" -PassThru +