Exemple #1
0
    def is_set_untracked(cls, labbook: LabBook, section: str) -> bool:
        """ Return True if the given labbook section is set to be untracked
        (to work around git performance issues when files are large).

        Args:
            labbook: Subject labbook
            section: Section one of code, input, or output.

        Returns:
            bool indicating whether the labbook's section is set as untracked
        """
        return in_untracked(labbook.root_dir, section)
Exemple #2
0
    def delete_files(cls, labbook: LabBook, section: str,
                     relative_paths: List[str]) -> None:
        """Delete file (or directory) from inside lb section.

        The list of paths is deleted in series. Only provide "parent" nodes in the file tree. This is because deletes
        on directories will remove all child objects, so subsequent deletes of individual files will then fail.


        Args:
            labbook(LabBook): Subject LabBook
            section(str): Section name (code, input, output)
            relative_paths(list(str)): a list of relative paths from labbook root to target

        Returns:
            None
        """
        labbook.validate_section(section)
        is_untracked = in_untracked(labbook.root_dir, section=section)

        if not isinstance(relative_paths, list):
            raise ValueError("Must provide list of paths to remove")

        for file_path in relative_paths:
            relative_path = LabBook.make_path_relative(file_path)
            target_path = os.path.join(labbook.root_dir, section,
                                       relative_path)
            if not os.path.exists(target_path):
                raise ValueError(
                    f"Attempted to delete non-existent path at `{target_path}`"
                )
            else:
                if is_untracked:
                    if os.path.isdir(target_path):
                        shutil.rmtree(target_path)
                    else:
                        os.remove(target_path)
                else:
                    labbook.git.remove(target_path,
                                       force=True,
                                       keep_file=False)

                if os.path.exists(target_path):
                    raise IOError(f"Failed to delete path: {target_path}")

        if not is_untracked:
            labbook.sweep_uncommitted_changes(show=True)
Exemple #3
0
    def makedir(cls,
                labbook: LabBook,
                relative_path: str,
                make_parents: bool = True,
                create_activity_record: bool = False) -> None:
        """Make a new directory inside the labbook directory.

        Args:
            labbook: Subject LabBook
            relative_path(str): Path within the labbook to make directory
            make_parents(bool): If true, create intermediary directories
            create_activity_record(bool): If true, create commit and activity record

        Returns:
            str: Absolute path of new directory
        """
        if not relative_path:
            raise ValueError("relative_path argument cannot be None or empty")

        relative_path = LabBook.make_path_relative(relative_path)
        new_directory_path = os.path.join(labbook.root_dir, relative_path)
        section = relative_path.split(os.sep)[0]
        git_untracked = in_untracked(labbook.root_dir, section)
        if os.path.exists(new_directory_path):
            return
        else:
            logger.info(f"Making new directory in `{new_directory_path}`")
            os.makedirs(new_directory_path, exist_ok=make_parents)
            if git_untracked:
                logger.warning(
                    f'New {str(labbook)} untracked directory `{new_directory_path}`'
                )
                return
            new_dir = ''
            for d in relative_path.split(os.sep):
                new_dir = os.path.join(new_dir, d)
                full_new_dir = os.path.join(labbook.root_dir, new_dir)

                gitkeep_path = os.path.join(full_new_dir, '.gitkeep')
                if not os.path.exists(gitkeep_path):
                    with open(gitkeep_path, 'w') as gitkeep:
                        gitkeep.write(
                            "This file is necessary to keep this directory tracked by Git"
                            " and archivable by compression tools. Do not delete or modify!"
                        )
                    labbook.git.add(gitkeep_path)

            if create_activity_record:
                # Create detail record
                activity_type, activity_detail_type, section_str = labbook.infer_section_from_relative_path(
                    relative_path)
                adr = ActivityDetailRecord(activity_detail_type,
                                           show=False,
                                           importance=0,
                                           action=ActivityAction.CREATE)

                msg = f"Created new {section_str} directory `{relative_path}`"
                commit = labbook.git.commit(msg)
                adr.add_value('text/markdown', msg)

                # Create activity record
                ar = ActivityRecord(activity_type,
                                    message=msg,
                                    linked_commit=commit.hexsha,
                                    show=True,
                                    importance=255,
                                    tags=['directory-create'])
                ar.add_detail_object(adr)

                # Store
                ars = ActivityStore(labbook)
                ars.create_activity_record(ar)
Exemple #4
0
    def move_file(cls, labbook: LabBook, section: str, src_rel_path: str, dst_rel_path: str) \
            -> List[Dict[str, Any]]:
        """Move a file or directory within a labbook, but not outside of it. Wraps
        underlying "mv" call.

        Args:
            labbook: Subject LabBook
            section(str): Section name (code, input, output)
            src_rel_path(str): Source file or directory
            dst_rel_path(str): Target file name and/or directory
        """

        # Start with Validations
        labbook.validate_section(section)
        if not src_rel_path:
            raise ValueError("src_rel_path cannot be None or empty")

        if dst_rel_path is None:
            raise ValueError("dst_rel_path cannot be None or empty")

        is_untracked = in_untracked(labbook.root_dir, section)
        src_rel_path = LabBook.make_path_relative(src_rel_path)
        dst_rel_path = LabBook.make_path_relative(dst_rel_path)

        src_abs_path = os.path.join(labbook.root_dir, section,
                                    src_rel_path.replace('..', ''))
        dst_abs_path = os.path.join(labbook.root_dir, section,
                                    dst_rel_path.replace('..', ''))

        if not os.path.exists(src_abs_path):
            raise ValueError(f"No src file exists at `{src_abs_path}`")

        try:
            src_type = 'directory' if os.path.isdir(src_abs_path) else 'file'
            logger.info(
                f"Moving {src_type} `{src_abs_path}` to `{dst_abs_path}`")

            if not is_untracked:
                labbook.git.remove(src_abs_path, keep_file=True)

            final_dest = shutil.move(src_abs_path, dst_abs_path)

            if not is_untracked:
                commit_msg = f"Moved {src_type} `{src_rel_path}` to `{dst_rel_path}`"
                cls._make_move_activity_record(labbook, section, dst_abs_path,
                                               commit_msg)

            if os.path.isfile(final_dest):
                t = final_dest.replace(os.path.join(labbook.root_dir, section),
                                       '')
                return [cls.get_file_info(labbook, section, t or "/")]
            else:
                moved_files = list()
                t = final_dest.replace(os.path.join(labbook.root_dir, section),
                                       '')
                moved_files.append(
                    cls.get_file_info(labbook, section, t or "/"))
                for root, dirs, files in os.walk(final_dest):
                    rt = root.replace(os.path.join(labbook.root_dir, section),
                                      '')
                    rt = _make_path_relative(rt)
                    for d in sorted(dirs):
                        dinfo = cls.get_file_info(labbook, section,
                                                  os.path.join(rt, d))
                        moved_files.append(dinfo)
                    for f in filter(lambda n: n != '.gitkeep', sorted(files)):
                        finfo = cls.get_file_info(labbook, section,
                                                  os.path.join(rt, f))
                        moved_files.append(finfo)
                return moved_files

        except Exception as e:
            logger.critical(
                "Failed moving file in labbook. Repository may be in corrupted state."
            )
            logger.exception(e)
            raise
Exemple #5
0
    def insert_file(cls,
                    labbook: LabBook,
                    section: str,
                    src_file: str,
                    dst_path: str = '') -> Dict[str, Any]:
        """ Move the file at `src_file` into the `dst_dir`, overwriting
        if a file already exists there. This calls `put_file()` under-
        the-hood, but will create an activity record.

        Args:
            labbook: Subject labbook
            section: Section name (code, input, output)
            src_file: Full path of file to insert into
            dst_path: Relative path within labbook where `src_file`
                      should be copied to

        Returns:
            dict: The inserted file's info
        """

        finfo = FileOperations.put_file(labbook=labbook,
                                        section=section,
                                        src_file=src_file,
                                        dst_path=dst_path)

        rel_path = os.path.join(section, finfo['key'])
        if in_untracked(labbook.root_dir, section):
            logger.warning(f"Inserted file {rel_path} ({finfo['size']} bytes)"
                           f" to untracked section {section}. This will not"
                           f" be tracked by commits or activity records.")
            return finfo

        # If we are setting this section to be untracked
        activity_type, activity_detail_type, section_str = \
            labbook.get_activity_type_from_section(section)

        commit_msg = f"Added new {section_str} file {rel_path}"
        try:
            labbook.git.add(rel_path)
            commit = labbook.git.commit(commit_msg)
        except Exception as x:
            logger.error(x)
            os.remove(dst_path)
            raise FileOperationsException(x)

        # Create Activity record and detail
        _, ext = os.path.splitext(rel_path) or 'file'
        adr = ActivityDetailRecord(activity_detail_type,
                                   show=False,
                                   importance=0,
                                   action=ActivityAction.CREATE)
        adr.add_value('text/plain', commit_msg)
        ar = ActivityRecord(activity_type,
                            message=commit_msg,
                            show=True,
                            importance=255,
                            linked_commit=commit.hexsha,
                            tags=[ext])
        ar.add_detail_object(adr)
        ars = ActivityStore(labbook)
        ars.create_activity_record(ar)

        return finfo