Browse Source

Merge 34bb74a330 into 9eead93ab7

pull/511/merge
David Schultz 2 years ago committed by GitHub
parent
commit
77adbde096
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 11
      docs/getting_started.rst
  2. 12
      src/sigal/__main__.py
  3. 74
      src/sigal/gallery.py
  4. 60
      src/sigal/plugins/nomedia.py
  5. 49
      tests/test_cli.py
  6. 15
      tests/test_gallery.py

11
docs/getting_started.rst

@ -72,6 +72,17 @@ Optional arguments:
My Pictures/Landscapes => Force
My Other Pictures/Landscapes => Force
``--only-album``
Only write a specific album path. Other albums will be ignored as if you
had set the ``ignore_directories`` setting to all of their names.
::
--only-album 'My Pictures/Pics'
My Pictures/Pics => Write
My Pictures/Pics/* => Ignore
* => Ignore
``-v, --verbose``
Show all messages

12
src/sigal/__main__.py

@ -85,6 +85,15 @@ def init(path):
"the album name. (-a 'My Pictures/* Pics' -a 'Festival')"
),
)
@option(
"--only-album",
default=None,
help=(
"Only write a specific album path. Other albums will be ignored "
"as if you had set the `ignore_directories` setting to all of "
"their names. (--only-album 'My Pictures/Pics')"
),
)
@option("-v", "--verbose", is_flag=True, help="Show all messages")
@option(
"-d",
@ -120,6 +129,7 @@ def build(
quiet,
force,
force_album,
only_album,
config,
theme,
title,
@ -186,7 +196,7 @@ def build(
locale.setlocale(locale.LC_ALL, settings["locale"])
init_plugins(settings)
gal = Gallery(settings, ncpu=ncpu, show_progress=show_progress)
gal = Gallery(settings, ncpu=ncpu, show_progress=show_progress, only_album=only_album)
gal.build(force=force_album if len(force_album) else force)
# copy extra files

74
src/sigal/gallery.py

@ -699,7 +699,7 @@ class Album:
class Gallery:
def __init__(self, settings, ncpu=None, show_progress=False):
def __init__(self, settings, ncpu=None, show_progress=False, only_album=None):
self.settings = settings
self.logger = logging.getLogger(__name__)
self.stats = defaultdict(int)
@ -711,6 +711,7 @@ class Gallery:
# Build the list of directories with images
albums = self.albums = {}
self.only_album = only_album
src_path = self.settings["source"]
ignore_dirs = settings["ignore_directories"]
@ -724,17 +725,26 @@ class Gallery:
self.progressbar_target = None if show_progress and isatty else Devnull()
for path, dirs, files in os.walk(src_path, followlinks=True, topdown=False):
for path, dirs, files in os.walk(src_path, followlinks=True, topdown=True):
if show_progress:
print("\rCollecting albums " + next(progressChars), end="")
relpath = os.path.relpath(path, src_path)
# Test if the directory match the ignore_dirs settings
if ignore_dirs and any(
fnmatch.fnmatch(relpath, ignore) for ignore in ignore_dirs
):
self.logger.info("Ignoring %s", relpath)
continue
for d in dirs[:]:
dir_relpath = join(relpath, d) if relpath != "." else d
# Test if the directory matches the only_album settings
if only_album and dir_relpath not in only_album and relpath != only_album:
self.logger.info("Skipping %s", dir_relpath)
dirs.remove(d)
continue
# Test if the directory matches the ignore_dirs settings
if ignore_dirs and any(
fnmatch.fnmatch(dir_relpath, ignore) for ignore in ignore_dirs
):
self.logger.info("Ignoring %s", dir_relpath)
dirs.remove(d)
# Remove files that match the ignore_files settings
if ignore_files:
@ -746,21 +756,29 @@ class Gallery:
files = [os.path.split(f)[1] for f in files_path]
self.logger.debug("Files after filtering: %r", files)
# Remove sub-directories that have been ignored in a previous
# iteration (as topdown=False, sub-directories are processed before
# their parent
for d in dirs[:]:
path = join(relpath, d) if relpath != "." else d
if path not in albums.keys():
dirs.remove(d)
album = Album(relpath, settings, dirs, files, self)
if not album.medias and not album.albums:
self.logger.info("Skip empty album: %r", album)
else:
album.create_output_directories()
albums[relpath] = album
self.logger.debug("Processing subdirs: %r", dirs)
self.stats["album"] += 1
albums[relpath] = album
# Remove empty albums
for relpath in sorted(albums.keys(), key=lambda x: len(x), reverse=True):
album = albums[relpath]
keep_only_album_children = only_album and os.path.relpath(os.path.dirname(album.src_path), src_path) == only_album
if not album.medias and not album.subdirs and not keep_only_album_children:
self.logger.info("Skip empty album: %r", album.path)
del albums[relpath]
if relpath != '.':
super_album = os.path.relpath(os.path.dirname(album.src_path), src_path)
self.logger.debug("Deleting album from super album %s", super_album)
albums[super_album].subdirs.remove(os.path.basename(album.path))
self.stats["album_skipped"] += 1
self.stats["album"] -= self.stats["album_skipped"]
for album in albums.values():
album.create_output_directories()
if show_progress:
print("\rCollecting albums, done.")
@ -771,6 +789,8 @@ class Gallery:
file=self.progressbar_target,
) as progress_albums:
for album in progress_albums:
if only_album and album.path != only_album:
continue
album.sort_subdirs(settings["albums_sort_attr"])
with progressbar(
@ -779,6 +799,8 @@ class Gallery:
file=self.progressbar_target,
) as progress_albums:
for album in progress_albums:
if only_album and album.path != only_album:
continue
album.sort_medias(settings["medias_sort_attr"])
self.logger.debug("Albums:\n%r", albums.values())
@ -846,9 +868,11 @@ class Gallery:
show_eta=False,
file=self.progressbar_target,
) as albums:
media_list = [
f for album in albums for f in self.process_dir(album, force=force)
]
media_list = []
for album in albums:
if self.only_album and album.path != self.only_album:
continue
media_list.extend(self.process_dir(album, force=force))
except KeyboardInterrupt:
sys.exit("Interrupted")
@ -903,6 +927,8 @@ class Gallery:
file=self.progressbar_target,
) as albums:
for album in albums:
if self.only_album and album.path != self.only_album:
continue
if album.albums:
if album.medias:
self.logger.warning(

60
src/sigal/plugins/nomedia.py

@ -54,31 +54,6 @@ from sigal import signals
logger = logging.getLogger(__name__)
def _remove_albums_with_subdirs(albums, keystoremove, prefix=""):
for keytoremove in keystoremove:
for key in list(albums.keys()):
if key.startswith(prefix + keytoremove):
# subdirs' target directories have already been created,
# remove them first
try:
album = albums[key]
settings = album.settings
if album.medias:
os.rmdir(os.path.join(album.dst_path, settings["thumb_dir"]))
if album.medias and settings["keep_orig"]:
os.rmdir(os.path.join(album.dst_path, settings["orig_dir"]))
os.rmdir(album.dst_path)
except OSError:
# directory was created and populated with images in a
# previous run => keep it
pass
# now remove the album from the surrounding album/gallery
del albums[key]
def filter_nomedia(album, settings=None):
"""Removes all filtered Media and subdirs from an Album"""
nomediapath = os.path.join(album.src_path, ".nomedia")
@ -90,39 +65,20 @@ def filter_nomedia(album, settings=None):
logger.info(
"Ignoring album '%s' because of present 0-byte .nomedia file", album.name
)
# subdirs have been added to the gallery already, remove them
# there, too
_remove_albums_with_subdirs(album.gallery.albums, [album.path])
try:
os.rmdir(album.dst_path)
except OSError:
# directory was created and populated with images in a
# previous run => keep it
pass
# cannot set albums => empty subdirs so that no albums are
# generated
album.subdirs = []
album.medias = []
album.subdirs.clear()
album.medias.clear()
else:
with open(nomediapath) as nomediaFile:
logger.info("Found a .nomedia file in %s, ignoring its entries", album.name)
ignored = nomediaFile.read().split("\n")
album.medias = [
media for media in album.medias if media.src_filename not in ignored
]
album.subdirs = [
dirname for dirname in album.subdirs if dirname not in ignored
]
# subdirs have been added to the gallery already, remove
# them there, too
_remove_albums_with_subdirs(
album.gallery.albums, ignored, album.path + os.path.sep
)
for media in album.medias[:]:
if media.src_filename in ignored:
album.medias.remove(media)
for dirname in album.subdirs[:]:
if dirname in ignored:
album.subdirs.remove(dirname)
def register(settings):

49
tests/test_cli.py

@ -105,6 +105,55 @@ atom_feed = {'feed_url': 'http://example.org/feed.atom', 'nb_items': 10}
logger.setLevel(logging.INFO)
def test_build_only_album(tmpdir, disconnect_signals):
runner = CliRunner()
config_file = str(tmpdir.join("sigal.conf.py"))
tmpdir.mkdir("pictures")
tmpdir = str(tmpdir)
cwd = os.getcwd()
try:
result = runner.invoke(init, [config_file])
assert result.exit_code == 0
os.symlink(
join(TESTGAL, "pictures", "dir2"),
join(tmpdir, "pictures", "dir1"),
)
os.chdir(tmpdir)
with open(config_file) as f:
text = f.read()
text += """
theme = 'colorbox'
plugins = ['sigal.plugins.media_page', 'sigal.plugins.nomedia',
'sigal.plugins.extended_caching']
"""
with open(config_file, "w") as f:
f.write(text)
result = runner.invoke(
build,
["pictures", "build", "--title", "Testing build", "-n", 1, "--debug", "--only-album", "dir1"],
catch_exceptions=False,
)
assert result.exit_code == 0
assert os.path.isfile(
join(tmpdir, "build", "dir1", "index.html")
)
assert not os.path.isfile(
join(tmpdir, "build", "dir2", "index.html")
)
finally:
os.chdir(cwd)
# Reset logger
logger = logging.getLogger("sigal")
logger.handlers[:] = []
logger.setLevel(logging.INFO)
def test_serve(tmpdir):
config_file = str(tmpdir.join("sigal.conf.py"))
runner = CliRunner()

15
tests/test_gallery.py

@ -326,6 +326,21 @@ def test_gallery(settings, tmp_path, caplog):
logger.setLevel(logging.INFO)
def test_gallery_only_album(settings, tmp_path, caplog):
"Test the Gallery class updating a single album."
caplog.set_level("ERROR")
settings["destination"] = str(tmp_path)
gal = Gallery(settings, ncpu=1, only_album="dir1")
gal.build()
out_html = os.path.join(settings["destination"], "dir1", "index.html")
assert os.path.isfile(out_html)
out_html2 = os.path.join(settings["destination"], "dir2", "index.html")
assert not os.path.isfile(out_html2)
def test_custom_theme(settings, tmp_path, caplog):
theme_path = tmp_path / "mytheme"
tpl_path = theme_path / "templates"

Loading…
Cancel
Save