Beispiel #1
0
def test_expanduser_simple():
    home = _get_userdir()
    assert expanduser("~") == home
    assert isinstance(expanduser("~"), fsnative)
    assert expanduser(os.path.join("~", "a", "b")) == \
        os.path.join(home, "a", "b")
    assert expanduser(senf.sep + "~") == senf.sep + "~"
    if senf.altsep is not None:
        assert expanduser("~" + senf.altsep) == home + senf.altsep
Beispiel #2
0
    def scan(self, paths, exclude=[], cofuncid=None):
        added = []
        exclude = [expanduser(path) for path in exclude if path]

        def need_yield(last_yield=[0]):
            current = time.time()
            if abs(current - last_yield[0]) > 0.015:
                last_yield[0] = current
                return True
            return False

        def need_added(last_added=[0]):
            current = time.time()
            if abs(current - last_added[0]) > 1.0:
                last_added[0] = current
                return True
            return False

        for fullpath in paths:
            print_d("Scanning %r." % fullpath, self)
            desc = _("Scanning %s") % (unexpand(fsn2text(fullpath)))
            with Task(_("Library"), desc) as task:
                if cofuncid:
                    task.copool(cofuncid)
                fullpath = expanduser(fullpath)
                if filter(fullpath.startswith, exclude):
                    continue
                for path, dnames, fnames in os.walk(fullpath):
                    for filename in fnames:
                        fullfilename = os.path.join(path, filename)
                        if filter(fullfilename.startswith, exclude):
                            continue
                        if fullfilename not in self._contents:
                            fullfilename = os.path.realpath(fullfilename)
                            # skip unknown file extensions
                            if not formats.filter(fullfilename):
                                continue
                            if filter(fullfilename.startswith, exclude):
                                continue
                            if fullfilename not in self._contents:
                                item = self.add_filename(fullfilename, False)
                                if item is not None:
                                    added.append(item)
                                    if len(added) > 100 or need_added():
                                        self.add(added)
                                        added = []
                                        task.pulse()
                                        yield
                                if added and need_yield():
                                    yield
                if added:
                    self.add(added)
                    added = []
                    task.pulse()
                    yield True
Beispiel #3
0
def get_home_dir():
    """Returns the root directory of the user, /home/user or C:\\Users\\user"""

    if os.name == "nt":
        return windows.get_profile_dir()
    else:
        return expanduser("~")
Beispiel #4
0
def get_home_dir():
    """Returns the root directory of the user, /home/user or C:\\Users\\user"""

    if os.name == "nt":
        return windows.get_profile_dir()
    else:
        return expanduser("~")
Beispiel #5
0
    def test_get_exclude_dirs(self):
        some_path = os.path.join(get_home_dir(), "foo")
        if os.name != "nt":
            some_path = unexpand(some_path)
        config.set('library', 'exclude', some_path)
        assert expanduser(some_path) in get_exclude_dirs()

        assert all([isinstance(p, fsnative) for p in get_exclude_dirs()])
Beispiel #6
0
    def test_get_scan_dirs(self):
        some_path = os.path.join(get_home_dir(), "foo")
        if os.name != "nt":
            some_path = unexpand(some_path)
        config.set('settings', 'scan', some_path)
        assert expanduser(some_path) in get_scan_dirs()

        assert all([isinstance(p, fsnative) for p in get_scan_dirs()])
Beispiel #7
0
def get_scan_dirs():
    """Returns a list of paths which should be scanned

    Returns:
        list
    """

    joined_paths = bytes2fsn(config.getbytes("settings", "scan"), "utf-8")
    return [expanduser(p) for p in split_scan_dirs(joined_paths)]
Beispiel #8
0
def test_expanduser_user():
    home = _get_userdir()
    user = os.path.basename(home)

    assert expanduser("~" + user) == home
    assert expanduser(os.path.join("~" + user, "foo")) == \
        os.path.join(home, "foo")

    if senf.altsep is not None:
        assert expanduser("~" + senf.altsep + "foo") == \
            home + senf.altsep + "foo"

        assert expanduser("~" + user + senf.altsep + "a" + senf.sep) == \
            home + senf.altsep + "a" + senf.sep

    if os.name == "nt":
        assert expanduser(os.path.join("~nope", "foo")) == \
            os.path.join(os.path.dirname(home), "nope", "foo")
Beispiel #9
0
def get_exclude_dirs():
    """Returns a list of paths which should be ignored during scanning

    Returns:
        list
    """

    paths = split_scan_dirs(bytes2fsn(config.getbytes("library", "exclude"), "utf-8"))
    return [expanduser(p) for p in paths]
Beispiel #10
0
def unexpand(filename, HOME=expanduser("~")):
    """Replace the user's home directory with ~/, if it appears at the
    start of the path name."""
    sub = (os.name == "nt" and "%USERPROFILE%") or "~"
    if filename == HOME:
        return sub
    elif filename.startswith(HOME + os.path.sep):
        filename = filename.replace(HOME, sub, 1)
    return filename
Beispiel #11
0
def get_scan_dirs():
    """Returns a list of paths which should be scanned

    Returns:
        list
    """

    joined_paths = bytes2fsn(config.getbytes("settings", "scan"), "utf-8")
    return [expanduser(p) for p in split_scan_dirs(joined_paths)]
Beispiel #12
0
def get_exclude_dirs():
    """Returns a list of paths which should be ignored during scanning

    Returns:
        list
    """

    paths = split_scan_dirs(
        bytes2fsn(config.getbytes("library", "exclude"), "utf-8"))
    return [expanduser(p) for p in paths]
Beispiel #13
0
def unexpand(filename):
    """Replace the user's home directory with ~ or %USERPROFILE%, if it
    appears at the start of the path name.

    Args:
        filename (fsnative): The file path
    Returns:
        fsnative: The path with the home directory replaced
    """

    sub = (os.name == "nt" and fsnative(u"%USERPROFILE%")) or fsnative(u"~")
    home = expanduser("~")
    if filename == home:
        return sub
    elif filename.startswith(home + os.path.sep):
        filename = filename.replace(home, sub, 1)
    return filename
Beispiel #14
0
def unexpand(filename):
    """Replace the user's home directory with ~ or %USERPROFILE%, if it
    appears at the start of the path name.

    Args:
        filename (fsnative): The file path
    Returns:
        fsnative: The path with the home directory replaced
    """

    sub = (os.name == "nt" and fsnative(u"%USERPROFILE%")) or fsnative(u"~")
    home = expanduser("~")
    if filename == home:
        return sub
    elif filename.startswith(home + os.path.sep):
        filename = filename.replace(home, sub, 1)
    return filename
Beispiel #15
0
    def _post(self, value, song, keep_extension=True):
        if value:
            assert isinstance(value, str)
            value = fsnative(value)

            if keep_extension:
                fn = song.get("~filename", ".")
                ext = fn[fn.rfind("."):].lower()
                val_ext = value[-len(ext):].lower()
                if not ext == val_ext:
                    value += ext.lower()

            if os.name == "nt":
                assert isinstance(value, str)
                value = strip_win32_incompat_from_path(value)

            value = expanduser(value)
            value = limit_path(value)

            if sep in value and not os.path.isabs(value):
                raise ValueError("Pattern is not rooted")
            return value
        else:
            return fsnative(value)
Beispiel #16
0
    def _post(self, value, song, keep_extension=True):
        if value:
            assert isinstance(value, text_type)
            value = fsnative(value)

            if keep_extension:
                fn = song.get("~filename", ".")
                ext = fn[fn.rfind("."):].lower()
                val_ext = value[-len(ext):].lower()
                if not ext == val_ext:
                    value += ext.lower()

            if os.name == "nt":
                assert isinstance(value, text_type)
                value = strip_win32_incompat_from_path(value)

            value = expanduser(value)
            value = limit_path(value)

            if sep in value and not os.path.isabs(value):
                raise ValueError("Pattern is not rooted")
            return value
        else:
            return fsnative(value)
    def test_get_scan_dirs(self):
        some_path = os.path.join(unexpand(get_home_dir()), "foo")
        config.set('settings', 'scan', some_path)
        assert expanduser(some_path) in get_scan_dirs()

        assert all([isinstance(p, fsnative) for p in get_scan_dirs()])
    def test_get_exclude_dirs(self):
        some_path = os.path.join(unexpand(get_home_dir()), "foo")
        config.set('library', 'exclude', some_path)
        assert expanduser(some_path) in get_exclude_dirs()

        assert all([isinstance(p, fsnative) for p in get_exclude_dirs()])
Beispiel #19
0
class TWatchedFileLibrary(TLibrary):
    Fake = FakeSongFile
    temp_path = Path(normalize_path(expanduser(_TEMP_DIR), True)).resolve()

    def setUp(self):
        init_fake_app()
        config.set("library", "watch", True)
        super().setUp()
        # Replace global one with this one
        librarian = app.library.librarian
        app.library.destroy()
        self.library.librarian = librarian
        app.library = self.library
        self.library.filename = "watching"
        librarian.register(self.library, "main")
        assert self.library.librarian.libraries

    def test_test_setup(self):
        assert self.temp_path.is_dir()
        assert self.temp_path.is_absolute()
        assert not self.temp_path.is_symlink(), "Symlinks cause trouble in these tests"
        assert not get_exclude_dirs()

    def tearDown(self):
        destroy_fake_app()

    def Library(self):
        lib = SongFileLibrary(watch_dirs=[text2fsn(str(self.temp_path))])
        # Setup needs copools
        run_gtk_loop()
        return lib

    def test_monitors(self):
        monitors = self.library._monitors
        assert monitors, "Not monitoring any dirs"
        temp_path = Path(self.temp_path)
        assert temp_path in monitors, f"Not monitoring {temp_path} (but {monitors})"

    @pytest.mark.flaky(max_runs=3, min_passes=2)
    def test_watched_adding_removing(self):
        with temp_filename(dir=self.temp_path, suffix=".mp3", as_path=True) as path:
            shutil.copy(Path(get_data_path("silence-44-s.mp3")), path)
            sleep(0.5)
            run_gtk_loop()
            assert path.exists()
            assert str(path) in self.library, f"{path} should be in [{self.fns}] now"
        assert not path.exists(), "Failed to delete test file"
        sleep(0.5)
        # Deletion now
        run_gtk_loop()
        assert self.removed, "Nothing was automatically removed"
        assert self.added, "Nothing was automatically added"
        assert {Path(af("~filename")) for af in self.added} == {path}
        assert {Path(af("~filename")) for af in self.removed} == {path}
        assert str(path) not in self.library, f"{path} shouldn't be in the library now"

    def test_watched_adding(self):
        with temp_filename(dir=self.temp_path, suffix=".mp3", as_path=True) as path:
            shutil.copy(Path(get_data_path("silence-44-s.mp3")), path)
            assert self.temp_path in path.parents, "Copied test file incorrectly"
            watch_dirs = self.library._monitors.keys()
            assert path.parent in watch_dirs, "Not monitoring directory of new file"
            run_gtk_loop()
            assert self.library, f"Nothing in library despite watches on {watch_dirs}"
            assert str(path) in self.library, (f"{path!s} should have been added to "
                                               f"library [{self.fns}]")
            assert str(path) in {af("~filename") for af in self.added}

    def test_watched_moving_song(self):
        with temp_filename(dir=self.temp_path, suffix=".flac", as_path=True) as path:
            shutil.copy(Path(get_data_path("silence-44-s.flac")), path)
            sleep(0.2)
            assert path.exists()
            run_gtk_loop()
            assert str(path) in self.library, f"New path {path!s} didn't get added"
            assert len(self.added) == 1
            assert self.added[0]("~basename") == path.name
            self.added.clear()

            # Now move it...
            new_path = path.parent / f"moved-{path.name}"
            path.rename(new_path)
            sleep(0.2)
            assert not path.exists(), "test should have removed old file"
            assert new_path.exists(), "test should have renamed file"
            print_d(f"New test file at {new_path}")
            run_gtk_loop()
            p = normalize_path(str(new_path), True)
            assert p in self.library, f"New path {new_path} not in library [{self.fns}]"
            msg = "Inconsistent events: should be (added and removed) or nothing at all"
            assert not (bool(self.added) ^ bool(self.removed)), msg

    def test_watched_moving_dir(self):
        temp_dir = self.temp_path / "old"
        temp_dir.mkdir(exist_ok=False)
        sleep(0.2)
        run_gtk_loop()
        assert temp_dir in self.library._monitors
        with temp_filename(dir=temp_dir, suffix=".flac", as_path=True) as path:
            shutil.copy(Path(get_data_path("silence-44-s.flac")), path)
            sleep(0.2)
            assert path.exists()
            run_gtk_loop()
            assert str(path) in self.library, f"New path {path!s} didn't get added"
            assert len(self.added) == 1
            self.added.clear()
            assert self.library

            # Now move the directory...
            new_dir = path.parent.parent / "new"
            temp_dir.rename(new_dir)
            assert new_dir.is_dir(), "test should have moved to new dir"
            sleep(0.2)
            run_gtk_loop()

            new_path = new_dir / path.name
            assert new_path.is_file()
            msg = f"New path {new_path} not in library [{self.fns}]. Did move_root run?"
            assert str(new_path) in self.library, msg
            assert not self.removed, "A file was removed"

    @property
    def fns(self) -> str:
        return ", ".join(s("~filename") for s in self.library)
Beispiel #20
0
def get_exclude_dirs() -> Iterable[fsnative]:
    """:return: a list of paths which should be ignored during scanning"""

    paths = split_scan_dirs(
        bytes2fsn(config.getbytes("library", "exclude"), "utf-8"))
    return [expanduser(p) for p in paths]  # type: ignore