Пример #1
0
    def process_project_version(self, project: Project,
                                version: ProjectVersion):
        self.__logger.info("  - Version  : %s", version.version_id)
        revision = "-"
        if project.repository.vcstype == "git":
            revision = version.revision + "~1"
        elif project.repository.vcstype == "svn":
            revision = str(int(version.revision) - 1)
        self.__logger.info("    Revision : %s", revision)

        checkout = version.get_checkout(self.__checkouts_path)
        if not checkout.exists():
            self.__logger.info("    Checkout : not checked out")
        else:
            self.__logger.info("    Checkout : %s", checkout.checkout_dir)

        version_compile = version.get_compile(self.__compiles_path)
        if version_compile.needs_compile():
            compile_state = "not compiled"
        else:
            compile_state = "compiled"
        self.__logger.info("    Compile  : %s", compile_state)

        super().process_project_version(project, version)

        return self.ok()
Пример #2
0
    def process_project_version(self, project: Project,
                                version: ProjectVersion) -> List[str]:
        logger = self.logger.getChild("version")

        detector_run = self.experiment.get_run(version)
        runtime = detector_run.get_runtime()

        if detector_run.is_success():
            logger.info("Preparing findings in %s...", version)

            result = "success"
            number_of_findings = detector_run.get_number_of_findings()
            potential_hits = detector_run.get_potential_hits()

            logger.info("Found %s potential hits.", len(potential_hits))
        else:
            number_of_findings = 0
            potential_hits = []

            if detector_run.is_error():
                logger.info("Run on %s produced an error.", version)
                result = "error"
            elif detector_run.is_timeout():
                logger.info("Run on %s timed out.", version)
                result = "timeout"
            else:
                logger.info("Not run on %s.", version)
                result = "not run"

        logger.info("Extracting target source code...")
        version_compile = version.get_compile(self.compiles_base_path)
        for potential_hit in potential_hits:
            snippets = potential_hit.get_snippets(
                version_compile.original_sources_path)
            potential_hit["target_snippets"] = [
                snippet.__dict__ for snippet in snippets
            ]

        try:
            logger.info("Publishing findings...")
            for potential_hits_slice in self.__slice_by_max_files_per_post(
                    potential_hits):
                self.__post(project, version, runtime, number_of_findings,
                            result, potential_hits_slice)
            logger.info("Findings published.")
        except RequestException as e:
            response = e.response
            if response:
                logger.error("ERROR: %d %s: %s", response.status_code,
                             response.reason, response.text)
            else:
                logger.error("ERROR: %s", e)

        return self.ok()
Пример #3
0
    def process_project_version(self, project: Project,
                                version: ProjectVersion) -> List[str]:
        logger = self.logger.getChild("version")

        detector_run = self.experiment.get_run(version)
        run_info = detector_run.get_run_info()
        potential_hits = detector_run.get_potential_hits()

        if detector_run.is_success():
            logger.info("Preparing findings in %s...", version)
            result = "success"
            logger.info("Found %s potential hits.", len(potential_hits))
        else:
            if detector_run.is_error():
                logger.info("Run on %s produced an error.", version)
                result = "error"
            elif detector_run.is_timeout():
                logger.info("Run on %s timed out.", version)
                result = "timeout"
            else:
                logger.info("Not run on %s.", version)
                result = "not run"

        version_compile = version.get_compile(self.compiles_base_path)

        try:
            logger.info("Publishing findings...")
            for potential_hits_slice in self.__slice_by_max_files_per_post(
                    potential_hits):
                post_data_slice = []
                for potential_hit in potential_hits_slice:
                    postable_data = self._prepare_post(potential_hit,
                                                       version_compile, logger)
                    post_data_slice.append(postable_data)

                file_paths = PublishFindingsTask.get_file_paths(
                    potential_hits_slice)
                self.__post(project, version, run_info, result,
                            post_data_slice, file_paths)
            logger.info("Findings published.")
        except RequestException as e:
            response = e.response
            if response:
                logger.error("ERROR: %d %s: %s", response.status_code,
                             response.reason, response.text)
            else:
                logger.error("ERROR: %s", e)

        return self.ok()
Пример #4
0
    def run(self, version: ProjectVersion, checkout: ProjectCheckout):
        logger = logging.getLogger("task.compile")

        version_compile = version.get_compile(self.compiles_base_path)

        build_path = mkdtemp(prefix='mubench-compile_') if self.use_temp_dir else version_compile.build_dir

        if self.force_compile or checkout.timestamp > version_compile.timestamp:
            logger.debug("Force compile - removing previous compiles...")
            version_compile.delete()

        try:
            if not version.is_compilable:
                raise UserWarning("Skipping compilation: not configured.")

            if version_compile.needs_compile():
                logger.info("Compiling %s...", version)
                logger.debug("Copying checkout to build directory...")
                checkout_path = checkout.checkout_dir
                copy_tree(checkout_path, build_path)
                logger.debug("Copying additional resources...")
                self.__copy_additional_compile_sources(version, build_path)

                logger.debug("Compiling project...")
                self._compile(version.compile_commands,
                              build_path,
                              version_compile.dependencies_path,
                              self.compiles_base_path,
                              logger)
                logger.debug("Create project jar...")
                zip_dir_contents(version_compile.original_classes_paths, version_compile.original_classpath)

                version_compile.save(self.run_timestamp)

            if self.use_temp_dir:
                logger.debug("Moving complete build to persistent directory...")
                copy_tree(build_path, version_compile.build_dir)
                remove_tree(build_path)
        except Exception:
            version_compile.delete()
            raise

        return version_compile
Пример #5
0
    def process_project_version_misuse(self, project: Project,
                                       version: ProjectVersion,
                                       misuse: Misuse):
        self.__logger.info("    - Misuse           : %s", misuse.misuse_id)
        self.__logger.info("      Description      : %s",
                           misuse.description.strip())
        self.__logger.info("      Fix Description  : %s",
                           misuse.fix.description.strip())
        self.__logger.info("      Misuse Elements  : - %s",
                           misuse.characteristics[0])
        for characteristic in misuse.characteristics[1:]:
            self.__logger.info("                         - %s", characteristic)

        checkout = version.get_checkout(self.__checkouts_path)
        if checkout.exists():
            location = misuse.location
            if project.repository.vcstype == "synthetic":
                checkout_path = join(version.path, "compile")
            else:
                checkout_path = checkout.checkout_dir
            source_file_path = join(checkout_path, version.source_dir,
                                    location.file)
            self.__logger.info("      Source File      : %s", source_file_path)
            self.__logger.info("      Enclosing Method : %s", location.method)

        self.__logger.info("      Fix Diff         : %s", misuse.fix.commit)
        if not misuse.patterns:
            pattern_compile_state = "no patterns to compile"
        elif version.get_compile(
                self.__compiles_path).needs_compile_patterns(misuse):
            pattern_compile_state = "patterns not compiled"
        else:
            pattern_compile_state = "patterns compiled"
        self.__logger.info("      Compile          : %s",
                           pattern_compile_state)

        return self.ok()
Пример #6
0
    def process_project_version(self, project: Project,
                                version: ProjectVersion):
        logger = logging.getLogger("compile")
        logger.info("Compiling %s...", version)
        logger = logging.getLogger("compile.tasks")

        project_compile = version.get_compile(self.compiles_base_path)

        build_path = mkdtemp(
            prefix='mubench-compile_'
        ) if self.use_temp_dir else project_compile.build_dir

        sources_path = join(build_path, version.source_dir)
        classes_path = join(build_path, version.classes_dir)

        if self.force_compile:
            logger.debug("Force compile - removing previous compiles...")
            project_compile.delete()

        try:
            needs_copy_sources = project_compile.needs_copy_sources()
            needs_compile = project_compile.needs_compile()

            if needs_copy_sources or needs_compile:
                logger.debug("Copying checkout to build directory...")
                checkout_path = version.get_checkout(
                    self.checkouts_base_path).checkout_dir
                copy_tree(checkout_path, build_path)
                logger.debug("Copying additional resources...")
                self.__copy_additional_compile_sources(version, build_path)

            if not needs_copy_sources:
                logger.debug("Already copied source.")
            else:
                logger.info("Copying sources...")
                logger.debug("Copying project sources...")
                copy_tree(sources_path, project_compile.original_sources_path)
                logger.debug("Copying misuse sources...")
                self.__copy_misuse_sources(sources_path, version.misuses,
                                           project_compile.misuse_source_path)
                logger.info("Copying pattern sources...")
                self.__copy_pattern_sources(version.misuses, project_compile)

            if not version.compile_commands:
                logger.warning("Skipping compilation: not configured.")
                return self.skip(version)

            if not needs_compile:
                logger.debug("Already compiled project.")
            else:
                logger.info("Compiling project...")
                logger.debug("Copying patterns to source directory...")
                self.__copy(version.patterns, sources_path)
                self._compile(version.compile_commands, build_path,
                              project_compile.dependencies_path,
                              self.compiles_base_path, logger)
                logger.debug("Move pattern classes...")
                self.__copy_pattern_classes(version.misuses, classes_path,
                                            project_compile)
                self.__remove_pattern_classes(version.misuses, classes_path)
                logger.debug("Copy project classes...")
                copy_tree(classes_path, project_compile.original_classes_path)
                logger.debug("Create project jar...")
                self.__create_jar(project_compile.original_classes_path,
                                  project_compile.original_classpath)
                logger.debug("Copy misuse classes...")
                self.__copy_misuse_classes(classes_path, version.misuses,
                                           project_compile.misuse_classes_path)

            if self.use_temp_dir:
                logger.debug(
                    "Moving complete build to persistent directory...")
                copy_tree(build_path, project_compile.build_dir)
                remove_tree(build_path)
        except Exception as e:
            logger.error("Compilation failed: %s", e)
            project_compile.delete()
            return self.skip(version)

        return self.ok()
class TestProjectVersion:
    # noinspection PyAttributeOutsideInit
    def setup(self):
        self.temp_dir = mkdtemp(prefix="mubench-test-project-version_")

        self.project_id = "project"
        self.version_id = "v1"
        self.uut = ProjectVersion(self.temp_dir, self.project_id,
                                  self.version_id)

    def teardown(self):
        remove_tree(self.temp_dir)

    def test_sets_path(self):
        assert_equals(
            join(self.temp_dir, self.project_id, Project.VERSIONS_DIR,
                 self.version_id), self.uut.path)

    def test_rejects_non_project_version_directory(self):
        assert not ProjectVersion.is_project_version(self.temp_dir)

    def test_accepts_project_version_directory(self):
        create_file(self.uut._version_file)
        assert ProjectVersion.is_project_version(self.uut.path)

    def test_reads_version_file(self):
        test_dict = {"revision": "42"}
        with safe_open(self.uut._version_file, 'w+') as stream:
            yaml.dump(test_dict, stream)

        assert_equals(test_dict, self.uut._yaml)

    def test_finds_misuses(self):
        misuse = create_misuse("1",
                               project=create_project(self.project_id,
                                                      base_path=self.temp_dir))
        create_file(misuse.misuse_file)
        self.uut._YAML = {"misuses": ["1"]}

        actual_misuses = self.uut.misuses

        assert_equals([misuse], actual_misuses)

    def test_version_without_misuse(self):
        self.uut._YAML = {"misuses": None}

        actual_misuses = self.uut.misuses

        assert_equals([], actual_misuses)

    def test_finds_only_own_misuses(self):
        project = create_project(self.project_id, base_path=self.temp_dir)
        misuse1 = create_misuse("1", project=project)
        create_file(misuse1.misuse_file)
        misuse2 = create_misuse("2", project=project)
        create_file(misuse2.misuse_file)
        self.uut._YAML = {"misuses": ["2"]}

        misuses = self.uut.misuses

        assert_equals([misuse2], misuses)

    def test_creates_build_config(self):
        self.uut._YAML = {
            "build": {
                "src": "src/java/",
                "commands": ["mvn compile"],
                "classes": "target/classes/"
            }
        }
        assert_equals("src/java/", self.uut.source_dir)
        assert_equals(["mvn compile"], self.uut.compile_commands)
        assert_equals("target/classes/", self.uut.classes_dir)

    def test_creates_build_config_with_defaults(self):
        self.uut._YAML = {}
        assert_equals("", self.uut.source_dir)
        assert_equals([], self.uut.compile_commands)
        assert_equals("", self.uut.classes_dir)

    def test_id(self):
        assert_equals("{}.{}".format(self.project_id, self.version_id),
                      self.uut.id)

    def test_derives_additional_compile_sources_path(self):
        assert_equals(join(self.uut.path, "compile"),
                      self.uut.additional_compile_sources)

    def test_derives_compile_base_path(self):
        self.uut._MISUSES = [create_misuse("m")
                             ]  # prevent version from loading misuses

        project_compile = self.uut.get_compile("/base/path")

        assert_equals(join("/base/path", self.project_id, self.version_id),
                      project_compile.base_path)
Пример #8
0
    def process_project_version(self, project: Project,
                                version: ProjectVersion):
        logger = logging.getLogger("compile")
        logger.info("Compiling %s...", version)
        logger.debug("- Force compile     = %r", self.force_compile)
        logger = logging.getLogger("compile.tasks")

        project_compile = version.get_compile(self.compiles_base_path)
        build_path = join(project_compile.base_path, Compile.__BUILD_DIR)
        sources_path = join(build_path, version.source_dir)
        classes_path = join(build_path, version.classes_dir)

        needs_copy_sources = project_compile.needs_copy_sources(
        ) or self.force_compile
        needs_compile = project_compile.needs_compile() or self.force_compile

        if needs_copy_sources or needs_compile:
            logger.debug("Copying to build directory...")
            checkout_path = version.get_checkout(
                self.checkouts_base_path).checkout_dir
            self.__clean_copy(checkout_path, build_path)
            logger.debug("Copying additional resources...")
            self.__copy_additional_compile_sources(version, build_path)

        if not needs_copy_sources:
            logger.debug("Already copied project source.")
        else:
            try:
                logger.info("Copying project sources...")
                self.__clean_copy(sources_path,
                                  project_compile.original_sources_path)
                self.__copy_misuse_sources(sources_path, version.misuses,
                                           project_compile.misuse_source_path)
            except IOError as e:
                logger.error("Failed to copy project sources: %s", e)
                return self.skip(version)

        if not version.compile_commands:
            logger.warn("Skipping compilation: not configured.")
            return self.skip(version)

        if not needs_compile:
            logger.info("Already compiled project.")
        else:
            try:
                logger.info("Compiling project...")
                self._compile(version.compile_commands, build_path,
                              project_compile.dependency_base_path)
                logger.debug("Copying project classes...")
                self.__clean_copy(classes_path,
                                  project_compile.original_classes_path)
                self.__copy_misuse_classes(classes_path, version.misuses,
                                           project_compile.misuse_classes_path)
            except CommandFailedError as e:
                logger.error("Compilation failed: %s", e)
                return self.skip(version)
            except FileNotFoundError as e:
                logger.error("Failed to copy classes: %s", e)
                return self.skip(version)

        if not version.patterns:
            logger.info("Skipping pattern compilation: no patterns.")
            return self.ok()

        needs_copy_pattern_sources = project_compile.needs_copy_pattern_sources(
        ) or self.force_compile
        needs_compile_patterns = project_compile.needs_compile_patterns(
        ) or self.force_compile

        if needs_copy_pattern_sources or needs_compile_patterns:
            logger.debug("Copying to build directory...")
            checkout_path = version.get_checkout(
                self.checkouts_base_path).checkout_dir
            self.__clean_copy(checkout_path, build_path)
            logger.debug("Copying additional resources...")
            self.__copy_additional_compile_sources(version, build_path)

        if not needs_copy_pattern_sources:
            logger.debug("Already copied pattern sources.")
        else:
            try:
                logger.info("Copying pattern sources...")
                self.__copy_pattern_sources(version.misuses, project_compile)
            except IOError as e:
                logger.error("Failed to copy pattern sources: %s", e)
                return self.skip(version)

        if not needs_compile_patterns:
            logger.info("Already compiled patterns.")
        else:
            try:
                logger.debug("Copying patterns to source directory...")
                self.__copy(version.patterns, sources_path)
                logger.info("Compiling patterns...")
                self._compile(version.compile_commands, build_path,
                              project_compile.dependency_base_path)
                logger.debug("Copying pattern classes...")
                self.__copy_pattern_classes(version.misuses, classes_path,
                                            project_compile)
            except FileNotFoundError as e:
                remove_tree(project_compile.pattern_classes_base_path)
                logger.error("Compilation failed: %s", e)
                return self.skip(version)
            except CommandFailedError as e:
                logger.error("Compilation failed: %s", e)
                return self.skip(version)

        return self.ok()