From: Mark Wooding Date: Tue, 22 Mar 2022 01:25:53 +0000 (+0000) Subject: mkm3u: Produce makefile fragments for tracking dependencies. X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~mdw/git/epls/commitdiff_plain/2f4f35b0ffa4f2e3f495f512e0c5e12b928dda1e mkm3u: Produce makefile fragments for tracking dependencies. This is extra annoying because `make' can't handle spaces, so I must do this the hard way. --- diff --git a/.gitignore b/.gitignore index 0940b00..c1a6939 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ +*.dep *.m3u8 *.m3u8.new !/ref/*.m3u8 diff --git a/Makefile b/Makefile index 33136ba..316f3ea 100644 --- a/Makefile +++ b/Makefile @@ -4,8 +4,9 @@ all: clean::; rm -f $(CLEANFILES) realclean::; rm -f $(REALCLEANFILES) force: -.PHONY: all clean +.PHONY: all clean force .SECONDEXPANSION: # not sorry +SHELL = bash V ?= 0 V_AT = $(V_AT_$V) @@ -178,7 +179,9 @@ $(call declare-playlist, drwho-war-games, D/Doctor Who/S06E07 ZZ. The War Games) $(call declare-playlist, drwho-silurians, D/Doctor Who/S07E02 BBB. Doctor Who and the Silurians) M3US = $(addsuffix .m3u8,$(PLAYLISTS)) +DEPFILES += $(addsuffix .dep,$(PLAYLISTS)) TARGETS += $(M3US) +CLEANFILES += $(DEPFILES) CLEANFILES += mkm3u.cache-stamp mkm3u.cache-stamp: @@ -190,7 +193,7 @@ mkm3u.cache-stamp: CLEANFILES += *.m3u8.new $(M3US): %.m3u8: $$($$*_EPLS) mkm3u mkm3u.cache-stamp $(call v-tag,MKM3U)./mkm3u $(MKM3UFLAGS) $($*_MKM3UFLAGS) \ - "$<" >"$@.new" && mv "$@.new" "$@" + -M$*.dep -O$@ -o"$@.new" "$<" && mv "$@.new" "$@" CHECKS = $(foreach p,$(PLAYLISTS), check/$p) check: $(CHECKS) @@ -236,6 +239,14 @@ $(FORCE_SAVE): force-save/%: %.m3u8 fi .PHONY: save $(SAVE) +comma = , +check-deps = $(shell if [ -f $1 ]; then for i in $2; do \ + if ! [ "$$i" -ot $1 ]; then \ + echo force; break; \ + fi; \ + done; fi) +-include $(DEPFILES) + all: $(TARGETS) p:; : $p diff --git a/mkm3u b/mkm3u index 9053c5f..7141a32 100755 --- a/mkm3u +++ b/mkm3u @@ -512,6 +512,7 @@ class Playlist (object): if me.episodes: me.seasons.append(me.episodes) me.episodes = [] + def write(me, f): f.write("#EXTM3U\n") for season in me.seasons: @@ -530,6 +531,19 @@ class Playlist (object): f.write("#EXTINF:%d,,%s: %s\n%s\n" % (ch.duration, label, ch.title, ch.url)) + def write_deps(me, f, out): + deps = set() + for season in me.seasons: + for ep in season: deps.add(ep.source.fn) + f.write("### -*-makefile-*-\n") + f.write("%s: $(call check-deps, %s," % (out, out)) + for dep in sorted(deps): + f.write(" \\\n\t'%s'" % + OS.path.join(ROOT, dep) + .replace(",", "$(comma)") + .replace("'", "'\\''")) + f.write(")\n") + DEFAULT_EXPVAR = 0.05 R_DURMULT = RX.compile(r""" ^ (\d+ (?: \. \d+)?) x @@ -809,28 +823,41 @@ class EpisodeListParser (object): return me._pl op = OP.OptionParser \ - (usage = "%prog [-c] [-d CACHE] [-s SERIES] EPLS\n" + (usage = "%prog [-c] [-M DEPS] [-d CACHE] [-o OUT] [-s SERIES] EPLS\n" "%prog -i -d CACHE", description = "Generate M3U playlists from an episode list.") +op.add_option("-M", "--make-deps", metavar = "DEPS", + dest = "deps", type = "str", default = None, + help = "Write a `make' fragment for dependencies") op.add_option("-c", "--chapters", dest = "chaptersp", action = "store_true", default = False, help = "Output individual chapter names") op.add_option("-i", "--init-db", dest = "initdbp", action = "store_true", default = False, help = "Initialize the database") -op.add_option("-d", "--database", +op.add_option("-d", "--database", metavar = "CACHE", dest = "database", type = "str", default = None, help = "Set filename for cache database") -op.add_option("-s", "--series", +op.add_option("-o", "--output", metavar = "OUT", + dest = "output", type = "str", default = None, + help = "Write output playlist to OUT") +op.add_option("-O", "--fake-output", metavar = "OUT", + dest = "fakeout", type = "str", default = None, + help = "Pretend output goes to OUT for purposes of `-M'") +op.add_option("-s", "--series", metavar = "SERIES", dest = "series", type = "str", default = None, help = "Output only the listed SERIES (comma-separated)") try: opts, argv = op.parse_args() + if opts.initdbp: if opts.chaptersp or opts.series is not None or \ + opts.output is not None or opts.deps is not None or \ + opts.fakeout is not None or \ opts.database is None or len(argv): op.print_usage(file = SYS.stderr); SYS.exit(2) setup_db(opts.database) + else: if len(argv) != 1: op.print_usage(file = SYS.stderr); SYS.exit(2) if opts.database is not None: init_db(opts.database) @@ -839,10 +866,29 @@ try: else: series_wanted = set() for name in opts.series.split(","): series_wanted.add(name) + if opts.deps is not None: + if (opts.output is None or opts.output == "-") and opts.fakeout is None: + raise ExpectedError("can't write dep fragment without output file") + if opts.fakeout is None: opts.fakeout = opts.output + else: + if opts.fakeout is not None: + raise ExpectedError("fake output set but no dep fragment") + ep = EpisodeListParser(series_wanted, opts.chaptersp) ep.parse_file(argv[0]) pl = ep.done() - pl.write(SYS.stdout) + + if opts.output is None or opts.output == "-": + pl.write(SYS.stdout) + else: + with open(opts.output, "w") as f: pl.write(f) + + if opts.deps: + if opts.deps == "-": + pl.write_deps(SYS.stdout, opts.fakeout) + else: + with open(opts.deps, "w") as f: pl.write_deps(f, opts.fakeout) + except (ExpectedError, IOError, OSError) as e: LOC.report(e) SYS.exit(2)