def test_generate_script_only_generates_once(tmpdir): """ Test defaults script generation """ script_path = cli_scripts.generate_script(tmpdir.strpath, "salt-foobar") with open(script_path) as rfh: contents = rfh.read() expected = textwrap.dedent("""\ #!{} from __future__ import absolute_import import os import sys # We really do not want buffered output os.environ[str("PYTHONUNBUFFERED")] = str("1") # Don't write .pyc files or create them in __pycache__ directories os.environ[str("PYTHONDONTWRITEBYTECODE")] = str("1") import atexit from salt.scripts import salt_foobar import salt.utils.platform def main(): if salt.utils.platform.is_windows(): import os.path import py_compile cfile = os.path.splitext(__file__)[0] + '.pyc' if not os.path.exists(cfile): py_compile.compile(__file__, cfile) salt_foobar() if __name__ == '__main__': exitcode = 0 try: main() except SystemExit as exc: exitcode = exc.code sys.stdout.flush() sys.stderr.flush() atexit._run_exitfuncs() os._exit(exitcode) """.format(sys.executable)) assert contents == expected statinfo_1 = os.stat(script_path) script_path = cli_scripts.generate_script(tmpdir.strpath, "salt-foobar") with open(script_path) as rfh: contents = rfh.read() assert contents == expected statinfo_2 = os.stat(script_path) assert statinfo_1 == statinfo_2
def get_salt_ssh_cli(self, factory_class=cli.ssh.SaltSshCliFactory, roster_file=None, target_host=None, client_key=None, ssh_user=None, **factory_class_kwargs): """ Return a `salt-ssh` CLI process for this master instance Args: roster_file(str): The roster file to use target_host(str): The target host address to connect to client_key(str): The path to the private ssh key to use to connect ssh_user(str): The remote username to connect as """ script_path = cli_scripts.generate_script( self.factories_manager.scripts_dir, "salt-ssh", code_dir=self.factories_manager.code_dir, inject_coverage=self.factories_manager.inject_coverage, inject_sitecustomize=self.factories_manager.inject_sitecustomize, ) return factory_class(cli_script_name=script_path, config=self.config.copy(), roster_file=roster_file, target_host=target_host, client_key=client_key, ssh_user=ssh_user or running_username(), **factory_class_kwargs)
def get_salt_call_cli(self, minion_id, cli_class=salt_factories.SaltCallCLI, **cli_kwargs): """ Return a `salt-call` CLI process """ script_path = cli_scripts.generate_script( self.scripts_dir, "salt-call", executable=self.executable, code_dir=self.code_dir, inject_coverage=self.inject_coverage, inject_sitecustomize=self.inject_sitecustomize, ) try: return cli_class( script_path, config=self.cache["configs"]["minions"][minion_id], **cli_kwargs) except KeyError: try: return cli_class( script_path, base_script_args=["--proxyid={}".format(minion_id)], config=self.cache["proxy_minions"][minion_id].config, **cli_kwargs, ) except KeyError: raise KeyError( "Could not find {} in the minions or proxy minions caches". format(minion_id))
def test_exit_status_unknown_user(request, salt_factories, shell_tests_salt_master_config): """ Ensure correct exit status when the master is configured to run as an unknown user. """ script_path = cli_scripts.generate_script( salt_factories.scripts_dir, "salt-master", code_dir=salt_factories.code_dir, inject_coverage=salt_factories.inject_coverage, inject_sitecustomize=salt_factories.inject_sitecustomize, ) proc = MasterFactory(cli_script_name=script_path, config=shell_tests_salt_master_config) proc.start() iterations = salt_factories.start_timeout while proc.is_running(): if not iterations: # pragma: no cover break time.sleep(1) iterations -= 1 ret = proc.terminate() assert ret.exitcode == salt.defaults.exitcodes.EX_NOUSER, ret assert "The user is not available." in ret.stderr, ret # Now spawn_<daemon> should behave the same with pytest.raises(FactoryNotStarted) as exc: salt_factories.spawn_master(request, shell_tests_salt_master_config["id"], max_start_attempts=1) assert exc.value.exitcode == salt.defaults.exitcodes.EX_NOUSER, str( exc.value) assert "The user is not available." in exc.value.stderr, str(exc.value)
def test_generate_script_salt(tmpdir): """ Test script generation for the salt CLI script """ script_path = cli_scripts.generate_script(tmpdir.strpath, "salt") with open(script_path) as rfh: contents = rfh.read() expected = textwrap.dedent("""\ #!{} from __future__ import absolute_import import os import sys # We really do not want buffered output os.environ[str("PYTHONUNBUFFERED")] = str("1") # Don't write .pyc files or create them in __pycache__ directories os.environ[str("PYTHONDONTWRITEBYTECODE")] = str("1") import atexit from salt.scripts import salt_main if __name__ == '__main__': exitcode = 0 try: salt_main() except SystemExit as exc: exitcode = exc.code sys.stdout.flush() sys.stderr.flush() atexit._run_exitfuncs() os._exit(exitcode) """.format(sys.executable)) assert contents == expected
def salt_minion_script_path(salt_factories): return cli_scripts.generate_script( salt_factories.scripts_dir, "salt-minion", code_dir=salt_factories.code_dir, inject_coverage=salt_factories.inject_coverage, inject_sitecustomize=salt_factories.inject_sitecustomize, )
def test_generate_script_creates_missing_bin_dir(tmpdir): """ Test defaults script generation """ script_path = cli_scripts.generate_script(tmpdir.join("blah").strpath, "salt-foobar") with open(script_path) as rfh: contents = rfh.read() expected = textwrap.dedent( """\ from __future__ import absolute_import import os import sys # We really do not want buffered output os.environ[str("PYTHONUNBUFFERED")] = str("1") # Don't write .pyc files or create them in __pycache__ directories os.environ[str("PYTHONDONTWRITEBYTECODE")] = str("1") import atexit import traceback from salt.scripts import salt_foobar def main(): if sys.platform.startswith("win"): import os.path import py_compile cfile = os.path.splitext(__file__)[0] + '.pyc' if not os.path.exists(cfile): py_compile.compile(__file__, cfile) salt_foobar() if __name__ == '__main__': exitcode = 0 try: main() except SystemExit as exc: exitcode = exc.code # https://docs.python.org/3/library/exceptions.html#SystemExit if exitcode is None: exitcode = 0 if not isinstance(exitcode, int): # A string?! sys.stderr.write(exitcode) exitcode = 1 except Exception as exc: sys.stderr.write( "An un-handled exception was caught: " + str(exc) + "\\n" + traceback.format_exc() ) exitcode = 1 sys.stdout.flush() sys.stderr.flush() atexit._run_exitfuncs() os._exit(exitcode) """ ) assert contents == expected assert os.path.isdir(tmpdir.join("blah").strpath)
def test_generate_script_salt_api(tmpdir): """ Test script generation for the salt-api CLI script """ script_path = cli_scripts.generate_script(tmpdir.strpath, "salt-api") with open(script_path) as rfh: contents = rfh.read() expected = textwrap.dedent( """\ from __future__ import absolute_import import os import sys # We really do not want buffered output os.environ[str("PYTHONUNBUFFERED")] = str("1") # Don't write .pyc files or create them in __pycache__ directories os.environ[str("PYTHONDONTWRITEBYTECODE")] = str("1") import atexit import traceback import salt.cli.api import salt.utils.process salt.utils.process.notify_systemd() def main(): sapi = salt.cli.api.SaltAPI() sapi.start() if __name__ == '__main__': exitcode = 0 try: main() except SystemExit as exc: exitcode = exc.code # https://docs.python.org/3/library/exceptions.html#SystemExit if exitcode is None: exitcode = 0 if not isinstance(exitcode, int): # A string?! sys.stderr.write(exitcode) exitcode = 1 except Exception as exc: sys.stderr.write( "An un-handled exception was caught: " + str(exc) + "\\n" + traceback.format_exc() ) exitcode = 1 sys.stdout.flush() sys.stderr.flush() atexit._run_exitfuncs() os._exit(exitcode) """ ) assert contents == expected
def get_salt_script_path(self, script_name): """ Return the path to the customized script path, generating one if needed. """ return cli_scripts.generate_script( self.scripts_dir, script_name, code_dir=self.code_dir, inject_coverage=self.inject_coverage, inject_sitecustomize=self.inject_sitecustomize, )
def test_generate_script_long_executable(tmpdir): """ Test that long executable paths get converted to `/usr/bin/env python` """ executable = sys.executable while len(executable) <= 128: executable += executable script_path = cli_scripts.generate_script(tmpdir.strpath, "salt-foobar", executable=executable) with open(script_path) as rfh: contents = rfh.read() expected = textwrap.dedent("""\ #!/usr/bin/env python from __future__ import absolute_import import os import sys # We really do not want buffered output os.environ[str("PYTHONUNBUFFERED")] = str("1") # Don't write .pyc files or create them in __pycache__ directories os.environ[str("PYTHONDONTWRITEBYTECODE")] = str("1") import atexit from salt.scripts import salt_foobar import salt.utils.platform def main(): if salt.utils.platform.is_windows(): import os.path import py_compile cfile = os.path.splitext(__file__)[0] + '.pyc' if not os.path.exists(cfile): py_compile.compile(__file__, cfile) salt_foobar() if __name__ == '__main__': exitcode = 0 try: main() except SystemExit as exc: exitcode = exc.code sys.stdout.flush() sys.stderr.flush() atexit._run_exitfuncs() os._exit(exitcode) """) assert contents == expected
def get_script_path(bin_dir, script_name): """ Return the path to a testing runtime script, generating one if it does not yet exist """ # Late import from tests.support.runtests import RUNTIME_VARS if not os.path.isdir(bin_dir): os.makedirs(bin_dir) cli_script_name = "cli_{}.py".format(script_name.replace("-", "_")) script_path = os.path.join(bin_dir, cli_script_name) if not os.path.isfile(script_path): generate_script( bin_dir=bin_dir, script_name=script_name, code_dir=RUNTIME_VARS.CODE_DIR, inject_coverage="COVERAGE_PROCESS_START" in os.environ, inject_sitecustomize="COVERAGE_PROCESS_START" in os.environ, ) log.info("Returning script path %r", script_path) return script_path
def test_generate_script_code_dir(tmpdir): """ Test code_dir inclusion in script generation """ code_dir = tmpdir.mkdir("code-dir").strpath script_path = cli_scripts.generate_script(tmpdir.strpath, "salt-foobar", code_dir=code_dir) with open(script_path) as rfh: contents = rfh.read() expected = textwrap.dedent("""\ from __future__ import absolute_import import os import sys # We really do not want buffered output os.environ[str("PYTHONUNBUFFERED")] = str("1") # Don't write .pyc files or create them in __pycache__ directories os.environ[str("PYTHONDONTWRITEBYTECODE")] = str("1") CODE_DIR = r'{}' if CODE_DIR in sys.path: sys.path.remove(CODE_DIR) sys.path.insert(0, CODE_DIR) import atexit from salt.scripts import salt_foobar def main(): if sys.platform.startswith("win"): import os.path import py_compile cfile = os.path.splitext(__file__)[0] + '.pyc' if not os.path.exists(cfile): py_compile.compile(__file__, cfile) salt_foobar() if __name__ == '__main__': exitcode = 0 try: main() except SystemExit as exc: exitcode = exc.code sys.stdout.flush() sys.stderr.flush() atexit._run_exitfuncs() os._exit(exitcode) """.format(code_dir)) assert contents == expected
def salt_cloud_cli( self, defaults=None, overrides=None, factory_class=cli.cloud.SaltCloud, **factory_class_kwargs ): """ Return a salt-cloud CLI instance Args: defaults(dict): A dictionary of default configuration to use when configuring the minion overrides(dict): A dictionary of configuration overrides to use when configuring the minion Returns: :py:class:`~saltfactories.cli.cloud.SaltCloud`: The salt-cloud CLI script process class instance """ root_dir = pathlib.Path(self.config["root_dir"]) config = factory_class.configure( self, self.id, root_dir=root_dir, defaults=defaults, overrides=overrides, ) self.factories_manager.final_cloud_config_tweaks(config) config = factory_class.write_config(config) if self.system_install is False: script_path = cli_scripts.generate_script( self.factories_manager.scripts_dir, "salt-cloud", code_dir=self.factories_manager.code_dir, inject_coverage=self.factories_manager.inject_coverage, inject_sitecustomize=self.factories_manager.inject_sitecustomize, ) else: script_path = shutil.which("salt-cloud") return factory_class( script_name=script_path, config=config, system_install=self.factories_manager.system_install, **factory_class_kwargs )
def get_salt_spm_cli(self, factory_class=cli.spm.SpmCliFactory, **factory_class_kwargs): """ Return a `spm` CLI process for this master instance """ script_path = cli_scripts.generate_script( self.factories_manager.scripts_dir, "spm", code_dir=self.factories_manager.code_dir, inject_coverage=self.factories_manager.inject_coverage, inject_sitecustomize=self.factories_manager.inject_sitecustomize, ) return factory_class(cli_script_name=script_path, config=self.config.copy(), **factory_class_kwargs)
def get_salt_call_cli(self, factory_class=cli.call.SaltCallCliFactory, **factory_class_kwargs): """ Return a `salt-call` CLI process for this minion instance """ script_path = cli_scripts.generate_script( self.factories_manager.scripts_dir, "salt-call", code_dir=self.factories_manager.code_dir, inject_coverage=self.factories_manager.inject_coverage, inject_sitecustomize=self.factories_manager.inject_sitecustomize, ) return factory_class(cli_script_name=script_path, config=self.config.copy(), **factory_class_kwargs)
def get_salt_run_cli(self, master_id, cli_class=salt_factories.SaltRunCLI, **cli_kwargs): """ Return a `salt-run` CLI process """ script_path = cli_scripts.generate_script( self.scripts_dir, "salt-run", executable=self.executable, code_dir=self.code_dir, inject_coverage=self.inject_coverage, inject_sitecustomize=self.inject_sitecustomize, ) return cli_class(script_path, config=self.cache["configs"]["masters"][master_id], **cli_kwargs)
def salt_spm_cli(self, factory_class=cli.spm.Spm, **factory_class_kwargs): """ Return a `spm` CLI process for this master instance """ if self.system_install is False: script_path = cli_scripts.generate_script( self.factories_manager.scripts_dir, "spm", code_dir=self.factories_manager.code_dir, inject_coverage=self.factories_manager.inject_coverage, inject_sitecustomize=self.factories_manager. inject_sitecustomize, ) else: script_path = shutil.which("spm") return factory_class( script_name=script_path, config=self.config.copy(), system_install=self.factories_manager.system_install, **factory_class_kwargs)
def get_salt_cloud_cli(self, config_defaults=None, config_overrides=None, factory_class=cli.cloud.SaltCloudFactory, **factory_class_kwargs): """ Return a salt-cloud CLI instance Args: config_defaults(dict): A dictionary of default configuration to use when configuring the minion config_overrides(dict): A dictionary of configuration overrides to use when configuring the minion Returns: :py:class:`~saltfactories.factories.cli.cloud.SaltCloudFactory`: The salt-cloud CLI script process class instance """ root_dir = pathlib.Path(self.config["root_dir"]) config = factory_class.configure( self, self.id, root_dir=root_dir, config_defaults=config_defaults, config_overrides=config_overrides, ) self.factories_manager.final_cloud_config_tweaks(config) config = factory_class.write_config(config) script_path = cli_scripts.generate_script( self.factories_manager.scripts_dir, "salt-cloud", code_dir=self.factories_manager.code_dir, inject_coverage=self.factories_manager.inject_coverage, inject_sitecustomize=self.factories_manager.inject_sitecustomize, ) return factory_class(cli_script_name=script_path, config=config, **factory_class_kwargs)
def salt_call_cli(self, factory_class=cli.call.SaltCall, **factory_class_kwargs): """ Return a `salt-call` CLI process for this minion instance """ if self.system_install is False: script_path = cli_scripts.generate_script( self.factories_manager.scripts_dir, "salt-call", code_dir=self.factories_manager.code_dir, inject_coverage=self.factories_manager.inject_coverage, inject_sitecustomize=self.factories_manager.inject_sitecustomize, ) else: script_path = shutil.which("salt-call") return factory_class( script_name=script_path, config=self.config.copy(), base_script_args=["--proxyid={}".format(self.id)], system_install=self.factories_manager.system_install, **factory_class_kwargs )
def test_generate_script_salt_api(tmpdir): """ Test script generation for the salt-api CLI script """ script_path = cli_scripts.generate_script(tmpdir.strpath, "salt-api") with open(script_path) as rfh: contents = rfh.read() expected = textwrap.dedent("""\ from __future__ import absolute_import import os import sys # We really do not want buffered output os.environ[str("PYTHONUNBUFFERED")] = str("1") # Don't write .pyc files or create them in __pycache__ directories os.environ[str("PYTHONDONTWRITEBYTECODE")] = str("1") import atexit import salt.cli.api import salt.utils.process salt.utils.process.notify_systemd() def main(): sapi = salt.cli.api.SaltAPI() sapi.start() if __name__ == '__main__': exitcode = 0 try: main() except SystemExit as exc: exitcode = exc.code sys.stdout.flush() sys.stderr.flush() atexit._run_exitfuncs() os._exit(exitcode) """) assert contents == expected
def _start_daemon(self, request, script_name, daemon_config, daemon_class, cache_key, daemon_id, max_start_attempts=3, **extra_daemon_class_kwargs): """ Helper method to start daemons """ script_path = cli_scripts.generate_script( self.scripts_dir, script_name, executable=self.executable, code_dir=self.code_dir, inject_coverage=self.inject_coverage, inject_sitecustomize=self.inject_sitecustomize, ) proc = saltfactories.utils.processes.helpers.start_daemon( script_path, daemon_class, config=daemon_config, start_timeout=self.start_timeout, slow_stop=self.slow_stop, environ=self.environ, cwd=self.cwd, max_attempts=max_start_attempts, event_listener=self.event_listener, salt_factories=self, **extra_daemon_class_kwargs, ) self.cache[cache_key][daemon_id] = proc if self.stats_processes: self.stats_processes[proc.get_display_name()] = psutil.Process( proc.pid) request.addfinalizer(proc.terminate) request.addfinalizer(lambda: self.cache[cache_key].pop(daemon_id)) return proc
def test_generate_script_inject_coverage(tmpdir): """ Test coverage related code included in script generation """ # If code_dir is not passed, assert that we fail with pytest.raises(RuntimeError): cli_scripts.generate_script(tmpdir.strpath, "salt-foobar-fail", inject_coverage=True) code_dir = tmpdir.mkdir("code-dir").strpath script_path = cli_scripts.generate_script(tmpdir.strpath, "salt-foobar", code_dir=code_dir, inject_coverage=True) with open(script_path) as rfh: contents = rfh.read() expected = textwrap.dedent("""\ #!{} from __future__ import absolute_import import os import sys # We really do not want buffered output os.environ[str("PYTHONUNBUFFERED")] = str("1") # Don't write .pyc files or create them in __pycache__ directories os.environ[str("PYTHONDONTWRITEBYTECODE")] = str("1") CODE_DIR = r'{}' if CODE_DIR in sys.path: sys.path.remove(CODE_DIR) sys.path.insert(0, CODE_DIR) # Setup coverage environment variables COVERAGE_FILE = os.path.join(CODE_DIR, '.coverage') COVERAGE_PROCESS_START = os.path.join(CODE_DIR, '.coveragerc') os.environ[str('COVERAGE_FILE')] = str(COVERAGE_FILE) os.environ[str('COVERAGE_PROCESS_START')] = str(COVERAGE_PROCESS_START) import atexit from salt.scripts import salt_foobar import salt.utils.platform def main(): if salt.utils.platform.is_windows(): import os.path import py_compile cfile = os.path.splitext(__file__)[0] + '.pyc' if not os.path.exists(cfile): py_compile.compile(__file__, cfile) salt_foobar() if __name__ == '__main__': exitcode = 0 try: main() except SystemExit as exc: exitcode = exc.code sys.stdout.flush() sys.stderr.flush() atexit._run_exitfuncs() os._exit(exitcode) """.format(sys.executable, code_dir)) assert contents == expected
def test_generate_script_inject_coverage(tmpdir): """ Test coverage related code included in script generation """ # If code_dir is not passed, assert that we fail with pytest.raises(pytest.UsageError): cli_scripts.generate_script(tmpdir.strpath, "salt-foobar-fail", inject_coverage=True) code_dir = tmpdir.mkdir("code-dir").strpath script_path = cli_scripts.generate_script(tmpdir.strpath, "salt-foobar", code_dir=code_dir, inject_coverage=True) with open(script_path) as rfh: contents = rfh.read() expected = textwrap.dedent("""\ from __future__ import absolute_import import os import sys # We really do not want buffered output os.environ[str("PYTHONUNBUFFERED")] = str("1") # Don't write .pyc files or create them in __pycache__ directories os.environ[str("PYTHONDONTWRITEBYTECODE")] = str("1") CODE_DIR = r'{}' if CODE_DIR in sys.path: sys.path.remove(CODE_DIR) sys.path.insert(0, CODE_DIR) # Setup coverage environment variables COVERAGE_FILE = os.path.join(CODE_DIR, '.coverage') COVERAGE_PROCESS_START = os.path.join(CODE_DIR, '.coveragerc') os.environ[str('COVERAGE_FILE')] = str(COVERAGE_FILE) os.environ[str('COVERAGE_PROCESS_START')] = str(COVERAGE_PROCESS_START) import atexit import traceback from salt.scripts import salt_foobar def main(): if sys.platform.startswith("win"): import os.path import py_compile cfile = os.path.splitext(__file__)[0] + '.pyc' if not os.path.exists(cfile): py_compile.compile(__file__, cfile) salt_foobar() if __name__ == '__main__': exitcode = 0 try: main() except SystemExit as exc: exitcode = exc.code # https://docs.python.org/3/library/exceptions.html#SystemExit if exitcode is None: exitcode = 0 if not isinstance(exitcode, int): # A string?! sys.stderr.write(exitcode) exitcode = 1 except Exception as exc: sys.stderr.write( "An un-handled exception was caught: " + str(exc) + "\\n" + traceback.format_exc() ) exitcode = 1 sys.stdout.flush() sys.stderr.flush() atexit._run_exitfuncs() os._exit(exitcode) """.format(code_dir)) assert contents == expected
def test_generate_script_inject_sitecustomize(tmpdir): """ Test sitecustomize injection related code included in script generation """ sitecustomize_path = pathlib.Path( cli_scripts.__file__).resolve().parent / "coverage" code_dir = tmpdir.mkdir("code-dir").strpath script_path = cli_scripts.generate_script( tmpdir.strpath, "salt-foobar", code_dir=code_dir, inject_coverage=True, inject_sitecustomize=True, ) with open(script_path) as rfh: contents = rfh.read() expected = textwrap.dedent("""\ from __future__ import absolute_import import os import sys # We really do not want buffered output os.environ[str("PYTHONUNBUFFERED")] = str("1") # Don't write .pyc files or create them in __pycache__ directories os.environ[str("PYTHONDONTWRITEBYTECODE")] = str("1") CODE_DIR = r'{}' if CODE_DIR in sys.path: sys.path.remove(CODE_DIR) sys.path.insert(0, CODE_DIR) # Setup coverage environment variables COVERAGE_FILE = os.path.join(CODE_DIR, '.coverage') COVERAGE_PROCESS_START = os.path.join(CODE_DIR, '.coveragerc') os.environ[str('COVERAGE_FILE')] = str(COVERAGE_FILE) os.environ[str('COVERAGE_PROCESS_START')] = str(COVERAGE_PROCESS_START) # Allow sitecustomize.py to be importable for test coverage purposes SITECUSTOMIZE_DIR = r'{}' PYTHONPATH = os.environ.get('PYTHONPATH') or None if PYTHONPATH is None: PYTHONPATH_ENV_VAR = SITECUSTOMIZE_DIR else: PYTHON_PATH_ENTRIES = PYTHONPATH.split(os.pathsep) if SITECUSTOMIZE_DIR in PYTHON_PATH_ENTRIES: PYTHON_PATH_ENTRIES.remove(SITECUSTOMIZE_DIR) PYTHON_PATH_ENTRIES.insert(0, SITECUSTOMIZE_DIR) PYTHONPATH_ENV_VAR = os.pathsep.join(PYTHON_PATH_ENTRIES) os.environ[str('PYTHONPATH')] = str(PYTHONPATH_ENV_VAR) if SITECUSTOMIZE_DIR in sys.path: sys.path.remove(SITECUSTOMIZE_DIR) sys.path.insert(0, SITECUSTOMIZE_DIR) import atexit import traceback from salt.scripts import salt_foobar def main(): if sys.platform.startswith("win"): import os.path import py_compile cfile = os.path.splitext(__file__)[0] + '.pyc' if not os.path.exists(cfile): py_compile.compile(__file__, cfile) salt_foobar() if __name__ == '__main__': exitcode = 0 try: main() except SystemExit as exc: exitcode = exc.code # https://docs.python.org/3/library/exceptions.html#SystemExit if exitcode is None: exitcode = 0 if not isinstance(exitcode, int): # A string?! sys.stderr.write(exitcode) exitcode = 1 except Exception as exc: sys.stderr.write( "An un-handled exception was caught: " + str(exc) + "\\n" + traceback.format_exc() ) exitcode = 1 sys.stdout.flush() sys.stderr.flush() atexit._run_exitfuncs() os._exit(exitcode) """.format(code_dir, str(sitecustomize_path))) assert contents == expected script_path = cli_scripts.generate_script(tmpdir.strpath, "salt-foobar-2", inject_sitecustomize=True) with open(script_path) as rfh: contents = rfh.read() expected = textwrap.dedent("""\ from __future__ import absolute_import import os import sys # We really do not want buffered output os.environ[str("PYTHONUNBUFFERED")] = str("1") # Don't write .pyc files or create them in __pycache__ directories os.environ[str("PYTHONDONTWRITEBYTECODE")] = str("1") # Allow sitecustomize.py to be importable for test coverage purposes SITECUSTOMIZE_DIR = r'{}' PYTHONPATH = os.environ.get('PYTHONPATH') or None if PYTHONPATH is None: PYTHONPATH_ENV_VAR = SITECUSTOMIZE_DIR else: PYTHON_PATH_ENTRIES = PYTHONPATH.split(os.pathsep) if SITECUSTOMIZE_DIR in PYTHON_PATH_ENTRIES: PYTHON_PATH_ENTRIES.remove(SITECUSTOMIZE_DIR) PYTHON_PATH_ENTRIES.insert(0, SITECUSTOMIZE_DIR) PYTHONPATH_ENV_VAR = os.pathsep.join(PYTHON_PATH_ENTRIES) os.environ[str('PYTHONPATH')] = str(PYTHONPATH_ENV_VAR) if SITECUSTOMIZE_DIR in sys.path: sys.path.remove(SITECUSTOMIZE_DIR) sys.path.insert(0, SITECUSTOMIZE_DIR) import atexit import traceback from salt.scripts import salt_foobar_2 def main(): if sys.platform.startswith("win"): import os.path import py_compile cfile = os.path.splitext(__file__)[0] + '.pyc' if not os.path.exists(cfile): py_compile.compile(__file__, cfile) salt_foobar_2() if __name__ == '__main__': exitcode = 0 try: main() except SystemExit as exc: exitcode = exc.code # https://docs.python.org/3/library/exceptions.html#SystemExit if exitcode is None: exitcode = 0 if not isinstance(exitcode, int): # A string?! sys.stderr.write(exitcode) exitcode = 1 except Exception as exc: sys.stderr.write( "An un-handled exception was caught: " + str(exc) + "\\n" + traceback.format_exc() ) exitcode = 1 sys.stdout.flush() sys.stderr.flush() atexit._run_exitfuncs() os._exit(exitcode) """.format(str(sitecustomize_path))) assert contents == expected
def test_generate_script_inject_sitecustomize(tmpdir): """ Test sitecustomize injection related code included in script generation """ sitecustomize_path = os.path.join(os.path.dirname(cli_scripts.__file__), "coverage") code_dir = tmpdir.mkdir("code-dir").strpath script_path = cli_scripts.generate_script( tmpdir.strpath, "salt-foobar", code_dir=code_dir, inject_coverage=True, inject_sitecustomize=True, ) with open(script_path) as rfh: contents = rfh.read() expected = textwrap.dedent("""\ #!{} from __future__ import absolute_import import os import sys # We really do not want buffered output os.environ[str("PYTHONUNBUFFERED")] = str("1") # Don't write .pyc files or create them in __pycache__ directories os.environ[str("PYTHONDONTWRITEBYTECODE")] = str("1") CODE_DIR = r'{}' if CODE_DIR in sys.path: sys.path.remove(CODE_DIR) sys.path.insert(0, CODE_DIR) # Setup coverage environment variables COVERAGE_FILE = os.path.join(CODE_DIR, '.coverage') COVERAGE_PROCESS_START = os.path.join(CODE_DIR, '.coveragerc') os.environ[str('COVERAGE_FILE')] = str(COVERAGE_FILE) os.environ[str('COVERAGE_PROCESS_START')] = str(COVERAGE_PROCESS_START) # Allow sitecustomize.py to be importable for test coverage purposes SITECUSTOMIZE_DIR = r'{}' PYTHONPATH = os.environ.get('PYTHONPATH') or None if PYTHONPATH is None: PYTHONPATH_ENV_VAR = SITECUSTOMIZE_DIR else: PYTHON_PATH_ENTRIES = PYTHONPATH.split(os.pathsep) if SITECUSTOMIZE_DIR in PYTHON_PATH_ENTRIES: PYTHON_PATH_ENTRIES.remove(SITECUSTOMIZE_DIR) PYTHON_PATH_ENTRIES.insert(0, SITECUSTOMIZE_DIR) PYTHONPATH_ENV_VAR = os.pathsep.join(PYTHON_PATH_ENTRIES) os.environ[str('PYTHONPATH')] = str(PYTHONPATH_ENV_VAR) if SITECUSTOMIZE_DIR in sys.path: sys.path.remove(SITECUSTOMIZE_DIR) sys.path.insert(0, SITECUSTOMIZE_DIR) import atexit from salt.scripts import salt_foobar import salt.utils.platform def main(): if salt.utils.platform.is_windows(): import os.path import py_compile cfile = os.path.splitext(__file__)[0] + '.pyc' if not os.path.exists(cfile): py_compile.compile(__file__, cfile) salt_foobar() if __name__ == '__main__': exitcode = 0 try: main() except SystemExit as exc: exitcode = exc.code sys.stdout.flush() sys.stderr.flush() atexit._run_exitfuncs() os._exit(exitcode) """.format(sys.executable, code_dir, sitecustomize_path)) assert contents == expected script_path = cli_scripts.generate_script(tmpdir.strpath, "salt-foobar-2", inject_sitecustomize=True) with open(script_path) as rfh: contents = rfh.read() expected = textwrap.dedent("""\ #!{} from __future__ import absolute_import import os import sys # We really do not want buffered output os.environ[str("PYTHONUNBUFFERED")] = str("1") # Don't write .pyc files or create them in __pycache__ directories os.environ[str("PYTHONDONTWRITEBYTECODE")] = str("1") # Allow sitecustomize.py to be importable for test coverage purposes SITECUSTOMIZE_DIR = r'{}' PYTHONPATH = os.environ.get('PYTHONPATH') or None if PYTHONPATH is None: PYTHONPATH_ENV_VAR = SITECUSTOMIZE_DIR else: PYTHON_PATH_ENTRIES = PYTHONPATH.split(os.pathsep) if SITECUSTOMIZE_DIR in PYTHON_PATH_ENTRIES: PYTHON_PATH_ENTRIES.remove(SITECUSTOMIZE_DIR) PYTHON_PATH_ENTRIES.insert(0, SITECUSTOMIZE_DIR) PYTHONPATH_ENV_VAR = os.pathsep.join(PYTHON_PATH_ENTRIES) os.environ[str('PYTHONPATH')] = str(PYTHONPATH_ENV_VAR) if SITECUSTOMIZE_DIR in sys.path: sys.path.remove(SITECUSTOMIZE_DIR) sys.path.insert(0, SITECUSTOMIZE_DIR) import atexit from salt.scripts import salt_foobar_2 import salt.utils.platform def main(): if salt.utils.platform.is_windows(): import os.path import py_compile cfile = os.path.splitext(__file__)[0] + '.pyc' if not os.path.exists(cfile): py_compile.compile(__file__, cfile) salt_foobar_2() if __name__ == '__main__': exitcode = 0 try: main() except SystemExit as exc: exitcode = exc.code sys.stdout.flush() sys.stderr.flush() atexit._run_exitfuncs() os._exit(exitcode) """.format(sys.executable, sitecustomize_path)) assert contents == expected