Exemple #1
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)

        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:
                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}")
        labbook.sweep_uncommitted_changes(show=True)
Exemple #2
0
 def test_makedir_simple(self, mock_labbook):
     # Note that "score" refers to the count of .gitkeep files.
     lb = mock_labbook[2]
     long_dir = "code/non/existant/dir/should/now/be/made"
     dirs = ["code/cat_dir", "code/dog_dir", "code/mouse_dir/", "code/mouse_dir/new_dir", long_dir]
     for d in dirs:
         FO.makedir(lb, d)
         assert os.path.isdir(os.path.join(lb.root_dir, d))
         assert os.path.isfile(os.path.join(lb.root_dir, d, '.gitkeep'))
     score = 0
     for root, dirs, files in os.walk(os.path.join(lb.root_dir, 'code', 'non')):
         for f in files:
             if f == '.gitkeep':
                 score += 1
     # Ensure that count of .gitkeep files equals the number of subdirs, excluding the code dir.
     assert score == len(LabBook.make_path_relative(long_dir).split(os.sep)) - 1
Exemple #3
0
 def test_make_path_relative(self):
     vectors = [
         # In format of input: expected output
         (None, None),
         ('', ''),
         ('/', ''),
         ('//', ''),
         ('/////cats', 'cats'),
         ('//cats///', 'cats///'),
         ('cats', 'cats'),
         ('/cats/', 'cats/'),
         ('complex/.path/.like/this', 'complex/.path/.like/this'),
         ('//complex/.path/.like/this', 'complex/.path/.like/this')
     ]
     for sample_input, expected_output in vectors:
         assert LabBook.make_path_relative(sample_input) == expected_output
Exemple #4
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)
        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)
            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 #5
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")

        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}`")
            labbook.git.remove(src_abs_path, keep_file=True)
            final_dest = shutil.move(src_abs_path, dst_abs_path)
            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