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
Example #2
0
    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)
Example #3
0
 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))
Example #4
0
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
Example #6
0
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,
    )
Example #7
0
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)
Example #8
0
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
Example #9
0
 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
Example #11
0
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
Example #12
0
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
Example #13
0
    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
        )
Example #14
0
 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)
Example #15
0
 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)
Example #16
0
 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)
Example #18
0
    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)
Example #19
0
 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
     )
Example #20
0
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
Example #21
0
 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