Ejemplo n.º 1
0
def test_fetch_content_equals_file_content_from_nix_expression(
        network_file: NetworkFile, nix: Nix):
    fetch_content = network_file.fetch()

    nix_expression = "with builtins;"
    nix_expression += "let pkgs = import <nixpkgs> {};"
    nix_expression += f"fileContent = readFile ({network_file.nix_expression()});"
    nix_expression += " in "
    nix_expression += 'pkgs.writeTextFile { name = "test"; text = fileContent; }'
    with tempfile.TemporaryDirectory() as target_directory:
        target_file = os.path.join(target_directory, "result")
        nix.build_expression(nix_expression, out_link=target_file)
        with open(target_file) as f:
            nix_content = f.read()
    assert nix_content == fetch_content
Ejemplo n.º 2
0
def test_can_build_a_flake(tmpdir, nix: Nix):
    build_dir: Path = Path(str(tmpdir))
    out_link_path = build_dir / "result"
    flake_path = build_dir / "flake.nix"
    flake_path.write_text(
        """{
  description = "A flake for building Hello World";
  inputs.nixpkgs.url = github:NixOS/nixpkgs/nixos-20.03;
  outputs = { self, nixpkgs }: {
    defaultPackage.x86_64-linux = nixpkgs.legacyPackages.x86_64-linux.hello;
  };
}"""
    )
    nix.build_flake(flake_path / "..", out_link=out_link_path)
    completed_process = subprocess.run(str(out_link_path / "bin" / "hello"))
    assert completed_process.returncode == 0
Ejemplo n.º 3
0
def test_flake_with_packages_can_be_built(
    flake_renderer: FlakeRenderer,
    build_wheels,
    package_generator: PackageGenerator,
    generated_sources: Sources,
    result_path: Path,
    nix: Nix,
    flake_directory: Path,
) -> None:
    package_generator.generate_setuptools_package(name="package1")
    wheels = build_wheels(["package1"])
    flake_renderer.render_expression(
        packages_metadata=wheels,
        sources=generated_sources,
    )
    nix.build_flake(flake_directory, out_link=result_path)
    assert (result_path / "bin" / "python").exists()
Ejemplo n.º 4
0
def build_wheel(target_directory: Path, requirement: str) -> str:
    logger = StreamLogger(sys.stdout)
    requirement_parser = RequirementParser(logger=logger)
    package_directory: str = str(ROOT / "unittests" / "data")
    escaped_requirement = shlex.quote(requirement)
    target_directory = target_directory.resolve()
    with tempfile.TemporaryDirectory() as build_directory:
        os.chdir(str(build_directory))
        nix = Nix(logger=logger)
        nix.shell(
            command=
            f"pip wheel {escaped_requirement} --find-links {str(package_directory)} --no-deps",
            derivation_path=DERIVATION_PATH,
            nix_arguments=dict(),
        )
        try:
            parsed_requirement = requirement_parser.parse(requirement)
        except ParsingFailed:
            for path in os.listdir("."):
                if path.endswith(".whl"):
                    wheel_path = path
                    break
                else:
                    raise Exception("Build process did not produce .whl file")
        else:
            for path in os.listdir("."):
                if path.endswith(".whl") and parsed_requirement.name() in path:
                    wheel_path = path
                    break
                else:
                    raise Exception("Build process did not produce .whl file")

        target_file_name = os.path.basename(wheel_path)
        target_path = target_directory / target_file_name
        shutil.move(wheel_path, str(target_path))
    return target_file_name
Ejemplo n.º 5
0
def nix(logger):
    return Nix(logger)
Ejemplo n.º 6
0
 def nix(self) -> Nix:
     return Nix(
         nix_path=self.configuration.nix_path,
         executable_directory=self.configuration.nix_executable_directory,
         logger=self.logger(),
     )
Ejemplo n.º 7
0
def nix(logger: Logger) -> Nix:
    return Nix(logger)
Ejemplo n.º 8
0
def test_evaluate_nix_expression_raises_exception_when_executable_not_found(
        logger):
    nix = Nix(executable_directory="/does-not-exist", logger=logger)
    with pytest.raises(ExecutableNotFound):
        nix.evaluate_expression("true")
Ejemplo n.º 9
0
def nix_instance(tmpdir, logger):
    nix_path_addition = tmpdir.mkdir("testpath_exists")
    yield Nix(nix_path=["test_variable={}".format(str(nix_path_addition))],
              logger=logger)
Ejemplo n.º 10
0
 def setUp(self) -> None:
     self.logger = StreamLogger(output=sys.stdout)
     self.nix = Nix(logger=self.logger)
     self.assertNotEqual(self.name_of_testcase, "undefined")
     self.requirement_parser = RequirementParser(self.logger)
Ejemplo n.º 11
0
class IntegrationTest(TestCase):
    """Methods to implement for a valid test case:

    name_of_testcase
    requirements

    optional:

    setup_requires() -- default: []
    executables_for_testing() -- default: []
    extra_environment() -- default: dict()
    external_dependencies
    requirements_file_check(content) -- default: (lambda content: None)
    constraints
    code_for_testing
    python_version
    code_for_testing_filename
    explicit_build_directory
    dependencyGraph -- default {}: yaml that will be used as input for pypi2nix

    check_dependency_graph(
        self,
        dependency_graph: DependencyGraph,
        requirement_parser: RequirementParser
    ):
        Override this function in your test case to perform checks on the
        dependency graph information that pypi2nix renders.  You can use
        the requirement_parser supplied though the method argument to
        generate Requirement objects. For example::
            django = requirement_parser.parse('django')
            pytz = requirement_parser.parse('pytz')

        If we wanted to check that pypi2nix detected the dependency of django
        on the pytz package than we could do it the following way:
            self.assertTrue(
                dependency_graph.is_runtime_dependency(
                    dependent=django,
                    dependency=pytz,
                )
            )
    """
    def setUp(self) -> None:
        self.logger = StreamLogger(output=sys.stdout)
        self.nix = Nix(logger=self.logger)
        self.assertNotEqual(self.name_of_testcase, "undefined")
        self.requirement_parser = RequirementParser(self.logger)

    def test_build_example(self) -> None:
        self.build_pypi2nix()
        self.generate_requirements_file()
        self.build_nix_expression()
        self.check_requirements_file_content()
        self.run_expression_tests()
        self.run_dependency_graph_tests()

    def build_pypi2nix(self) -> None:
        print("Build pypi2nix executable")
        try:
            self.nix.build(
                os.path.join(os.path.dirname(HERE), "default.nix"),
                out_link=os.path.join(HERE, "pypi2nix"),
            )
        except EvaluationFailed:
            self.fail("Could not build pypi2nix executable")

    def generate_requirements_file(self) -> None:
        print("Generate requirements.txt")
        requirements_file_content = self.generate_requirements_file_content()
        self.write_requirements_file(requirements_file_content)

    def build_nix_expression(self) -> None:
        print("Build nix expression")
        if self.explicit_build_directory:
            self.prepare_build_directory()
        process = subprocess.Popen(
            self.build_nix_expression_command(),
            cwd=self.example_directory(),
            env=self.nix_build_env(),
            stdin=subprocess.DEVNULL,
        )
        process.communicate()
        if process.returncode != 0:
            self.fail("Could not build nix expression for {testname}".format(
                testname=self.name_of_testcase))

    def build_nix_expression_command(self) -> List[str]:
        command = [
            os.path.join(HERE, "pypi2nix", "bin", "pypi2nix"),
            "-vvv",
            "-V",
            self.python_version,
            "-r",
            "requirements.txt",
            "--default-overrides",
            "--dependency-graph-input",
            self.rendered_dependency_graph(),
            "--dependency-graph-output",
            self._dependency_graph_output_path(),
        ]
        for requirement in self.setup_requires():
            command.append("-s")
            command.append(requirement)
        for variable_name, value in self.extra_environment().items():
            command.append("-N")
            command.append("{name}={value}".format(name=variable_name,
                                                   value=value))
        for dependency in self.external_dependencies:
            command.append("-E")
            command.append(dependency)
        if self.explicit_build_directory:
            command.append("--build-directory")
            command.append(self.build_directory())
        return command

    def setup_requires(self) -> List[str]:
        return []

    def check_requirements_file_content(self) -> None:
        requirements_file_content = self.read_requirements_file_contents()
        self.requirements_file_check(requirements_file_content)

    def run_expression_tests(self) -> None:
        self.build_interpreter_from_generated_expression()
        self.build_additional_attributes()
        self.run_interpreter_with_test_code()
        self.run_executable_tests()

    def run_dependency_graph_tests(self) -> None:
        dependency_graph = self._read_dependency_graph()
        self.check_dependency_graph(dependency_graph, self.requirement_parser)

    def build_interpreter_from_generated_expression(self) -> None:
        print("Build python interpreter from generated expression")
        try:
            self.nix.build(
                os.path.join(self.example_directory(), "requirements.nix"),
                attribute="interpreter",
                out_link=os.path.join(self.example_directory(), "result"),
            )
        except EvaluationFailed:
            self.fail(
                "Failed to build python interpreter from nix expression generated"
            )

    def build_additional_attributes(self) -> None:
        for additional_path in self.additional_paths_to_build:
            try:
                self.nix.evaluate_file(
                    os.path.join(self.example_directory(), "requirements.nix"),
                    attribute=additional_path,
                )
            except EvaluationFailed:
                self.fail(f"Failed to build attribute path {additional_path}")

    def run_interpreter_with_test_code(self) -> None:
        if self.code_for_testing_string():
            test_code = self.code_for_testing_string()
            self.run_interpreter_with_test_code_from_result(test_code)
            self.run_interpreter_with_test_code_in_nix_shell(test_code)

    def run_interpreter_with_test_code_from_result(self,
                                                   test_code: str) -> None:
        print("Run generated interpreter with test code")
        process = subprocess.Popen(
            [
                os.path.join(self.example_directory(), "result", "bin",
                             "python")
            ],
            stdin=subprocess.PIPE,
        )
        process.communicate(input=test_code.encode())
        if process.returncode != 0:
            self.fail("Executation of test code failed")

    def run_interpreter_with_test_code_in_nix_shell(self,
                                                    test_code: str) -> None:
        print("Execute test code in nix-shell")
        test_command_line = [
            "nix",
            "run",
            "--show-trace",
            "-f",
            os.path.join(self.example_directory(), "requirements.nix"),
            "interpreter",
            "--command",
            "python",
        ]
        process = subprocess.Popen(
            test_command_line,
            cwd=os.path.join(self.example_directory(), "result", "bin"),
            env=self.nix_build_env(),
            stdin=subprocess.PIPE,
        )
        process.communicate(input=test_code.encode())
        if process.returncode != 0:
            self.fail("Executation of test code in nix-shell failed")

    def read_requirements_file_contents(self) -> str:
        with open(os.path.join(self.example_directory(),
                               "requirements.nix")) as f:
            return f.read()

    def code_for_testing_string(self) -> str:
        if self.code_for_testing and self.code_for_testing_filename:
            self.fail(
                "Cannot set `both code_for_testing` and `code_for_testing_filename`."
            )
        if self.code_for_testing:
            return "\n".join(self.code_for_testing)
        elif self.code_for_testing_filename:
            with open(
                    os.path.join(self.example_directory(),
                                 self.code_for_testing_filename)) as f:
                return f.read()
        else:
            return ""

    code_for_testing: List[str] = []
    code_for_testing_filename: Optional[str] = None

    def extra_environment(self) -> Dict[str, str]:
        return dict()

    def run_executable_tests(self) -> None:
        for test_command in self.executables_for_testing():
            self.run_test_command_in_shell(test_command)
            self.run_test_command_from_build_output(test_command)

    def run_test_command_in_shell(self, test_command: "TestCommand") -> None:
        print("Run {command} in nix-shell".format(command=test_command))
        test_command_line = [
            "nix",
            "run",
            "--show-trace",
            "-f",
            os.path.join(self.example_directory(), "requirements.nix"),
            "interpreter",
            "--command",
        ] + test_command.command
        process = subprocess.Popen(
            test_command_line,
            cwd=os.path.join(self.example_directory(), "result", "bin"),
            env=dict(self.nix_build_env(), **test_command.env),
        )
        process.communicate()
        print()  # for empty line after command output
        if process.returncode != 0:
            self.fail(
                "Tested executable `{command}` returned non-zero exitcode.".
                format(command=test_command))

    def run_test_command_from_build_output(
            self, test_command: "TestCommand") -> None:
        prepared_test_command = evolve(
            test_command,
            command=["./" + test_command.command[0]] +
            test_command.command[1:],
        )
        print("Run {command}".format(command=prepared_test_command))
        process = subprocess.Popen(
            prepared_test_command.command,
            cwd=os.path.join(self.example_directory(), "result", "bin"),
            env=dict(self.nix_build_env(), **prepared_test_command.env),
        )
        process.communicate()
        print()  # for empty line after command output
        if process.returncode != 0:
            self.fail(
                "Tested executable `{command}` returned non-zero exitcode.".
                format(command=test_command))

    def executables_for_testing(self) -> List["TestCommand"]:
        return []

    def nix_build_env(self) -> Dict[str, str]:
        environment_variables = dict(os.environ)
        del environment_variables["PYTHONPATH"]
        return environment_variables

    def generate_requirements_file_content(self) -> str:
        if self.constraints:
            self.generate_constraints_txt()
            requirements_txt_extra_content = [
                "-c " + self.constraints_txt_path()
            ]
        else:
            requirements_txt_extra_content = []
        return "\n".join(self.requirements + requirements_txt_extra_content)

    def generate_constraints_txt(self) -> None:
        with open(self.constraints_txt_path(), "w") as f:
            f.write("\n".join(self.constraints))

    def constraints_txt_path(self) -> str:
        return os.path.join(self.example_directory(), "constraints.txt")

    def write_requirements_file(self, content: str) -> None:
        os.makedirs(os.path.dirname(self.requirements_file_path()),
                    exist_ok=True)
        with open(self.requirements_file_path(), "w") as f:
            f.write(content)

    def requirements_file_path(self) -> str:
        return os.path.join(self.example_directory(), "requirements.txt")

    def example_directory(self) -> str:
        return os.path.join(HERE, self.name_of_testcase)

    def requirements_file_check(self, _: str) -> None:
        pass

    def _dependency_graph_output_path(self) -> str:
        return os.path.join(self.example_directory(), "dependency-graph.yml")

    def build_directory(self):
        return os.path.join(self.example_directory(), "build")

    def prepare_build_directory(self):
        if os.path.exists(self.build_directory()):
            shutil.rmtree(self.build_directory())
        os.makedirs(self.build_directory())

    def check_dependency_graph(self, dependency_graph: DependencyGraph,
                               requirement_parser: RequirementParser):
        pass

    def _read_dependency_graph(self) -> DependencyGraph:
        with open(self._dependency_graph_output_path()) as f:
            return DependencyGraph.deserialize(f.read())

    constraints: List[str] = []
    python_version: str = "python3"
    requirements: List[str] = []
    name_of_testcase: str = "undefined"
    external_dependencies: List[str] = []
    explicit_build_directory: bool = False
    additional_paths_to_build: List[str] = []
    dependency_graph: Dict[str, Dict[str, List[str]]] = {}

    @memoize
    def rendered_dependency_graph(self) -> str:
        path = os.path.join(self.example_directory(), "dependency-input.yml")
        with open(path, "w") as f:
            yaml.dump(
                self.dependency_graph,
                f,
            )
        return path
Ejemplo n.º 12
0
def main(
    version: str,
    verbose: int,
    nix_shell: str,
    nix_path: List[str],
    basename: str,
    cache_dir: str,
    extra_build_inputs: List[str],
    extra_env: str,
    enable_tests: bool,
    python_version: str,
    requirements: List[str],
    editable: List[str],
    setup_requires: List[str],
    overrides: List[AnyOverrides],
    default_overrides: bool,
    wheels_cache: List[str],
) -> None:
    """SPECIFICATION should be requirements.txt (output of pip freeze).
    """

    logger = Logger(output=sys.stdout)
    nix_executable_directory: Optional[str] = (os.path.abspath(
        os.path.dirname(nix_shell)) if os.path.exists(nix_shell) else None)

    nix = Nix(
        nix_path=nix_path,
        executable_directory=nix_executable_directory,
        verbose=verbose != 0,
    )
    platform_generator = PlatformGenerator(nix=nix)

    if default_overrides:
        overrides += tuple([
            pypi2nix.overrides.OverridesGithub(owner="garbas",
                                               repo="nixpkgs-python",
                                               path="overrides.nix")
        ])

    with open(os.path.join(os.path.dirname(__file__), "VERSION")) as f:
        pypi2nix_version = f.read()

    if version:
        click.echo(pypi2nix_version)
        return

    python_version_argument = python_version
    python_versions = pypi2nix.utils.PYTHON_VERSIONS.keys()
    if not python_version:
        raise click.exceptions.UsageError(
            'Missing option "-V" / "--python-version".  Choose from ' +
            (", ".join(python_versions)))
    python_version = pypi2nix.utils.PYTHON_VERSIONS[python_version]
    target_platform = platform_generator.from_python_version(
        python_version_argument)

    requirement_collector = RequirementsCollector(target_platform)
    setup_requirement_collector = RequirementsCollector(target_platform)

    extra_build_inputs = pypi2nix.utils.args_as_list(extra_build_inputs)
    setup_requires = pypi2nix.utils.args_as_list(setup_requires)

    for item in editable:
        requirement_collector.add_line(item)
    for build_input in setup_requires:
        setup_requirement_collector.add_line(build_input)

    # temporary pypi2nix folder and make sure it exists
    tmp_dir = os.path.join(tempfile.gettempdir(), "pypi2nix")
    if not os.path.exists(tmp_dir):
        os.makedirs(tmp_dir)

    current_dir = os.getcwd()
    requirements_name = os.path.join(current_dir, basename)

    if not cache_dir:
        cache_dir = os.path.join(tmp_dir, "cache")

    download_cache_dir = os.path.join(cache_dir, "download")
    wheel_cache_dir = os.path.join(cache_dir, "wheel")

    if not os.path.exists(download_cache_dir):
        os.makedirs(download_cache_dir)

    if not os.path.exists(wheel_cache_dir):
        os.makedirs(wheel_cache_dir)

    assert requirements is not None

    project_hash = md5_sum_of_files_with_file_names(requirements)

    project_dir = os.path.join(tmp_dir, project_hash)
    if os.path.exists(project_dir):
        shutil.rmtree(project_dir)
    os.makedirs(project_dir)

    for requirement_file_path in requirements:
        requirement_collector.add_file(requirement_file_path)

    requirement_set = requirement_collector.requirements()
    setup_requirements = setup_requirement_collector.requirements()

    sources = Sources()
    sources.update(requirement_set.sources())
    sources.update(setup_requirements.sources())

    click.echo("pypi2nix v{} running ...".format(pypi2nix_version))
    click.echo("")

    click.echo("Stage1: Downloading wheels and creating wheelhouse ...")

    pip = Pip(
        nix=nix,
        project_directory=project_dir,
        extra_env=extra_env,
        extra_build_inputs=extra_build_inputs,
        verbose=verbose,
        wheels_cache=wheels_cache,
        target_platform=target_platform,
    )
    wheel_builder = pypi2nix.stage1.WheelBuilder(pip=pip,
                                                 project_directory=project_dir,
                                                 logger=logger)
    wheels = wheel_builder.build(requirements=requirement_set,
                                 setup_requirements=setup_requirements)
    requirements_frozen = wheel_builder.get_frozen_requirements()
    default_environment = pip.default_environment()
    additional_dependency_graph = wheel_builder.additional_build_dependencies

    click.echo("Stage2: Extracting metadata from pypi.python.org ...")

    stage2 = pypi2nix.stage2.Stage2(sources=sources, verbose=verbose)

    packages_metadata = stage2.main(
        wheel_paths=wheels,
        default_environment=default_environment,
        wheel_cache_dir=wheel_cache_dir,
        additional_dependencies=additional_dependency_graph,
    )
    click.echo("Stage3: Generating Nix expressions ...")

    pypi2nix.stage3.main(
        packages_metadata=packages_metadata,
        sources=sources,
        requirements_name=requirements_name,
        requirements_frozen=requirements_frozen,
        extra_build_inputs=extra_build_inputs,
        enable_tests=enable_tests,
        python_version=python_version,
        current_dir=current_dir,
        common_overrides=overrides,
    )

    click.echo("")
    click.echo("Nix expressions generated successfully.")
    click.echo("")
    click.echo("To start development run:")
    click.echo("    nix-shell requirements.nix -A interpreter")
    click.echo("")
    click.echo("More information you can find at")
    click.echo("    https://github.com/garbas/pypi2nix")
    click.echo("")
Ejemplo n.º 13
0
def nix():
    return Nix(verbose=True)
Ejemplo n.º 14
0
def expression_evaluater(nix: Nix):
    return lambda expression: nix.evaluate_expression(
        "let pkgs = import <nixpkgs> {}; in " + expression)
Ejemplo n.º 15
0
def expression_evaluater(logger):
    nix_instance = Nix(logger=logger)
    return lambda expression: nix_instance.evaluate_expression(
        "let pkgs = import <nixpkgs> {}; in " + expression
    )
Ejemplo n.º 16
0
class IntegrationTest(TestCase):
    """Methods to implement for a valid test case:

    name_of_testcase
    requirements

    optional:

    setup_requires() -- default: []
    executables_for_testing() -- default: []
    extra_environment() -- default: dict()
    external_dependencies
    requirements_file_check(content) -- default: (lambda content: None)
    constraints
    code_for_testing
    python_version
    default_overrides
    code_for_testing_filename
    explicit_build_directory
    """
    def setUp(self) -> None:
        self.logger = StreamLogger(output=sys.stdout)
        self.nix = Nix(nix_path=[NIX_PATH], logger=self.logger)
        self.assertNotEqual(self.name_of_testcase, "undefined")

    def test_build_example(self) -> None:
        self.build_pypi2nix()
        self.generate_requirements_file()
        self.build_nix_expression()
        self.check_requirements_file_content()
        self.run_expression_tests()

    def build_pypi2nix(self) -> None:
        print("Build pypi2nix executable")
        try:
            self.nix.build(
                os.path.join(os.path.dirname(HERE), "default.nix"),
                out_link=os.path.join(HERE, "pypi2nix"),
            )
        except EvaluationFailed:
            self.fail("Could not build pypi2nix executable")

    def generate_requirements_file(self) -> None:
        print("Generate requirements.txt")
        requirements_file_content = self.generate_requirements_file_content()
        self.write_requirements_file(requirements_file_content)

    def build_nix_expression(self) -> None:
        print("Build nix expression")
        if self.explicit_build_directory:
            self.prepare_build_directory()
        process = subprocess.Popen(
            self.build_nix_expression_command(),
            cwd=self.example_directory(),
            env=self.nix_build_env(),
            stdin=subprocess.DEVNULL,
        )
        process.communicate()
        if process.returncode != 0:
            self.fail("Could not build nix expression for {testname}".format(
                testname=self.name_of_testcase))

    def build_nix_expression_command(self) -> List[str]:
        command = [
            os.path.join(HERE, "pypi2nix", "bin", "pypi2nix"),
            "-vvv",
            "-V",
            self.python_version,
            "-r",
            "requirements.txt",
        ]
        for requirement in self.setup_requires():
            command.append("-s")
            command.append(requirement)

        for variable_name, value in self.extra_environment().items():
            command.append("-N")
            command.append("{name}={value}".format(name=variable_name,
                                                   value=value))

        for dependency in self.external_dependencies:
            command.append("-E")
            command.append(dependency)
        if self.explicit_build_directory:
            command.append("--build-directory")
            command.append(self.build_directory())

        if self.default_overrides:
            command.append("--default-overrides")

        return command

    def setup_requires(self) -> List[str]:
        return []

    def check_requirements_file_content(self) -> None:
        requirements_file_content = self.read_requirements_file_contents()
        self.requirements_file_check(requirements_file_content)

    def run_expression_tests(self) -> None:
        self.build_interpreter_from_generated_expression()
        self.run_interpreter_with_test_code()
        self.run_executable_tests()

    def build_interpreter_from_generated_expression(self) -> None:
        print("Build python interpreter from generated expression")
        try:
            self.nix.build(
                os.path.join(self.example_directory(), "requirements.nix"),
                attribute="interpreter",
                out_link=os.path.join(self.example_directory(), "result"),
            )
        except EvaluationFailed:
            self.fail(
                "Failed to build python interpreter from nix expression generated"
            )

    def run_interpreter_with_test_code(self) -> None:
        if self.code_for_testing_string():
            test_code = self.code_for_testing_string()
            self.run_interpreter_with_test_code_from_result(test_code)
            self.run_interpreter_with_test_code_in_nix_shell(test_code)

    def run_interpreter_with_test_code_from_result(self,
                                                   test_code: str) -> None:
        print("Run generated interpreter with test code")
        process = subprocess.Popen(
            [
                os.path.join(self.example_directory(), "result", "bin",
                             "python")
            ],
            stdin=subprocess.PIPE,
        )
        process.communicate(input=test_code.encode())
        if process.returncode != 0:
            self.fail("Executation of test code failed")

    def run_interpreter_with_test_code_in_nix_shell(self,
                                                    test_code: str) -> None:
        print("Execute test code in nix-shell")
        test_command_line = [
            "nix",
            "run",
            "--show-trace",
            "-f",
            os.path.join(self.example_directory(), "requirements.nix"),
            "interpreter",
            "--command",
            "python",
        ]
        process = subprocess.Popen(
            test_command_line,
            cwd=os.path.join(self.example_directory(), "result", "bin"),
            env=self.nix_build_env(),
            stdin=subprocess.PIPE,
        )
        process.communicate(input=test_code.encode())
        if process.returncode != 0:
            self.fail("Executation of test code in nix-shell failed")

    def read_requirements_file_contents(self) -> str:
        with open(os.path.join(self.example_directory(),
                               "requirements.nix")) as f:
            return f.read()

    def code_for_testing_string(self) -> str:
        if self.code_for_testing and self.code_for_testing_filename:
            self.fail(
                "Cannot set `both code_for_testing` and `code_for_testing_filename`."
            )
        if self.code_for_testing:
            return "\n".join(self.code_for_testing)
        elif self.code_for_testing_filename:
            with open(
                    os.path.join(self.example_directory(),
                                 self.code_for_testing_filename)) as f:
                return f.read()
        else:
            return ""

    code_for_testing: List[str] = []
    code_for_testing_filename: Optional[str] = None

    def extra_environment(self) -> Dict[str, str]:
        return dict()

    def run_executable_tests(self) -> None:
        for test_command in self.executables_for_testing():
            self.run_test_command_in_shell(test_command)
            self.run_test_command_from_build_output(test_command)

    def run_test_command_in_shell(self, test_command: "TestCommand") -> None:
        print("Run {command} in nix-shell".format(command=test_command))
        test_command_line = [
            "nix",
            "run",
            "--show-trace",
            "-f",
            os.path.join(self.example_directory(), "requirements.nix"),
            "interpreter",
            "--command",
        ] + test_command.command
        process = subprocess.Popen(
            test_command_line,
            cwd=os.path.join(self.example_directory(), "result", "bin"),
            env=dict(self.nix_build_env(), **test_command.env),
        )
        process.communicate()
        print()  # for empty line after command output
        if process.returncode != 0:
            self.fail(
                "Tested executable `{command}` returned non-zero exitcode.".
                format(command=test_command))

    def run_test_command_from_build_output(
            self, test_command: "TestCommand") -> None:
        prepared_test_command = evolve(
            test_command,
            command=["./" + test_command.command[0]] +
            test_command.command[1:],
        )
        print("Run {command}".format(command=prepared_test_command))
        process = subprocess.Popen(
            prepared_test_command.command,
            cwd=os.path.join(self.example_directory(), "result", "bin"),
            env=dict(self.nix_build_env(), **prepared_test_command.env),
        )
        process.communicate()
        print()  # for empty line after command output
        if process.returncode != 0:
            self.fail(
                "Tested executable `{command}` returned non-zero exitcode.".
                format(command=test_command))

    def executables_for_testing(self) -> List["TestCommand"]:
        return []

    def nix_build_env(self) -> Dict[str, str]:
        environment_variables = dict(os.environ)
        environment_variables["NIX_PATH"] = NIX_PATH
        del environment_variables["PYTHONPATH"]
        return environment_variables

    def generate_requirements_file_content(self) -> str:
        if self.constraints:
            self.generate_constraints_txt()
            requirements_txt_extra_content = [
                "-c " + self.constraints_txt_path()
            ]
        else:
            requirements_txt_extra_content = []
        return "\n".join(self.requirements + requirements_txt_extra_content)

    def generate_constraints_txt(self) -> None:
        with open(self.constraints_txt_path(), "w") as f:
            f.write("\n".join(self.constraints))

    def constraints_txt_path(self) -> str:
        return os.path.join(self.example_directory(), "constraints.txt")

    def write_requirements_file(self, content: str) -> None:
        os.makedirs(os.path.dirname(self.requirements_file_path()),
                    exist_ok=True)
        with open(self.requirements_file_path(), "w") as f:
            f.write(content)

    def requirements_file_path(self) -> str:
        return os.path.join(self.example_directory(), "requirements.txt")

    def example_directory(self) -> str:
        return os.path.join(HERE, self.name_of_testcase)

    def requirements_file_check(self, _: str) -> None:
        pass

    def build_directory(self):
        return os.path.join(self.example_directory(), "build")

    def prepare_build_directory(self):
        if os.path.exists(self.build_directory()):
            shutil.rmtree(self.build_directory())
        os.makedirs(self.build_directory())

    default_overrides = False
    constraints: List[str] = []
    python_version: str = "python3"
    requirements: List[str] = []
    name_of_testcase: str = "undefined"
    external_dependencies: List[str] = []
    explicit_build_directory: bool = False
Ejemplo n.º 17
0
 def setUp(self) -> None:
     self.logger = StreamLogger(output=sys.stdout)
     self.nix = Nix(nix_path=[NIX_PATH], logger=self.logger)
     self.assertNotEqual(self.name_of_testcase, "undefined")
Ejemplo n.º 18
0
def test_can_evaluate_nix_expression(network_file: NetworkFile, nix: Nix):
    expression = f"let pkgs = import <nixpkgs> {{}}; in {network_file.nix_expression()}"
    nix.evaluate_expression(expression)