From 9eb081ea0a8afcfbcb78a04068897e79022d5161 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Mon, 7 Nov 2022 00:10:39 +0000 Subject: [PATCH] meson: Generate ChangeLog files for release tarballs on dist Part-of: --- meson.build | 2 + scripts/gen-changelog.py | 240 ++++++++++++++++++ scripts/meson.build | 53 ++++ subprojects/gst-devtools/meson.build | 2 + .../gst-devtools/scripts/gen-changelog.py | 240 ++++++++++++++++++ subprojects/gst-docs/meson.build | 2 + subprojects/gst-docs/scripts/gen-changelog.py | 240 ++++++++++++++++++ subprojects/gst-editing-services/meson.build | 2 + .../scripts/gen-changelog.py | 240 ++++++++++++++++++ subprojects/gst-libav/meson.build | 2 + .../gst-libav/scripts/gen-changelog.py | 240 ++++++++++++++++++ subprojects/gst-omx/meson.build | 2 + subprojects/gst-omx/scripts/gen-changelog.py | 240 ++++++++++++++++++ subprojects/gst-plugins-bad/meson.build | 2 + .../gst-plugins-bad/scripts/gen-changelog.py | 240 ++++++++++++++++++ subprojects/gst-plugins-base/meson.build | 2 + .../gst-plugins-base/scripts/gen-changelog.py | 240 ++++++++++++++++++ subprojects/gst-plugins-good/meson.build | 2 + .../gst-plugins-good/scripts/gen-changelog.py | 240 ++++++++++++++++++ subprojects/gst-plugins-ugly/meson.build | 2 + .../gst-plugins-ugly/scripts/gen-changelog.py | 240 ++++++++++++++++++ subprojects/gst-python/meson.build | 2 + .../gst-python/scripts/gen-changelog.py | 240 ++++++++++++++++++ subprojects/gst-rtsp-server/meson.build | 2 + .../gst-rtsp-server/scripts/gen-changelog.py | 240 ++++++++++++++++++ subprojects/gstreamer-sharp/meson.build | 2 + .../gstreamer-sharp/scripts/gen-changelog.py | 240 ++++++++++++++++++ subprojects/gstreamer-vaapi/meson.build | 2 + .../gstreamer-vaapi/scripts/gen-changelog.py | 240 ++++++++++++++++++ subprojects/gstreamer/meson.build | 2 + .../gstreamer/scripts/gen-changelog.py | 240 ++++++++++++++++++ 31 files changed, 3683 insertions(+) create mode 100755 scripts/gen-changelog.py create mode 100644 scripts/meson.build create mode 100755 subprojects/gst-devtools/scripts/gen-changelog.py create mode 100755 subprojects/gst-docs/scripts/gen-changelog.py create mode 100755 subprojects/gst-editing-services/scripts/gen-changelog.py create mode 100755 subprojects/gst-libav/scripts/gen-changelog.py create mode 100755 subprojects/gst-omx/scripts/gen-changelog.py create mode 100755 subprojects/gst-plugins-bad/scripts/gen-changelog.py create mode 100755 subprojects/gst-plugins-base/scripts/gen-changelog.py create mode 100755 subprojects/gst-plugins-good/scripts/gen-changelog.py create mode 100755 subprojects/gst-plugins-ugly/scripts/gen-changelog.py create mode 100755 subprojects/gst-python/scripts/gen-changelog.py create mode 100755 subprojects/gst-rtsp-server/scripts/gen-changelog.py create mode 100755 subprojects/gstreamer-sharp/scripts/gen-changelog.py create mode 100755 subprojects/gstreamer-vaapi/scripts/gen-changelog.py create mode 100755 subprojects/gstreamer/scripts/gen-changelog.py diff --git a/meson.build b/meson.build index 88b74579f0..ee9d10454b 100644 --- a/meson.build +++ b/meson.build @@ -496,6 +496,8 @@ if orc_subproject.found() and orc_update_targets.length() > 0 alias_target('update-orc-dist', orc_update_targets) endif +subdir('scripts') + dotnet_format = find_program('dotnet-format', required: false) if dotnet_format.found() run_target('csharp_format_check', diff --git a/scripts/gen-changelog.py b/scripts/gen-changelog.py new file mode 100755 index 0000000000..3924e6ea32 --- /dev/null +++ b/scripts/gen-changelog.py @@ -0,0 +1,240 @@ +#!/usr/bin/env python3 +# +# Makes a GNU-Style ChangeLog from a git repository +import os +import sys +import subprocess +import re + +meson_source_root = os.environ.get('MESON_SOURCE_ROOT') + +meson_dist_root = os.environ.get('MESON_DIST_ROOT') +if meson_dist_root: + output_fn = os.path.join(meson_dist_root, 'ChangeLog') +else: + output_fn = sys.stdout.fileno() + +# commit hash => release version tag string +release_refs = {} + +# These are the pre-monorepo module beginnings +changelog_starts = { + 'gstreamer': '70521179a75db0c7230cc47c6d7f9d63cf73d351', + 'gst-plugins-base': '68746a38d5e48e6f7c220663dcc2f175ff55cb3c', + 'gst-plugins-good': '81f63142d65b62b0971c19ceb79956c49ffc2f06', + 'gst-plugins-ugly': '7d7c3e478e32b7b66c44cc4442d571fbab534740', + 'gst-plugins-bad': 'ea6821e2934fe8d356ea89d5610f0630b3446877', + 'gst-libav': '3c440154c60d1ec0a54186f0fad4aebfd2ecc3ea', + 'gst-rtsp-server': '5029c85a46a8c366c4bf272d503e22bbcd624ece', + 'gst-editing-services': 'ee8bf88ebf131cf7c7161356540efc20bf411e14', + 'gst-python': 'b3e564eff577e2f577d795051bbcca85d47c89dc', + 'gstreamer-vaapi': 'c89e9afc5d43837c498a55f8f13ddf235442b83b', + 'gst-omx': 'd2463b017f222e678978582544a9c9a80edfd330', + 'gst-devtools': 'da962d096af9460502843e41b7d25fdece7ff1c2', + 'gstreamer-sharp': 'b94528f8e7979df49fedf137dfa228d8fe475e1b', +} + + +def print_help(): + print('', file=sys.stderr) + print('gen-changelog: generate GNU-style changelog from git history', + file=sys.stderr) + print('', file=sys.stderr) + print('Usage: {} [OPTIONS] GSTREAMER-MODULE [START-TAG] [HEAD-TAG]'.format( + sys.argv[0]), file=sys.stderr) + print('', file=sys.stderr) + sys.exit(1) + + +if len(sys.argv) < 2 or len(sys.argv) > 4 or '--help' in sys.argv: + print_help() + +module = sys.argv[1] + +if len(sys.argv) > 2: + start_tag = sys.argv[2] +else: + start_tag = None + +if len(sys.argv) > 3: + head_tag = sys.argv[3] +else: + head_tag = None + +if module not in changelog_starts: + print(f'Unknown module {module}', file=sys.stderr) + print_help() + + +def process_commit(lines, files, subtree_path=None): + # DATE NAME + # BLANK LINE + # Subject + # BLANK LINE + # ... + # FILES + fileincommit = False + lines = [x.strip() for x in lines if x.strip() + and not x.startswith('git-svn-id')] + files = [x.strip() for x in files if x.strip()] + for line in lines: + if line.startswith('* ') and ':' in line: + fileincommit = True + break + + top_line = lines[0] + print(top_line.strip()) + print() + if not fileincommit: + for f in files: + if subtree_path and f.startswith(subtree_path): + # requires Python 3.9 + print('\t* %s:' % f.removeprefix(subtree_path)) + else: + print('\t* %s:' % f) + for line in lines[1:]: + print('\t ', line) + print() + + +def output_commits(module, start_tag, end_tag, subtree_path=None): + # retrieve commit date for start tag so we can filter the log for commits + # after that date. That way we don't include commits from merged-in + # plugin-move branches that go back to the beginning of time. + start_date = get_commit_date_for_ref(start_tag) + + cmd = ['git', 'log', + '--pretty=format:--START-COMMIT--%H%n%ai %an <%ae>%n%n%s%n%b%n--END-COMMIT--', + '--date=short', + '--name-only', + f'--since={start_date}', + f'{start_tag}..{end_tag}', + ] + + if subtree_path: + cmd += ['--', '.'] + + p = subprocess.Popen(args=cmd, shell=False, + stdout=subprocess.PIPE, cwd=meson_source_root) + buf = [] + files = [] + filemode = False + for lin in [x.decode('utf8', errors='replace') for x in p.stdout.readlines()]: + if lin.startswith("--START-COMMIT--"): + commit_hash = lin[16:].strip() + if buf != []: + process_commit(buf, files, subtree_path) + + if commit_hash in release_refs: + version_str = release_refs[commit_hash] + print(f'=== release {version_str} ===\n') + + buf = [] + files = [] + filemode = False + elif lin.startswith("--END-COMMIT--"): + filemode = True + elif filemode is True: + files.append(lin) + else: + buf.append(lin) + if buf != []: + process_commit(buf, files, subtree_path) + + +def get_commit_date_for_ref(ref): + cmd = ['git', 'log', '--pretty=format:%cI', '-1', ref] + r = subprocess.run(cmd, capture_output=True, text=True, + check=True, cwd=meson_source_root) + commit_date = r.stdout.strip() + return commit_date + + +def populate_release_tags_for_premonorepo_module(module_tag_prefix): + if module_tag_prefix != '': + cmd = ['git', 'tag', '--list', f'{module_tag_prefix}*'] + else: + cmd = ['git', 'tag', '--list', '1.*', 'RELEASE-*'] + + p = subprocess.Popen(args=cmd, shell=False, + stdout=subprocess.PIPE, cwd=meson_source_root) + for line in [x.decode('utf8') for x in p.stdout.readlines()]: + git_tag = line.strip() + version_str = git_tag.removeprefix(module_tag_prefix).removeprefix('RELEASE-').split('-')[0].replace('_', '.') + # might have been populated with post-monorepo tags already for gstreamer core + if version_str not in release_refs: + # find last commit before tag in module subdirectory + cmd = ['git', 'log', '--pretty=format:%H', '-1', git_tag] + r = subprocess.run(cmd, capture_output=True, + text=True, check=True, cwd=meson_source_root) + commit_hash = r.stdout.strip() + release_refs[commit_hash] = version_str + + # print(f'{git_tag} => {version_str} => {commit_hash}') + + +def populate_release_tags_for_monorepo_subproject(): + cmd = ['git', 'tag', '--list', '1.*'] + p = subprocess.Popen(args=cmd, shell=False, + stdout=subprocess.PIPE, cwd=meson_source_root) + for line in [x.decode('utf8') for x in p.stdout.readlines()]: + version_str = line.strip() + version_arr = version_str.split('.') + major = int(version_arr[0]) + minor = int(version_arr[1]) + micro = int(version_arr[2]) + # ignore pre-monorepo versions + if major < 1: + continue + if major == 1 and minor < 19: + continue + if major == 1 and minor == 19 and micro < 2: + continue + # find last commit before tag in module subdirectory + cmd = ['git', 'log', '--pretty=format:%H', + '-1', version_str, '--', '.'] + r = subprocess.run(cmd, capture_output=True, text=True, + check=True, cwd=meson_source_root) + commit_hash = r.stdout.strip() + release_refs[commit_hash] = version_str + + +if __name__ == '__main__': + module_tag_prefix = '' if module == 'gstreamer' else f'{module}-' + + populate_release_tags_for_monorepo_subproject() + + with open(output_fn, 'w') as f: + sys.stdout = f + + # Force writing of head tag + if head_tag and head_tag not in release_refs.values(): + print(f'=== release {head_tag} ===\n') + + # Output all commits from start_tag onwards, otherwise output full history. + # (We assume the start_tag is after the monorepo merge if it's specified.) + if start_tag and start_tag != 'start': + output_commits(module, start_tag, 'HEAD', f'subprojects/{module}/') + else: + # First output all post-monorepo commits or commits from start_tag if specified + output_commits(module, 'monorepo-start', + 'HEAD', f'subprojects/{module}/') + + populate_release_tags_for_premonorepo_module(module_tag_prefix) + + # Next output all pre-monorepo commits (modules have their own root) + if not start_tag: + module_start = f'{module_tag_prefix}1.0.0' + elif start_tag == 'start': + module_start = changelog_starts[module] + else: + module_start = f'{module_tag_prefix}{start_tag}' + + output_commits(module, module_start, + f'{module_tag_prefix}1.19.2', None) + + # Write start tag at end for clarity + if not start_tag: + print(f'=== release 1.0.0 ===\n') + elif start_tag != 'start': + print(f'=== release {start_tag} ===\n') diff --git a/scripts/meson.build b/scripts/meson.build new file mode 100644 index 0000000000..0554b17b6e --- /dev/null +++ b/scripts/meson.build @@ -0,0 +1,53 @@ +fs = import('fs') + +# scripts checks +release_modules = [ + 'gstreamer', + 'gst-plugins-base', + 'gst-plugins-good', + 'gst-plugins-ugly', + 'gst-plugins-bad', + 'gst-libav', + 'gst-rtsp-server', + 'gst-editing-services', + 'gst-devtools', + 'gst-python', + 'gstreamer-vaapi', + 'gst-omx', + 'gst-docs', + 'gstreamer-sharp', +] + +# Make sure the files are all identical to avoid divergence +gen_cl_hash = fs.hash(files('gen-changelog.py'), 'md5') + +out_of_sync_list = [] + +foreach m : release_modules + module_gen_cl_hash = fs.hash(f'../subprojects/@m@/scripts/gen-changelog.py', 'md5') + + if module_gen_cl_hash != gen_cl_hash + out_of_sync_list += [f'subprojects/@m@/scripts/gen-changelog.py'] + endif +endforeach + +if out_of_sync_list.length() > 0 + module_list = ' '.join(release_modules) + out_of_sync_msg = '\n '.join(out_of_sync_list) + error(''' + + ============================================================================================================== + + The following subproject scripts are out of sync with scripts/gen-changelog.py: + + @0@ + + Run + + for m in @1@; do cp scripts/gen-changelog.py subprojects/$m/scripts/gen-changelog.py; done + + from the top-level git source directory to sync them up. + + ============================================================================================================== + '''.format(out_of_sync_msg, module_list)) +endif diff --git a/subprojects/gst-devtools/meson.build b/subprojects/gst-devtools/meson.build index d7752da59c..9a03dbfe65 100644 --- a/subprojects/gst-devtools/meson.build +++ b/subprojects/gst-devtools/meson.build @@ -174,6 +174,8 @@ if not get_option('debug_viewer').disabled() endif subdir('docs') +meson.add_dist_script('scripts/gen-changelog.py', meson.project_name(), '1.20.0', meson.project_version()) + plugin_names = [] gst_plugins = [] foreach plugin: plugins diff --git a/subprojects/gst-devtools/scripts/gen-changelog.py b/subprojects/gst-devtools/scripts/gen-changelog.py new file mode 100755 index 0000000000..3924e6ea32 --- /dev/null +++ b/subprojects/gst-devtools/scripts/gen-changelog.py @@ -0,0 +1,240 @@ +#!/usr/bin/env python3 +# +# Makes a GNU-Style ChangeLog from a git repository +import os +import sys +import subprocess +import re + +meson_source_root = os.environ.get('MESON_SOURCE_ROOT') + +meson_dist_root = os.environ.get('MESON_DIST_ROOT') +if meson_dist_root: + output_fn = os.path.join(meson_dist_root, 'ChangeLog') +else: + output_fn = sys.stdout.fileno() + +# commit hash => release version tag string +release_refs = {} + +# These are the pre-monorepo module beginnings +changelog_starts = { + 'gstreamer': '70521179a75db0c7230cc47c6d7f9d63cf73d351', + 'gst-plugins-base': '68746a38d5e48e6f7c220663dcc2f175ff55cb3c', + 'gst-plugins-good': '81f63142d65b62b0971c19ceb79956c49ffc2f06', + 'gst-plugins-ugly': '7d7c3e478e32b7b66c44cc4442d571fbab534740', + 'gst-plugins-bad': 'ea6821e2934fe8d356ea89d5610f0630b3446877', + 'gst-libav': '3c440154c60d1ec0a54186f0fad4aebfd2ecc3ea', + 'gst-rtsp-server': '5029c85a46a8c366c4bf272d503e22bbcd624ece', + 'gst-editing-services': 'ee8bf88ebf131cf7c7161356540efc20bf411e14', + 'gst-python': 'b3e564eff577e2f577d795051bbcca85d47c89dc', + 'gstreamer-vaapi': 'c89e9afc5d43837c498a55f8f13ddf235442b83b', + 'gst-omx': 'd2463b017f222e678978582544a9c9a80edfd330', + 'gst-devtools': 'da962d096af9460502843e41b7d25fdece7ff1c2', + 'gstreamer-sharp': 'b94528f8e7979df49fedf137dfa228d8fe475e1b', +} + + +def print_help(): + print('', file=sys.stderr) + print('gen-changelog: generate GNU-style changelog from git history', + file=sys.stderr) + print('', file=sys.stderr) + print('Usage: {} [OPTIONS] GSTREAMER-MODULE [START-TAG] [HEAD-TAG]'.format( + sys.argv[0]), file=sys.stderr) + print('', file=sys.stderr) + sys.exit(1) + + +if len(sys.argv) < 2 or len(sys.argv) > 4 or '--help' in sys.argv: + print_help() + +module = sys.argv[1] + +if len(sys.argv) > 2: + start_tag = sys.argv[2] +else: + start_tag = None + +if len(sys.argv) > 3: + head_tag = sys.argv[3] +else: + head_tag = None + +if module not in changelog_starts: + print(f'Unknown module {module}', file=sys.stderr) + print_help() + + +def process_commit(lines, files, subtree_path=None): + # DATE NAME + # BLANK LINE + # Subject + # BLANK LINE + # ... + # FILES + fileincommit = False + lines = [x.strip() for x in lines if x.strip() + and not x.startswith('git-svn-id')] + files = [x.strip() for x in files if x.strip()] + for line in lines: + if line.startswith('* ') and ':' in line: + fileincommit = True + break + + top_line = lines[0] + print(top_line.strip()) + print() + if not fileincommit: + for f in files: + if subtree_path and f.startswith(subtree_path): + # requires Python 3.9 + print('\t* %s:' % f.removeprefix(subtree_path)) + else: + print('\t* %s:' % f) + for line in lines[1:]: + print('\t ', line) + print() + + +def output_commits(module, start_tag, end_tag, subtree_path=None): + # retrieve commit date for start tag so we can filter the log for commits + # after that date. That way we don't include commits from merged-in + # plugin-move branches that go back to the beginning of time. + start_date = get_commit_date_for_ref(start_tag) + + cmd = ['git', 'log', + '--pretty=format:--START-COMMIT--%H%n%ai %an <%ae>%n%n%s%n%b%n--END-COMMIT--', + '--date=short', + '--name-only', + f'--since={start_date}', + f'{start_tag}..{end_tag}', + ] + + if subtree_path: + cmd += ['--', '.'] + + p = subprocess.Popen(args=cmd, shell=False, + stdout=subprocess.PIPE, cwd=meson_source_root) + buf = [] + files = [] + filemode = False + for lin in [x.decode('utf8', errors='replace') for x in p.stdout.readlines()]: + if lin.startswith("--START-COMMIT--"): + commit_hash = lin[16:].strip() + if buf != []: + process_commit(buf, files, subtree_path) + + if commit_hash in release_refs: + version_str = release_refs[commit_hash] + print(f'=== release {version_str} ===\n') + + buf = [] + files = [] + filemode = False + elif lin.startswith("--END-COMMIT--"): + filemode = True + elif filemode is True: + files.append(lin) + else: + buf.append(lin) + if buf != []: + process_commit(buf, files, subtree_path) + + +def get_commit_date_for_ref(ref): + cmd = ['git', 'log', '--pretty=format:%cI', '-1', ref] + r = subprocess.run(cmd, capture_output=True, text=True, + check=True, cwd=meson_source_root) + commit_date = r.stdout.strip() + return commit_date + + +def populate_release_tags_for_premonorepo_module(module_tag_prefix): + if module_tag_prefix != '': + cmd = ['git', 'tag', '--list', f'{module_tag_prefix}*'] + else: + cmd = ['git', 'tag', '--list', '1.*', 'RELEASE-*'] + + p = subprocess.Popen(args=cmd, shell=False, + stdout=subprocess.PIPE, cwd=meson_source_root) + for line in [x.decode('utf8') for x in p.stdout.readlines()]: + git_tag = line.strip() + version_str = git_tag.removeprefix(module_tag_prefix).removeprefix('RELEASE-').split('-')[0].replace('_', '.') + # might have been populated with post-monorepo tags already for gstreamer core + if version_str not in release_refs: + # find last commit before tag in module subdirectory + cmd = ['git', 'log', '--pretty=format:%H', '-1', git_tag] + r = subprocess.run(cmd, capture_output=True, + text=True, check=True, cwd=meson_source_root) + commit_hash = r.stdout.strip() + release_refs[commit_hash] = version_str + + # print(f'{git_tag} => {version_str} => {commit_hash}') + + +def populate_release_tags_for_monorepo_subproject(): + cmd = ['git', 'tag', '--list', '1.*'] + p = subprocess.Popen(args=cmd, shell=False, + stdout=subprocess.PIPE, cwd=meson_source_root) + for line in [x.decode('utf8') for x in p.stdout.readlines()]: + version_str = line.strip() + version_arr = version_str.split('.') + major = int(version_arr[0]) + minor = int(version_arr[1]) + micro = int(version_arr[2]) + # ignore pre-monorepo versions + if major < 1: + continue + if major == 1 and minor < 19: + continue + if major == 1 and minor == 19 and micro < 2: + continue + # find last commit before tag in module subdirectory + cmd = ['git', 'log', '--pretty=format:%H', + '-1', version_str, '--', '.'] + r = subprocess.run(cmd, capture_output=True, text=True, + check=True, cwd=meson_source_root) + commit_hash = r.stdout.strip() + release_refs[commit_hash] = version_str + + +if __name__ == '__main__': + module_tag_prefix = '' if module == 'gstreamer' else f'{module}-' + + populate_release_tags_for_monorepo_subproject() + + with open(output_fn, 'w') as f: + sys.stdout = f + + # Force writing of head tag + if head_tag and head_tag not in release_refs.values(): + print(f'=== release {head_tag} ===\n') + + # Output all commits from start_tag onwards, otherwise output full history. + # (We assume the start_tag is after the monorepo merge if it's specified.) + if start_tag and start_tag != 'start': + output_commits(module, start_tag, 'HEAD', f'subprojects/{module}/') + else: + # First output all post-monorepo commits or commits from start_tag if specified + output_commits(module, 'monorepo-start', + 'HEAD', f'subprojects/{module}/') + + populate_release_tags_for_premonorepo_module(module_tag_prefix) + + # Next output all pre-monorepo commits (modules have their own root) + if not start_tag: + module_start = f'{module_tag_prefix}1.0.0' + elif start_tag == 'start': + module_start = changelog_starts[module] + else: + module_start = f'{module_tag_prefix}{start_tag}' + + output_commits(module, module_start, + f'{module_tag_prefix}1.19.2', None) + + # Write start tag at end for clarity + if not start_tag: + print(f'=== release 1.0.0 ===\n') + elif start_tag != 'start': + print(f'=== release {start_tag} ===\n') diff --git a/subprojects/gst-docs/meson.build b/subprojects/gst-docs/meson.build index 69666b306e..530e20396b 100644 --- a/subprojects/gst-docs/meson.build +++ b/subprojects/gst-docs/meson.build @@ -144,3 +144,5 @@ run_target('release', meson.current_build_dir()], depends: [gstreamer_doc] ) + +meson.add_dist_script('scripts/gen-changelog.py', meson.project_name(), '1.20.0', meson.project_version()) diff --git a/subprojects/gst-docs/scripts/gen-changelog.py b/subprojects/gst-docs/scripts/gen-changelog.py new file mode 100755 index 0000000000..3924e6ea32 --- /dev/null +++ b/subprojects/gst-docs/scripts/gen-changelog.py @@ -0,0 +1,240 @@ +#!/usr/bin/env python3 +# +# Makes a GNU-Style ChangeLog from a git repository +import os +import sys +import subprocess +import re + +meson_source_root = os.environ.get('MESON_SOURCE_ROOT') + +meson_dist_root = os.environ.get('MESON_DIST_ROOT') +if meson_dist_root: + output_fn = os.path.join(meson_dist_root, 'ChangeLog') +else: + output_fn = sys.stdout.fileno() + +# commit hash => release version tag string +release_refs = {} + +# These are the pre-monorepo module beginnings +changelog_starts = { + 'gstreamer': '70521179a75db0c7230cc47c6d7f9d63cf73d351', + 'gst-plugins-base': '68746a38d5e48e6f7c220663dcc2f175ff55cb3c', + 'gst-plugins-good': '81f63142d65b62b0971c19ceb79956c49ffc2f06', + 'gst-plugins-ugly': '7d7c3e478e32b7b66c44cc4442d571fbab534740', + 'gst-plugins-bad': 'ea6821e2934fe8d356ea89d5610f0630b3446877', + 'gst-libav': '3c440154c60d1ec0a54186f0fad4aebfd2ecc3ea', + 'gst-rtsp-server': '5029c85a46a8c366c4bf272d503e22bbcd624ece', + 'gst-editing-services': 'ee8bf88ebf131cf7c7161356540efc20bf411e14', + 'gst-python': 'b3e564eff577e2f577d795051bbcca85d47c89dc', + 'gstreamer-vaapi': 'c89e9afc5d43837c498a55f8f13ddf235442b83b', + 'gst-omx': 'd2463b017f222e678978582544a9c9a80edfd330', + 'gst-devtools': 'da962d096af9460502843e41b7d25fdece7ff1c2', + 'gstreamer-sharp': 'b94528f8e7979df49fedf137dfa228d8fe475e1b', +} + + +def print_help(): + print('', file=sys.stderr) + print('gen-changelog: generate GNU-style changelog from git history', + file=sys.stderr) + print('', file=sys.stderr) + print('Usage: {} [OPTIONS] GSTREAMER-MODULE [START-TAG] [HEAD-TAG]'.format( + sys.argv[0]), file=sys.stderr) + print('', file=sys.stderr) + sys.exit(1) + + +if len(sys.argv) < 2 or len(sys.argv) > 4 or '--help' in sys.argv: + print_help() + +module = sys.argv[1] + +if len(sys.argv) > 2: + start_tag = sys.argv[2] +else: + start_tag = None + +if len(sys.argv) > 3: + head_tag = sys.argv[3] +else: + head_tag = None + +if module not in changelog_starts: + print(f'Unknown module {module}', file=sys.stderr) + print_help() + + +def process_commit(lines, files, subtree_path=None): + # DATE NAME + # BLANK LINE + # Subject + # BLANK LINE + # ... + # FILES + fileincommit = False + lines = [x.strip() for x in lines if x.strip() + and not x.startswith('git-svn-id')] + files = [x.strip() for x in files if x.strip()] + for line in lines: + if line.startswith('* ') and ':' in line: + fileincommit = True + break + + top_line = lines[0] + print(top_line.strip()) + print() + if not fileincommit: + for f in files: + if subtree_path and f.startswith(subtree_path): + # requires Python 3.9 + print('\t* %s:' % f.removeprefix(subtree_path)) + else: + print('\t* %s:' % f) + for line in lines[1:]: + print('\t ', line) + print() + + +def output_commits(module, start_tag, end_tag, subtree_path=None): + # retrieve commit date for start tag so we can filter the log for commits + # after that date. That way we don't include commits from merged-in + # plugin-move branches that go back to the beginning of time. + start_date = get_commit_date_for_ref(start_tag) + + cmd = ['git', 'log', + '--pretty=format:--START-COMMIT--%H%n%ai %an <%ae>%n%n%s%n%b%n--END-COMMIT--', + '--date=short', + '--name-only', + f'--since={start_date}', + f'{start_tag}..{end_tag}', + ] + + if subtree_path: + cmd += ['--', '.'] + + p = subprocess.Popen(args=cmd, shell=False, + stdout=subprocess.PIPE, cwd=meson_source_root) + buf = [] + files = [] + filemode = False + for lin in [x.decode('utf8', errors='replace') for x in p.stdout.readlines()]: + if lin.startswith("--START-COMMIT--"): + commit_hash = lin[16:].strip() + if buf != []: + process_commit(buf, files, subtree_path) + + if commit_hash in release_refs: + version_str = release_refs[commit_hash] + print(f'=== release {version_str} ===\n') + + buf = [] + files = [] + filemode = False + elif lin.startswith("--END-COMMIT--"): + filemode = True + elif filemode is True: + files.append(lin) + else: + buf.append(lin) + if buf != []: + process_commit(buf, files, subtree_path) + + +def get_commit_date_for_ref(ref): + cmd = ['git', 'log', '--pretty=format:%cI', '-1', ref] + r = subprocess.run(cmd, capture_output=True, text=True, + check=True, cwd=meson_source_root) + commit_date = r.stdout.strip() + return commit_date + + +def populate_release_tags_for_premonorepo_module(module_tag_prefix): + if module_tag_prefix != '': + cmd = ['git', 'tag', '--list', f'{module_tag_prefix}*'] + else: + cmd = ['git', 'tag', '--list', '1.*', 'RELEASE-*'] + + p = subprocess.Popen(args=cmd, shell=False, + stdout=subprocess.PIPE, cwd=meson_source_root) + for line in [x.decode('utf8') for x in p.stdout.readlines()]: + git_tag = line.strip() + version_str = git_tag.removeprefix(module_tag_prefix).removeprefix('RELEASE-').split('-')[0].replace('_', '.') + # might have been populated with post-monorepo tags already for gstreamer core + if version_str not in release_refs: + # find last commit before tag in module subdirectory + cmd = ['git', 'log', '--pretty=format:%H', '-1', git_tag] + r = subprocess.run(cmd, capture_output=True, + text=True, check=True, cwd=meson_source_root) + commit_hash = r.stdout.strip() + release_refs[commit_hash] = version_str + + # print(f'{git_tag} => {version_str} => {commit_hash}') + + +def populate_release_tags_for_monorepo_subproject(): + cmd = ['git', 'tag', '--list', '1.*'] + p = subprocess.Popen(args=cmd, shell=False, + stdout=subprocess.PIPE, cwd=meson_source_root) + for line in [x.decode('utf8') for x in p.stdout.readlines()]: + version_str = line.strip() + version_arr = version_str.split('.') + major = int(version_arr[0]) + minor = int(version_arr[1]) + micro = int(version_arr[2]) + # ignore pre-monorepo versions + if major < 1: + continue + if major == 1 and minor < 19: + continue + if major == 1 and minor == 19 and micro < 2: + continue + # find last commit before tag in module subdirectory + cmd = ['git', 'log', '--pretty=format:%H', + '-1', version_str, '--', '.'] + r = subprocess.run(cmd, capture_output=True, text=True, + check=True, cwd=meson_source_root) + commit_hash = r.stdout.strip() + release_refs[commit_hash] = version_str + + +if __name__ == '__main__': + module_tag_prefix = '' if module == 'gstreamer' else f'{module}-' + + populate_release_tags_for_monorepo_subproject() + + with open(output_fn, 'w') as f: + sys.stdout = f + + # Force writing of head tag + if head_tag and head_tag not in release_refs.values(): + print(f'=== release {head_tag} ===\n') + + # Output all commits from start_tag onwards, otherwise output full history. + # (We assume the start_tag is after the monorepo merge if it's specified.) + if start_tag and start_tag != 'start': + output_commits(module, start_tag, 'HEAD', f'subprojects/{module}/') + else: + # First output all post-monorepo commits or commits from start_tag if specified + output_commits(module, 'monorepo-start', + 'HEAD', f'subprojects/{module}/') + + populate_release_tags_for_premonorepo_module(module_tag_prefix) + + # Next output all pre-monorepo commits (modules have their own root) + if not start_tag: + module_start = f'{module_tag_prefix}1.0.0' + elif start_tag == 'start': + module_start = changelog_starts[module] + else: + module_start = f'{module_tag_prefix}{start_tag}' + + output_commits(module, module_start, + f'{module_tag_prefix}1.19.2', None) + + # Write start tag at end for clarity + if not start_tag: + print(f'=== release 1.0.0 ===\n') + elif start_tag != 'start': + print(f'=== release {start_tag} ===\n') diff --git a/subprojects/gst-editing-services/meson.build b/subprojects/gst-editing-services/meson.build index 86393ddca7..1d8c12ce98 100644 --- a/subprojects/gst-editing-services/meson.build +++ b/subprojects/gst-editing-services/meson.build @@ -309,6 +309,8 @@ endif configure_file(output: 'config.h', configuration: cdata) +meson.add_dist_script('scripts/gen-changelog.py', meson.project_name(), '1.20.0', meson.project_version()) + plugin_names = [] gst_plugins = [] foreach plugin: plugins diff --git a/subprojects/gst-editing-services/scripts/gen-changelog.py b/subprojects/gst-editing-services/scripts/gen-changelog.py new file mode 100755 index 0000000000..3924e6ea32 --- /dev/null +++ b/subprojects/gst-editing-services/scripts/gen-changelog.py @@ -0,0 +1,240 @@ +#!/usr/bin/env python3 +# +# Makes a GNU-Style ChangeLog from a git repository +import os +import sys +import subprocess +import re + +meson_source_root = os.environ.get('MESON_SOURCE_ROOT') + +meson_dist_root = os.environ.get('MESON_DIST_ROOT') +if meson_dist_root: + output_fn = os.path.join(meson_dist_root, 'ChangeLog') +else: + output_fn = sys.stdout.fileno() + +# commit hash => release version tag string +release_refs = {} + +# These are the pre-monorepo module beginnings +changelog_starts = { + 'gstreamer': '70521179a75db0c7230cc47c6d7f9d63cf73d351', + 'gst-plugins-base': '68746a38d5e48e6f7c220663dcc2f175ff55cb3c', + 'gst-plugins-good': '81f63142d65b62b0971c19ceb79956c49ffc2f06', + 'gst-plugins-ugly': '7d7c3e478e32b7b66c44cc4442d571fbab534740', + 'gst-plugins-bad': 'ea6821e2934fe8d356ea89d5610f0630b3446877', + 'gst-libav': '3c440154c60d1ec0a54186f0fad4aebfd2ecc3ea', + 'gst-rtsp-server': '5029c85a46a8c366c4bf272d503e22bbcd624ece', + 'gst-editing-services': 'ee8bf88ebf131cf7c7161356540efc20bf411e14', + 'gst-python': 'b3e564eff577e2f577d795051bbcca85d47c89dc', + 'gstreamer-vaapi': 'c89e9afc5d43837c498a55f8f13ddf235442b83b', + 'gst-omx': 'd2463b017f222e678978582544a9c9a80edfd330', + 'gst-devtools': 'da962d096af9460502843e41b7d25fdece7ff1c2', + 'gstreamer-sharp': 'b94528f8e7979df49fedf137dfa228d8fe475e1b', +} + + +def print_help(): + print('', file=sys.stderr) + print('gen-changelog: generate GNU-style changelog from git history', + file=sys.stderr) + print('', file=sys.stderr) + print('Usage: {} [OPTIONS] GSTREAMER-MODULE [START-TAG] [HEAD-TAG]'.format( + sys.argv[0]), file=sys.stderr) + print('', file=sys.stderr) + sys.exit(1) + + +if len(sys.argv) < 2 or len(sys.argv) > 4 or '--help' in sys.argv: + print_help() + +module = sys.argv[1] + +if len(sys.argv) > 2: + start_tag = sys.argv[2] +else: + start_tag = None + +if len(sys.argv) > 3: + head_tag = sys.argv[3] +else: + head_tag = None + +if module not in changelog_starts: + print(f'Unknown module {module}', file=sys.stderr) + print_help() + + +def process_commit(lines, files, subtree_path=None): + # DATE NAME + # BLANK LINE + # Subject + # BLANK LINE + # ... + # FILES + fileincommit = False + lines = [x.strip() for x in lines if x.strip() + and not x.startswith('git-svn-id')] + files = [x.strip() for x in files if x.strip()] + for line in lines: + if line.startswith('* ') and ':' in line: + fileincommit = True + break + + top_line = lines[0] + print(top_line.strip()) + print() + if not fileincommit: + for f in files: + if subtree_path and f.startswith(subtree_path): + # requires Python 3.9 + print('\t* %s:' % f.removeprefix(subtree_path)) + else: + print('\t* %s:' % f) + for line in lines[1:]: + print('\t ', line) + print() + + +def output_commits(module, start_tag, end_tag, subtree_path=None): + # retrieve commit date for start tag so we can filter the log for commits + # after that date. That way we don't include commits from merged-in + # plugin-move branches that go back to the beginning of time. + start_date = get_commit_date_for_ref(start_tag) + + cmd = ['git', 'log', + '--pretty=format:--START-COMMIT--%H%n%ai %an <%ae>%n%n%s%n%b%n--END-COMMIT--', + '--date=short', + '--name-only', + f'--since={start_date}', + f'{start_tag}..{end_tag}', + ] + + if subtree_path: + cmd += ['--', '.'] + + p = subprocess.Popen(args=cmd, shell=False, + stdout=subprocess.PIPE, cwd=meson_source_root) + buf = [] + files = [] + filemode = False + for lin in [x.decode('utf8', errors='replace') for x in p.stdout.readlines()]: + if lin.startswith("--START-COMMIT--"): + commit_hash = lin[16:].strip() + if buf != []: + process_commit(buf, files, subtree_path) + + if commit_hash in release_refs: + version_str = release_refs[commit_hash] + print(f'=== release {version_str} ===\n') + + buf = [] + files = [] + filemode = False + elif lin.startswith("--END-COMMIT--"): + filemode = True + elif filemode is True: + files.append(lin) + else: + buf.append(lin) + if buf != []: + process_commit(buf, files, subtree_path) + + +def get_commit_date_for_ref(ref): + cmd = ['git', 'log', '--pretty=format:%cI', '-1', ref] + r = subprocess.run(cmd, capture_output=True, text=True, + check=True, cwd=meson_source_root) + commit_date = r.stdout.strip() + return commit_date + + +def populate_release_tags_for_premonorepo_module(module_tag_prefix): + if module_tag_prefix != '': + cmd = ['git', 'tag', '--list', f'{module_tag_prefix}*'] + else: + cmd = ['git', 'tag', '--list', '1.*', 'RELEASE-*'] + + p = subprocess.Popen(args=cmd, shell=False, + stdout=subprocess.PIPE, cwd=meson_source_root) + for line in [x.decode('utf8') for x in p.stdout.readlines()]: + git_tag = line.strip() + version_str = git_tag.removeprefix(module_tag_prefix).removeprefix('RELEASE-').split('-')[0].replace('_', '.') + # might have been populated with post-monorepo tags already for gstreamer core + if version_str not in release_refs: + # find last commit before tag in module subdirectory + cmd = ['git', 'log', '--pretty=format:%H', '-1', git_tag] + r = subprocess.run(cmd, capture_output=True, + text=True, check=True, cwd=meson_source_root) + commit_hash = r.stdout.strip() + release_refs[commit_hash] = version_str + + # print(f'{git_tag} => {version_str} => {commit_hash}') + + +def populate_release_tags_for_monorepo_subproject(): + cmd = ['git', 'tag', '--list', '1.*'] + p = subprocess.Popen(args=cmd, shell=False, + stdout=subprocess.PIPE, cwd=meson_source_root) + for line in [x.decode('utf8') for x in p.stdout.readlines()]: + version_str = line.strip() + version_arr = version_str.split('.') + major = int(version_arr[0]) + minor = int(version_arr[1]) + micro = int(version_arr[2]) + # ignore pre-monorepo versions + if major < 1: + continue + if major == 1 and minor < 19: + continue + if major == 1 and minor == 19 and micro < 2: + continue + # find last commit before tag in module subdirectory + cmd = ['git', 'log', '--pretty=format:%H', + '-1', version_str, '--', '.'] + r = subprocess.run(cmd, capture_output=True, text=True, + check=True, cwd=meson_source_root) + commit_hash = r.stdout.strip() + release_refs[commit_hash] = version_str + + +if __name__ == '__main__': + module_tag_prefix = '' if module == 'gstreamer' else f'{module}-' + + populate_release_tags_for_monorepo_subproject() + + with open(output_fn, 'w') as f: + sys.stdout = f + + # Force writing of head tag + if head_tag and head_tag not in release_refs.values(): + print(f'=== release {head_tag} ===\n') + + # Output all commits from start_tag onwards, otherwise output full history. + # (We assume the start_tag is after the monorepo merge if it's specified.) + if start_tag and start_tag != 'start': + output_commits(module, start_tag, 'HEAD', f'subprojects/{module}/') + else: + # First output all post-monorepo commits or commits from start_tag if specified + output_commits(module, 'monorepo-start', + 'HEAD', f'subprojects/{module}/') + + populate_release_tags_for_premonorepo_module(module_tag_prefix) + + # Next output all pre-monorepo commits (modules have their own root) + if not start_tag: + module_start = f'{module_tag_prefix}1.0.0' + elif start_tag == 'start': + module_start = changelog_starts[module] + else: + module_start = f'{module_tag_prefix}{start_tag}' + + output_commits(module, module_start, + f'{module_tag_prefix}1.19.2', None) + + # Write start tag at end for clarity + if not start_tag: + print(f'=== release 1.0.0 ===\n') + elif start_tag != 'start': + print(f'=== release {start_tag} ===\n') diff --git a/subprojects/gst-libav/meson.build b/subprojects/gst-libav/meson.build index c53c69951c..a26df50ad4 100644 --- a/subprojects/gst-libav/meson.build +++ b/subprojects/gst-libav/meson.build @@ -236,6 +236,8 @@ endif configure_file(output: 'config.h', configuration: cdata) +meson.add_dist_script('scripts/gen-changelog.py', meson.project_name(), '1.20.0', meson.project_version()) + gst_plugins = [] foreach plugin: plugins pkgconfig.generate(plugin, install_dir: plugins_pkgconfig_install_dir) diff --git a/subprojects/gst-libav/scripts/gen-changelog.py b/subprojects/gst-libav/scripts/gen-changelog.py new file mode 100755 index 0000000000..3924e6ea32 --- /dev/null +++ b/subprojects/gst-libav/scripts/gen-changelog.py @@ -0,0 +1,240 @@ +#!/usr/bin/env python3 +# +# Makes a GNU-Style ChangeLog from a git repository +import os +import sys +import subprocess +import re + +meson_source_root = os.environ.get('MESON_SOURCE_ROOT') + +meson_dist_root = os.environ.get('MESON_DIST_ROOT') +if meson_dist_root: + output_fn = os.path.join(meson_dist_root, 'ChangeLog') +else: + output_fn = sys.stdout.fileno() + +# commit hash => release version tag string +release_refs = {} + +# These are the pre-monorepo module beginnings +changelog_starts = { + 'gstreamer': '70521179a75db0c7230cc47c6d7f9d63cf73d351', + 'gst-plugins-base': '68746a38d5e48e6f7c220663dcc2f175ff55cb3c', + 'gst-plugins-good': '81f63142d65b62b0971c19ceb79956c49ffc2f06', + 'gst-plugins-ugly': '7d7c3e478e32b7b66c44cc4442d571fbab534740', + 'gst-plugins-bad': 'ea6821e2934fe8d356ea89d5610f0630b3446877', + 'gst-libav': '3c440154c60d1ec0a54186f0fad4aebfd2ecc3ea', + 'gst-rtsp-server': '5029c85a46a8c366c4bf272d503e22bbcd624ece', + 'gst-editing-services': 'ee8bf88ebf131cf7c7161356540efc20bf411e14', + 'gst-python': 'b3e564eff577e2f577d795051bbcca85d47c89dc', + 'gstreamer-vaapi': 'c89e9afc5d43837c498a55f8f13ddf235442b83b', + 'gst-omx': 'd2463b017f222e678978582544a9c9a80edfd330', + 'gst-devtools': 'da962d096af9460502843e41b7d25fdece7ff1c2', + 'gstreamer-sharp': 'b94528f8e7979df49fedf137dfa228d8fe475e1b', +} + + +def print_help(): + print('', file=sys.stderr) + print('gen-changelog: generate GNU-style changelog from git history', + file=sys.stderr) + print('', file=sys.stderr) + print('Usage: {} [OPTIONS] GSTREAMER-MODULE [START-TAG] [HEAD-TAG]'.format( + sys.argv[0]), file=sys.stderr) + print('', file=sys.stderr) + sys.exit(1) + + +if len(sys.argv) < 2 or len(sys.argv) > 4 or '--help' in sys.argv: + print_help() + +module = sys.argv[1] + +if len(sys.argv) > 2: + start_tag = sys.argv[2] +else: + start_tag = None + +if len(sys.argv) > 3: + head_tag = sys.argv[3] +else: + head_tag = None + +if module not in changelog_starts: + print(f'Unknown module {module}', file=sys.stderr) + print_help() + + +def process_commit(lines, files, subtree_path=None): + # DATE NAME + # BLANK LINE + # Subject + # BLANK LINE + # ... + # FILES + fileincommit = False + lines = [x.strip() for x in lines if x.strip() + and not x.startswith('git-svn-id')] + files = [x.strip() for x in files if x.strip()] + for line in lines: + if line.startswith('* ') and ':' in line: + fileincommit = True + break + + top_line = lines[0] + print(top_line.strip()) + print() + if not fileincommit: + for f in files: + if subtree_path and f.startswith(subtree_path): + # requires Python 3.9 + print('\t* %s:' % f.removeprefix(subtree_path)) + else: + print('\t* %s:' % f) + for line in lines[1:]: + print('\t ', line) + print() + + +def output_commits(module, start_tag, end_tag, subtree_path=None): + # retrieve commit date for start tag so we can filter the log for commits + # after that date. That way we don't include commits from merged-in + # plugin-move branches that go back to the beginning of time. + start_date = get_commit_date_for_ref(start_tag) + + cmd = ['git', 'log', + '--pretty=format:--START-COMMIT--%H%n%ai %an <%ae>%n%n%s%n%b%n--END-COMMIT--', + '--date=short', + '--name-only', + f'--since={start_date}', + f'{start_tag}..{end_tag}', + ] + + if subtree_path: + cmd += ['--', '.'] + + p = subprocess.Popen(args=cmd, shell=False, + stdout=subprocess.PIPE, cwd=meson_source_root) + buf = [] + files = [] + filemode = False + for lin in [x.decode('utf8', errors='replace') for x in p.stdout.readlines()]: + if lin.startswith("--START-COMMIT--"): + commit_hash = lin[16:].strip() + if buf != []: + process_commit(buf, files, subtree_path) + + if commit_hash in release_refs: + version_str = release_refs[commit_hash] + print(f'=== release {version_str} ===\n') + + buf = [] + files = [] + filemode = False + elif lin.startswith("--END-COMMIT--"): + filemode = True + elif filemode is True: + files.append(lin) + else: + buf.append(lin) + if buf != []: + process_commit(buf, files, subtree_path) + + +def get_commit_date_for_ref(ref): + cmd = ['git', 'log', '--pretty=format:%cI', '-1', ref] + r = subprocess.run(cmd, capture_output=True, text=True, + check=True, cwd=meson_source_root) + commit_date = r.stdout.strip() + return commit_date + + +def populate_release_tags_for_premonorepo_module(module_tag_prefix): + if module_tag_prefix != '': + cmd = ['git', 'tag', '--list', f'{module_tag_prefix}*'] + else: + cmd = ['git', 'tag', '--list', '1.*', 'RELEASE-*'] + + p = subprocess.Popen(args=cmd, shell=False, + stdout=subprocess.PIPE, cwd=meson_source_root) + for line in [x.decode('utf8') for x in p.stdout.readlines()]: + git_tag = line.strip() + version_str = git_tag.removeprefix(module_tag_prefix).removeprefix('RELEASE-').split('-')[0].replace('_', '.') + # might have been populated with post-monorepo tags already for gstreamer core + if version_str not in release_refs: + # find last commit before tag in module subdirectory + cmd = ['git', 'log', '--pretty=format:%H', '-1', git_tag] + r = subprocess.run(cmd, capture_output=True, + text=True, check=True, cwd=meson_source_root) + commit_hash = r.stdout.strip() + release_refs[commit_hash] = version_str + + # print(f'{git_tag} => {version_str} => {commit_hash}') + + +def populate_release_tags_for_monorepo_subproject(): + cmd = ['git', 'tag', '--list', '1.*'] + p = subprocess.Popen(args=cmd, shell=False, + stdout=subprocess.PIPE, cwd=meson_source_root) + for line in [x.decode('utf8') for x in p.stdout.readlines()]: + version_str = line.strip() + version_arr = version_str.split('.') + major = int(version_arr[0]) + minor = int(version_arr[1]) + micro = int(version_arr[2]) + # ignore pre-monorepo versions + if major < 1: + continue + if major == 1 and minor < 19: + continue + if major == 1 and minor == 19 and micro < 2: + continue + # find last commit before tag in module subdirectory + cmd = ['git', 'log', '--pretty=format:%H', + '-1', version_str, '--', '.'] + r = subprocess.run(cmd, capture_output=True, text=True, + check=True, cwd=meson_source_root) + commit_hash = r.stdout.strip() + release_refs[commit_hash] = version_str + + +if __name__ == '__main__': + module_tag_prefix = '' if module == 'gstreamer' else f'{module}-' + + populate_release_tags_for_monorepo_subproject() + + with open(output_fn, 'w') as f: + sys.stdout = f + + # Force writing of head tag + if head_tag and head_tag not in release_refs.values(): + print(f'=== release {head_tag} ===\n') + + # Output all commits from start_tag onwards, otherwise output full history. + # (We assume the start_tag is after the monorepo merge if it's specified.) + if start_tag and start_tag != 'start': + output_commits(module, start_tag, 'HEAD', f'subprojects/{module}/') + else: + # First output all post-monorepo commits or commits from start_tag if specified + output_commits(module, 'monorepo-start', + 'HEAD', f'subprojects/{module}/') + + populate_release_tags_for_premonorepo_module(module_tag_prefix) + + # Next output all pre-monorepo commits (modules have their own root) + if not start_tag: + module_start = f'{module_tag_prefix}1.0.0' + elif start_tag == 'start': + module_start = changelog_starts[module] + else: + module_start = f'{module_tag_prefix}{start_tag}' + + output_commits(module, module_start, + f'{module_tag_prefix}1.19.2', None) + + # Write start tag at end for clarity + if not start_tag: + print(f'=== release 1.0.0 ===\n') + elif start_tag != 'start': + print(f'=== release {start_tag} ===\n') diff --git a/subprojects/gst-omx/meson.build b/subprojects/gst-omx/meson.build index bcfa1fd0f3..c68c650f72 100644 --- a/subprojects/gst-omx/meson.build +++ b/subprojects/gst-omx/meson.build @@ -425,3 +425,5 @@ if gst_version_nano == 0 endif configure_file(output: 'config.h', configuration: cdata) + +meson.add_dist_script('scripts/gen-changelog.py', meson.project_name(), '1.20.0', meson.project_version()) diff --git a/subprojects/gst-omx/scripts/gen-changelog.py b/subprojects/gst-omx/scripts/gen-changelog.py new file mode 100755 index 0000000000..3924e6ea32 --- /dev/null +++ b/subprojects/gst-omx/scripts/gen-changelog.py @@ -0,0 +1,240 @@ +#!/usr/bin/env python3 +# +# Makes a GNU-Style ChangeLog from a git repository +import os +import sys +import subprocess +import re + +meson_source_root = os.environ.get('MESON_SOURCE_ROOT') + +meson_dist_root = os.environ.get('MESON_DIST_ROOT') +if meson_dist_root: + output_fn = os.path.join(meson_dist_root, 'ChangeLog') +else: + output_fn = sys.stdout.fileno() + +# commit hash => release version tag string +release_refs = {} + +# These are the pre-monorepo module beginnings +changelog_starts = { + 'gstreamer': '70521179a75db0c7230cc47c6d7f9d63cf73d351', + 'gst-plugins-base': '68746a38d5e48e6f7c220663dcc2f175ff55cb3c', + 'gst-plugins-good': '81f63142d65b62b0971c19ceb79956c49ffc2f06', + 'gst-plugins-ugly': '7d7c3e478e32b7b66c44cc4442d571fbab534740', + 'gst-plugins-bad': 'ea6821e2934fe8d356ea89d5610f0630b3446877', + 'gst-libav': '3c440154c60d1ec0a54186f0fad4aebfd2ecc3ea', + 'gst-rtsp-server': '5029c85a46a8c366c4bf272d503e22bbcd624ece', + 'gst-editing-services': 'ee8bf88ebf131cf7c7161356540efc20bf411e14', + 'gst-python': 'b3e564eff577e2f577d795051bbcca85d47c89dc', + 'gstreamer-vaapi': 'c89e9afc5d43837c498a55f8f13ddf235442b83b', + 'gst-omx': 'd2463b017f222e678978582544a9c9a80edfd330', + 'gst-devtools': 'da962d096af9460502843e41b7d25fdece7ff1c2', + 'gstreamer-sharp': 'b94528f8e7979df49fedf137dfa228d8fe475e1b', +} + + +def print_help(): + print('', file=sys.stderr) + print('gen-changelog: generate GNU-style changelog from git history', + file=sys.stderr) + print('', file=sys.stderr) + print('Usage: {} [OPTIONS] GSTREAMER-MODULE [START-TAG] [HEAD-TAG]'.format( + sys.argv[0]), file=sys.stderr) + print('', file=sys.stderr) + sys.exit(1) + + +if len(sys.argv) < 2 or len(sys.argv) > 4 or '--help' in sys.argv: + print_help() + +module = sys.argv[1] + +if len(sys.argv) > 2: + start_tag = sys.argv[2] +else: + start_tag = None + +if len(sys.argv) > 3: + head_tag = sys.argv[3] +else: + head_tag = None + +if module not in changelog_starts: + print(f'Unknown module {module}', file=sys.stderr) + print_help() + + +def process_commit(lines, files, subtree_path=None): + # DATE NAME + # BLANK LINE + # Subject + # BLANK LINE + # ... + # FILES + fileincommit = False + lines = [x.strip() for x in lines if x.strip() + and not x.startswith('git-svn-id')] + files = [x.strip() for x in files if x.strip()] + for line in lines: + if line.startswith('* ') and ':' in line: + fileincommit = True + break + + top_line = lines[0] + print(top_line.strip()) + print() + if not fileincommit: + for f in files: + if subtree_path and f.startswith(subtree_path): + # requires Python 3.9 + print('\t* %s:' % f.removeprefix(subtree_path)) + else: + print('\t* %s:' % f) + for line in lines[1:]: + print('\t ', line) + print() + + +def output_commits(module, start_tag, end_tag, subtree_path=None): + # retrieve commit date for start tag so we can filter the log for commits + # after that date. That way we don't include commits from merged-in + # plugin-move branches that go back to the beginning of time. + start_date = get_commit_date_for_ref(start_tag) + + cmd = ['git', 'log', + '--pretty=format:--START-COMMIT--%H%n%ai %an <%ae>%n%n%s%n%b%n--END-COMMIT--', + '--date=short', + '--name-only', + f'--since={start_date}', + f'{start_tag}..{end_tag}', + ] + + if subtree_path: + cmd += ['--', '.'] + + p = subprocess.Popen(args=cmd, shell=False, + stdout=subprocess.PIPE, cwd=meson_source_root) + buf = [] + files = [] + filemode = False + for lin in [x.decode('utf8', errors='replace') for x in p.stdout.readlines()]: + if lin.startswith("--START-COMMIT--"): + commit_hash = lin[16:].strip() + if buf != []: + process_commit(buf, files, subtree_path) + + if commit_hash in release_refs: + version_str = release_refs[commit_hash] + print(f'=== release {version_str} ===\n') + + buf = [] + files = [] + filemode = False + elif lin.startswith("--END-COMMIT--"): + filemode = True + elif filemode is True: + files.append(lin) + else: + buf.append(lin) + if buf != []: + process_commit(buf, files, subtree_path) + + +def get_commit_date_for_ref(ref): + cmd = ['git', 'log', '--pretty=format:%cI', '-1', ref] + r = subprocess.run(cmd, capture_output=True, text=True, + check=True, cwd=meson_source_root) + commit_date = r.stdout.strip() + return commit_date + + +def populate_release_tags_for_premonorepo_module(module_tag_prefix): + if module_tag_prefix != '': + cmd = ['git', 'tag', '--list', f'{module_tag_prefix}*'] + else: + cmd = ['git', 'tag', '--list', '1.*', 'RELEASE-*'] + + p = subprocess.Popen(args=cmd, shell=False, + stdout=subprocess.PIPE, cwd=meson_source_root) + for line in [x.decode('utf8') for x in p.stdout.readlines()]: + git_tag = line.strip() + version_str = git_tag.removeprefix(module_tag_prefix).removeprefix('RELEASE-').split('-')[0].replace('_', '.') + # might have been populated with post-monorepo tags already for gstreamer core + if version_str not in release_refs: + # find last commit before tag in module subdirectory + cmd = ['git', 'log', '--pretty=format:%H', '-1', git_tag] + r = subprocess.run(cmd, capture_output=True, + text=True, check=True, cwd=meson_source_root) + commit_hash = r.stdout.strip() + release_refs[commit_hash] = version_str + + # print(f'{git_tag} => {version_str} => {commit_hash}') + + +def populate_release_tags_for_monorepo_subproject(): + cmd = ['git', 'tag', '--list', '1.*'] + p = subprocess.Popen(args=cmd, shell=False, + stdout=subprocess.PIPE, cwd=meson_source_root) + for line in [x.decode('utf8') for x in p.stdout.readlines()]: + version_str = line.strip() + version_arr = version_str.split('.') + major = int(version_arr[0]) + minor = int(version_arr[1]) + micro = int(version_arr[2]) + # ignore pre-monorepo versions + if major < 1: + continue + if major == 1 and minor < 19: + continue + if major == 1 and minor == 19 and micro < 2: + continue + # find last commit before tag in module subdirectory + cmd = ['git', 'log', '--pretty=format:%H', + '-1', version_str, '--', '.'] + r = subprocess.run(cmd, capture_output=True, text=True, + check=True, cwd=meson_source_root) + commit_hash = r.stdout.strip() + release_refs[commit_hash] = version_str + + +if __name__ == '__main__': + module_tag_prefix = '' if module == 'gstreamer' else f'{module}-' + + populate_release_tags_for_monorepo_subproject() + + with open(output_fn, 'w') as f: + sys.stdout = f + + # Force writing of head tag + if head_tag and head_tag not in release_refs.values(): + print(f'=== release {head_tag} ===\n') + + # Output all commits from start_tag onwards, otherwise output full history. + # (We assume the start_tag is after the monorepo merge if it's specified.) + if start_tag and start_tag != 'start': + output_commits(module, start_tag, 'HEAD', f'subprojects/{module}/') + else: + # First output all post-monorepo commits or commits from start_tag if specified + output_commits(module, 'monorepo-start', + 'HEAD', f'subprojects/{module}/') + + populate_release_tags_for_premonorepo_module(module_tag_prefix) + + # Next output all pre-monorepo commits (modules have their own root) + if not start_tag: + module_start = f'{module_tag_prefix}1.0.0' + elif start_tag == 'start': + module_start = changelog_starts[module] + else: + module_start = f'{module_tag_prefix}{start_tag}' + + output_commits(module, module_start, + f'{module_tag_prefix}1.19.2', None) + + # Write start tag at end for clarity + if not start_tag: + print(f'=== release 1.0.0 ===\n') + elif start_tag != 'start': + print(f'=== release {start_tag} ===\n') diff --git a/subprojects/gst-plugins-bad/meson.build b/subprojects/gst-plugins-bad/meson.build index ae4a0ba79d..8a8ff56155 100644 --- a/subprojects/gst-plugins-bad/meson.build +++ b/subprojects/gst-plugins-bad/meson.build @@ -600,6 +600,8 @@ endif configure_file(output : 'config.h', configuration : cdata) +meson.add_dist_script('scripts/gen-changelog.py', meson.project_name(), '1.20.0', meson.project_version()) + subdir('docs') plugin_names = [] diff --git a/subprojects/gst-plugins-bad/scripts/gen-changelog.py b/subprojects/gst-plugins-bad/scripts/gen-changelog.py new file mode 100755 index 0000000000..3924e6ea32 --- /dev/null +++ b/subprojects/gst-plugins-bad/scripts/gen-changelog.py @@ -0,0 +1,240 @@ +#!/usr/bin/env python3 +# +# Makes a GNU-Style ChangeLog from a git repository +import os +import sys +import subprocess +import re + +meson_source_root = os.environ.get('MESON_SOURCE_ROOT') + +meson_dist_root = os.environ.get('MESON_DIST_ROOT') +if meson_dist_root: + output_fn = os.path.join(meson_dist_root, 'ChangeLog') +else: + output_fn = sys.stdout.fileno() + +# commit hash => release version tag string +release_refs = {} + +# These are the pre-monorepo module beginnings +changelog_starts = { + 'gstreamer': '70521179a75db0c7230cc47c6d7f9d63cf73d351', + 'gst-plugins-base': '68746a38d5e48e6f7c220663dcc2f175ff55cb3c', + 'gst-plugins-good': '81f63142d65b62b0971c19ceb79956c49ffc2f06', + 'gst-plugins-ugly': '7d7c3e478e32b7b66c44cc4442d571fbab534740', + 'gst-plugins-bad': 'ea6821e2934fe8d356ea89d5610f0630b3446877', + 'gst-libav': '3c440154c60d1ec0a54186f0fad4aebfd2ecc3ea', + 'gst-rtsp-server': '5029c85a46a8c366c4bf272d503e22bbcd624ece', + 'gst-editing-services': 'ee8bf88ebf131cf7c7161356540efc20bf411e14', + 'gst-python': 'b3e564eff577e2f577d795051bbcca85d47c89dc', + 'gstreamer-vaapi': 'c89e9afc5d43837c498a55f8f13ddf235442b83b', + 'gst-omx': 'd2463b017f222e678978582544a9c9a80edfd330', + 'gst-devtools': 'da962d096af9460502843e41b7d25fdece7ff1c2', + 'gstreamer-sharp': 'b94528f8e7979df49fedf137dfa228d8fe475e1b', +} + + +def print_help(): + print('', file=sys.stderr) + print('gen-changelog: generate GNU-style changelog from git history', + file=sys.stderr) + print('', file=sys.stderr) + print('Usage: {} [OPTIONS] GSTREAMER-MODULE [START-TAG] [HEAD-TAG]'.format( + sys.argv[0]), file=sys.stderr) + print('', file=sys.stderr) + sys.exit(1) + + +if len(sys.argv) < 2 or len(sys.argv) > 4 or '--help' in sys.argv: + print_help() + +module = sys.argv[1] + +if len(sys.argv) > 2: + start_tag = sys.argv[2] +else: + start_tag = None + +if len(sys.argv) > 3: + head_tag = sys.argv[3] +else: + head_tag = None + +if module not in changelog_starts: + print(f'Unknown module {module}', file=sys.stderr) + print_help() + + +def process_commit(lines, files, subtree_path=None): + # DATE NAME + # BLANK LINE + # Subject + # BLANK LINE + # ... + # FILES + fileincommit = False + lines = [x.strip() for x in lines if x.strip() + and not x.startswith('git-svn-id')] + files = [x.strip() for x in files if x.strip()] + for line in lines: + if line.startswith('* ') and ':' in line: + fileincommit = True + break + + top_line = lines[0] + print(top_line.strip()) + print() + if not fileincommit: + for f in files: + if subtree_path and f.startswith(subtree_path): + # requires Python 3.9 + print('\t* %s:' % f.removeprefix(subtree_path)) + else: + print('\t* %s:' % f) + for line in lines[1:]: + print('\t ', line) + print() + + +def output_commits(module, start_tag, end_tag, subtree_path=None): + # retrieve commit date for start tag so we can filter the log for commits + # after that date. That way we don't include commits from merged-in + # plugin-move branches that go back to the beginning of time. + start_date = get_commit_date_for_ref(start_tag) + + cmd = ['git', 'log', + '--pretty=format:--START-COMMIT--%H%n%ai %an <%ae>%n%n%s%n%b%n--END-COMMIT--', + '--date=short', + '--name-only', + f'--since={start_date}', + f'{start_tag}..{end_tag}', + ] + + if subtree_path: + cmd += ['--', '.'] + + p = subprocess.Popen(args=cmd, shell=False, + stdout=subprocess.PIPE, cwd=meson_source_root) + buf = [] + files = [] + filemode = False + for lin in [x.decode('utf8', errors='replace') for x in p.stdout.readlines()]: + if lin.startswith("--START-COMMIT--"): + commit_hash = lin[16:].strip() + if buf != []: + process_commit(buf, files, subtree_path) + + if commit_hash in release_refs: + version_str = release_refs[commit_hash] + print(f'=== release {version_str} ===\n') + + buf = [] + files = [] + filemode = False + elif lin.startswith("--END-COMMIT--"): + filemode = True + elif filemode is True: + files.append(lin) + else: + buf.append(lin) + if buf != []: + process_commit(buf, files, subtree_path) + + +def get_commit_date_for_ref(ref): + cmd = ['git', 'log', '--pretty=format:%cI', '-1', ref] + r = subprocess.run(cmd, capture_output=True, text=True, + check=True, cwd=meson_source_root) + commit_date = r.stdout.strip() + return commit_date + + +def populate_release_tags_for_premonorepo_module(module_tag_prefix): + if module_tag_prefix != '': + cmd = ['git', 'tag', '--list', f'{module_tag_prefix}*'] + else: + cmd = ['git', 'tag', '--list', '1.*', 'RELEASE-*'] + + p = subprocess.Popen(args=cmd, shell=False, + stdout=subprocess.PIPE, cwd=meson_source_root) + for line in [x.decode('utf8') for x in p.stdout.readlines()]: + git_tag = line.strip() + version_str = git_tag.removeprefix(module_tag_prefix).removeprefix('RELEASE-').split('-')[0].replace('_', '.') + # might have been populated with post-monorepo tags already for gstreamer core + if version_str not in release_refs: + # find last commit before tag in module subdirectory + cmd = ['git', 'log', '--pretty=format:%H', '-1', git_tag] + r = subprocess.run(cmd, capture_output=True, + text=True, check=True, cwd=meson_source_root) + commit_hash = r.stdout.strip() + release_refs[commit_hash] = version_str + + # print(f'{git_tag} => {version_str} => {commit_hash}') + + +def populate_release_tags_for_monorepo_subproject(): + cmd = ['git', 'tag', '--list', '1.*'] + p = subprocess.Popen(args=cmd, shell=False, + stdout=subprocess.PIPE, cwd=meson_source_root) + for line in [x.decode('utf8') for x in p.stdout.readlines()]: + version_str = line.strip() + version_arr = version_str.split('.') + major = int(version_arr[0]) + minor = int(version_arr[1]) + micro = int(version_arr[2]) + # ignore pre-monorepo versions + if major < 1: + continue + if major == 1 and minor < 19: + continue + if major == 1 and minor == 19 and micro < 2: + continue + # find last commit before tag in module subdirectory + cmd = ['git', 'log', '--pretty=format:%H', + '-1', version_str, '--', '.'] + r = subprocess.run(cmd, capture_output=True, text=True, + check=True, cwd=meson_source_root) + commit_hash = r.stdout.strip() + release_refs[commit_hash] = version_str + + +if __name__ == '__main__': + module_tag_prefix = '' if module == 'gstreamer' else f'{module}-' + + populate_release_tags_for_monorepo_subproject() + + with open(output_fn, 'w') as f: + sys.stdout = f + + # Force writing of head tag + if head_tag and head_tag not in release_refs.values(): + print(f'=== release {head_tag} ===\n') + + # Output all commits from start_tag onwards, otherwise output full history. + # (We assume the start_tag is after the monorepo merge if it's specified.) + if start_tag and start_tag != 'start': + output_commits(module, start_tag, 'HEAD', f'subprojects/{module}/') + else: + # First output all post-monorepo commits or commits from start_tag if specified + output_commits(module, 'monorepo-start', + 'HEAD', f'subprojects/{module}/') + + populate_release_tags_for_premonorepo_module(module_tag_prefix) + + # Next output all pre-monorepo commits (modules have their own root) + if not start_tag: + module_start = f'{module_tag_prefix}1.0.0' + elif start_tag == 'start': + module_start = changelog_starts[module] + else: + module_start = f'{module_tag_prefix}{start_tag}' + + output_commits(module, module_start, + f'{module_tag_prefix}1.19.2', None) + + # Write start tag at end for clarity + if not start_tag: + print(f'=== release 1.0.0 ===\n') + elif start_tag != 'start': + print(f'=== release {start_tag} ===\n') diff --git a/subprojects/gst-plugins-base/meson.build b/subprojects/gst-plugins-base/meson.build index 83a341c337..e42c2024a1 100644 --- a/subprojects/gst-plugins-base/meson.build +++ b/subprojects/gst-plugins-base/meson.build @@ -550,6 +550,8 @@ endif # Use core_conf after all subdirs have set values configure_file(output : 'config.h', configuration : core_conf) +meson.add_dist_script('scripts/gen-changelog.py', meson.project_name(), '1.20.0', meson.project_version()) + plugin_names = [] gst_plugins = [] foreach plugin: plugins diff --git a/subprojects/gst-plugins-base/scripts/gen-changelog.py b/subprojects/gst-plugins-base/scripts/gen-changelog.py new file mode 100755 index 0000000000..3924e6ea32 --- /dev/null +++ b/subprojects/gst-plugins-base/scripts/gen-changelog.py @@ -0,0 +1,240 @@ +#!/usr/bin/env python3 +# +# Makes a GNU-Style ChangeLog from a git repository +import os +import sys +import subprocess +import re + +meson_source_root = os.environ.get('MESON_SOURCE_ROOT') + +meson_dist_root = os.environ.get('MESON_DIST_ROOT') +if meson_dist_root: + output_fn = os.path.join(meson_dist_root, 'ChangeLog') +else: + output_fn = sys.stdout.fileno() + +# commit hash => release version tag string +release_refs = {} + +# These are the pre-monorepo module beginnings +changelog_starts = { + 'gstreamer': '70521179a75db0c7230cc47c6d7f9d63cf73d351', + 'gst-plugins-base': '68746a38d5e48e6f7c220663dcc2f175ff55cb3c', + 'gst-plugins-good': '81f63142d65b62b0971c19ceb79956c49ffc2f06', + 'gst-plugins-ugly': '7d7c3e478e32b7b66c44cc4442d571fbab534740', + 'gst-plugins-bad': 'ea6821e2934fe8d356ea89d5610f0630b3446877', + 'gst-libav': '3c440154c60d1ec0a54186f0fad4aebfd2ecc3ea', + 'gst-rtsp-server': '5029c85a46a8c366c4bf272d503e22bbcd624ece', + 'gst-editing-services': 'ee8bf88ebf131cf7c7161356540efc20bf411e14', + 'gst-python': 'b3e564eff577e2f577d795051bbcca85d47c89dc', + 'gstreamer-vaapi': 'c89e9afc5d43837c498a55f8f13ddf235442b83b', + 'gst-omx': 'd2463b017f222e678978582544a9c9a80edfd330', + 'gst-devtools': 'da962d096af9460502843e41b7d25fdece7ff1c2', + 'gstreamer-sharp': 'b94528f8e7979df49fedf137dfa228d8fe475e1b', +} + + +def print_help(): + print('', file=sys.stderr) + print('gen-changelog: generate GNU-style changelog from git history', + file=sys.stderr) + print('', file=sys.stderr) + print('Usage: {} [OPTIONS] GSTREAMER-MODULE [START-TAG] [HEAD-TAG]'.format( + sys.argv[0]), file=sys.stderr) + print('', file=sys.stderr) + sys.exit(1) + + +if len(sys.argv) < 2 or len(sys.argv) > 4 or '--help' in sys.argv: + print_help() + +module = sys.argv[1] + +if len(sys.argv) > 2: + start_tag = sys.argv[2] +else: + start_tag = None + +if len(sys.argv) > 3: + head_tag = sys.argv[3] +else: + head_tag = None + +if module not in changelog_starts: + print(f'Unknown module {module}', file=sys.stderr) + print_help() + + +def process_commit(lines, files, subtree_path=None): + # DATE NAME + # BLANK LINE + # Subject + # BLANK LINE + # ... + # FILES + fileincommit = False + lines = [x.strip() for x in lines if x.strip() + and not x.startswith('git-svn-id')] + files = [x.strip() for x in files if x.strip()] + for line in lines: + if line.startswith('* ') and ':' in line: + fileincommit = True + break + + top_line = lines[0] + print(top_line.strip()) + print() + if not fileincommit: + for f in files: + if subtree_path and f.startswith(subtree_path): + # requires Python 3.9 + print('\t* %s:' % f.removeprefix(subtree_path)) + else: + print('\t* %s:' % f) + for line in lines[1:]: + print('\t ', line) + print() + + +def output_commits(module, start_tag, end_tag, subtree_path=None): + # retrieve commit date for start tag so we can filter the log for commits + # after that date. That way we don't include commits from merged-in + # plugin-move branches that go back to the beginning of time. + start_date = get_commit_date_for_ref(start_tag) + + cmd = ['git', 'log', + '--pretty=format:--START-COMMIT--%H%n%ai %an <%ae>%n%n%s%n%b%n--END-COMMIT--', + '--date=short', + '--name-only', + f'--since={start_date}', + f'{start_tag}..{end_tag}', + ] + + if subtree_path: + cmd += ['--', '.'] + + p = subprocess.Popen(args=cmd, shell=False, + stdout=subprocess.PIPE, cwd=meson_source_root) + buf = [] + files = [] + filemode = False + for lin in [x.decode('utf8', errors='replace') for x in p.stdout.readlines()]: + if lin.startswith("--START-COMMIT--"): + commit_hash = lin[16:].strip() + if buf != []: + process_commit(buf, files, subtree_path) + + if commit_hash in release_refs: + version_str = release_refs[commit_hash] + print(f'=== release {version_str} ===\n') + + buf = [] + files = [] + filemode = False + elif lin.startswith("--END-COMMIT--"): + filemode = True + elif filemode is True: + files.append(lin) + else: + buf.append(lin) + if buf != []: + process_commit(buf, files, subtree_path) + + +def get_commit_date_for_ref(ref): + cmd = ['git', 'log', '--pretty=format:%cI', '-1', ref] + r = subprocess.run(cmd, capture_output=True, text=True, + check=True, cwd=meson_source_root) + commit_date = r.stdout.strip() + return commit_date + + +def populate_release_tags_for_premonorepo_module(module_tag_prefix): + if module_tag_prefix != '': + cmd = ['git', 'tag', '--list', f'{module_tag_prefix}*'] + else: + cmd = ['git', 'tag', '--list', '1.*', 'RELEASE-*'] + + p = subprocess.Popen(args=cmd, shell=False, + stdout=subprocess.PIPE, cwd=meson_source_root) + for line in [x.decode('utf8') for x in p.stdout.readlines()]: + git_tag = line.strip() + version_str = git_tag.removeprefix(module_tag_prefix).removeprefix('RELEASE-').split('-')[0].replace('_', '.') + # might have been populated with post-monorepo tags already for gstreamer core + if version_str not in release_refs: + # find last commit before tag in module subdirectory + cmd = ['git', 'log', '--pretty=format:%H', '-1', git_tag] + r = subprocess.run(cmd, capture_output=True, + text=True, check=True, cwd=meson_source_root) + commit_hash = r.stdout.strip() + release_refs[commit_hash] = version_str + + # print(f'{git_tag} => {version_str} => {commit_hash}') + + +def populate_release_tags_for_monorepo_subproject(): + cmd = ['git', 'tag', '--list', '1.*'] + p = subprocess.Popen(args=cmd, shell=False, + stdout=subprocess.PIPE, cwd=meson_source_root) + for line in [x.decode('utf8') for x in p.stdout.readlines()]: + version_str = line.strip() + version_arr = version_str.split('.') + major = int(version_arr[0]) + minor = int(version_arr[1]) + micro = int(version_arr[2]) + # ignore pre-monorepo versions + if major < 1: + continue + if major == 1 and minor < 19: + continue + if major == 1 and minor == 19 and micro < 2: + continue + # find last commit before tag in module subdirectory + cmd = ['git', 'log', '--pretty=format:%H', + '-1', version_str, '--', '.'] + r = subprocess.run(cmd, capture_output=True, text=True, + check=True, cwd=meson_source_root) + commit_hash = r.stdout.strip() + release_refs[commit_hash] = version_str + + +if __name__ == '__main__': + module_tag_prefix = '' if module == 'gstreamer' else f'{module}-' + + populate_release_tags_for_monorepo_subproject() + + with open(output_fn, 'w') as f: + sys.stdout = f + + # Force writing of head tag + if head_tag and head_tag not in release_refs.values(): + print(f'=== release {head_tag} ===\n') + + # Output all commits from start_tag onwards, otherwise output full history. + # (We assume the start_tag is after the monorepo merge if it's specified.) + if start_tag and start_tag != 'start': + output_commits(module, start_tag, 'HEAD', f'subprojects/{module}/') + else: + # First output all post-monorepo commits or commits from start_tag if specified + output_commits(module, 'monorepo-start', + 'HEAD', f'subprojects/{module}/') + + populate_release_tags_for_premonorepo_module(module_tag_prefix) + + # Next output all pre-monorepo commits (modules have their own root) + if not start_tag: + module_start = f'{module_tag_prefix}1.0.0' + elif start_tag == 'start': + module_start = changelog_starts[module] + else: + module_start = f'{module_tag_prefix}{start_tag}' + + output_commits(module, module_start, + f'{module_tag_prefix}1.19.2', None) + + # Write start tag at end for clarity + if not start_tag: + print(f'=== release 1.0.0 ===\n') + elif start_tag != 'start': + print(f'=== release {start_tag} ===\n') diff --git a/subprojects/gst-plugins-good/meson.build b/subprojects/gst-plugins-good/meson.build index 942b38eb88..6a7cc77d4a 100644 --- a/subprojects/gst-plugins-good/meson.build +++ b/subprojects/gst-plugins-good/meson.build @@ -520,6 +520,8 @@ endif configure_file(output : 'config.h', configuration : cdata) +meson.add_dist_script('scripts/gen-changelog.py', meson.project_name(), '1.20.0', meson.project_version()) + plugin_names = [] gst_plugins = [] foreach plugin: plugins diff --git a/subprojects/gst-plugins-good/scripts/gen-changelog.py b/subprojects/gst-plugins-good/scripts/gen-changelog.py new file mode 100755 index 0000000000..3924e6ea32 --- /dev/null +++ b/subprojects/gst-plugins-good/scripts/gen-changelog.py @@ -0,0 +1,240 @@ +#!/usr/bin/env python3 +# +# Makes a GNU-Style ChangeLog from a git repository +import os +import sys +import subprocess +import re + +meson_source_root = os.environ.get('MESON_SOURCE_ROOT') + +meson_dist_root = os.environ.get('MESON_DIST_ROOT') +if meson_dist_root: + output_fn = os.path.join(meson_dist_root, 'ChangeLog') +else: + output_fn = sys.stdout.fileno() + +# commit hash => release version tag string +release_refs = {} + +# These are the pre-monorepo module beginnings +changelog_starts = { + 'gstreamer': '70521179a75db0c7230cc47c6d7f9d63cf73d351', + 'gst-plugins-base': '68746a38d5e48e6f7c220663dcc2f175ff55cb3c', + 'gst-plugins-good': '81f63142d65b62b0971c19ceb79956c49ffc2f06', + 'gst-plugins-ugly': '7d7c3e478e32b7b66c44cc4442d571fbab534740', + 'gst-plugins-bad': 'ea6821e2934fe8d356ea89d5610f0630b3446877', + 'gst-libav': '3c440154c60d1ec0a54186f0fad4aebfd2ecc3ea', + 'gst-rtsp-server': '5029c85a46a8c366c4bf272d503e22bbcd624ece', + 'gst-editing-services': 'ee8bf88ebf131cf7c7161356540efc20bf411e14', + 'gst-python': 'b3e564eff577e2f577d795051bbcca85d47c89dc', + 'gstreamer-vaapi': 'c89e9afc5d43837c498a55f8f13ddf235442b83b', + 'gst-omx': 'd2463b017f222e678978582544a9c9a80edfd330', + 'gst-devtools': 'da962d096af9460502843e41b7d25fdece7ff1c2', + 'gstreamer-sharp': 'b94528f8e7979df49fedf137dfa228d8fe475e1b', +} + + +def print_help(): + print('', file=sys.stderr) + print('gen-changelog: generate GNU-style changelog from git history', + file=sys.stderr) + print('', file=sys.stderr) + print('Usage: {} [OPTIONS] GSTREAMER-MODULE [START-TAG] [HEAD-TAG]'.format( + sys.argv[0]), file=sys.stderr) + print('', file=sys.stderr) + sys.exit(1) + + +if len(sys.argv) < 2 or len(sys.argv) > 4 or '--help' in sys.argv: + print_help() + +module = sys.argv[1] + +if len(sys.argv) > 2: + start_tag = sys.argv[2] +else: + start_tag = None + +if len(sys.argv) > 3: + head_tag = sys.argv[3] +else: + head_tag = None + +if module not in changelog_starts: + print(f'Unknown module {module}', file=sys.stderr) + print_help() + + +def process_commit(lines, files, subtree_path=None): + # DATE NAME + # BLANK LINE + # Subject + # BLANK LINE + # ... + # FILES + fileincommit = False + lines = [x.strip() for x in lines if x.strip() + and not x.startswith('git-svn-id')] + files = [x.strip() for x in files if x.strip()] + for line in lines: + if line.startswith('* ') and ':' in line: + fileincommit = True + break + + top_line = lines[0] + print(top_line.strip()) + print() + if not fileincommit: + for f in files: + if subtree_path and f.startswith(subtree_path): + # requires Python 3.9 + print('\t* %s:' % f.removeprefix(subtree_path)) + else: + print('\t* %s:' % f) + for line in lines[1:]: + print('\t ', line) + print() + + +def output_commits(module, start_tag, end_tag, subtree_path=None): + # retrieve commit date for start tag so we can filter the log for commits + # after that date. That way we don't include commits from merged-in + # plugin-move branches that go back to the beginning of time. + start_date = get_commit_date_for_ref(start_tag) + + cmd = ['git', 'log', + '--pretty=format:--START-COMMIT--%H%n%ai %an <%ae>%n%n%s%n%b%n--END-COMMIT--', + '--date=short', + '--name-only', + f'--since={start_date}', + f'{start_tag}..{end_tag}', + ] + + if subtree_path: + cmd += ['--', '.'] + + p = subprocess.Popen(args=cmd, shell=False, + stdout=subprocess.PIPE, cwd=meson_source_root) + buf = [] + files = [] + filemode = False + for lin in [x.decode('utf8', errors='replace') for x in p.stdout.readlines()]: + if lin.startswith("--START-COMMIT--"): + commit_hash = lin[16:].strip() + if buf != []: + process_commit(buf, files, subtree_path) + + if commit_hash in release_refs: + version_str = release_refs[commit_hash] + print(f'=== release {version_str} ===\n') + + buf = [] + files = [] + filemode = False + elif lin.startswith("--END-COMMIT--"): + filemode = True + elif filemode is True: + files.append(lin) + else: + buf.append(lin) + if buf != []: + process_commit(buf, files, subtree_path) + + +def get_commit_date_for_ref(ref): + cmd = ['git', 'log', '--pretty=format:%cI', '-1', ref] + r = subprocess.run(cmd, capture_output=True, text=True, + check=True, cwd=meson_source_root) + commit_date = r.stdout.strip() + return commit_date + + +def populate_release_tags_for_premonorepo_module(module_tag_prefix): + if module_tag_prefix != '': + cmd = ['git', 'tag', '--list', f'{module_tag_prefix}*'] + else: + cmd = ['git', 'tag', '--list', '1.*', 'RELEASE-*'] + + p = subprocess.Popen(args=cmd, shell=False, + stdout=subprocess.PIPE, cwd=meson_source_root) + for line in [x.decode('utf8') for x in p.stdout.readlines()]: + git_tag = line.strip() + version_str = git_tag.removeprefix(module_tag_prefix).removeprefix('RELEASE-').split('-')[0].replace('_', '.') + # might have been populated with post-monorepo tags already for gstreamer core + if version_str not in release_refs: + # find last commit before tag in module subdirectory + cmd = ['git', 'log', '--pretty=format:%H', '-1', git_tag] + r = subprocess.run(cmd, capture_output=True, + text=True, check=True, cwd=meson_source_root) + commit_hash = r.stdout.strip() + release_refs[commit_hash] = version_str + + # print(f'{git_tag} => {version_str} => {commit_hash}') + + +def populate_release_tags_for_monorepo_subproject(): + cmd = ['git', 'tag', '--list', '1.*'] + p = subprocess.Popen(args=cmd, shell=False, + stdout=subprocess.PIPE, cwd=meson_source_root) + for line in [x.decode('utf8') for x in p.stdout.readlines()]: + version_str = line.strip() + version_arr = version_str.split('.') + major = int(version_arr[0]) + minor = int(version_arr[1]) + micro = int(version_arr[2]) + # ignore pre-monorepo versions + if major < 1: + continue + if major == 1 and minor < 19: + continue + if major == 1 and minor == 19 and micro < 2: + continue + # find last commit before tag in module subdirectory + cmd = ['git', 'log', '--pretty=format:%H', + '-1', version_str, '--', '.'] + r = subprocess.run(cmd, capture_output=True, text=True, + check=True, cwd=meson_source_root) + commit_hash = r.stdout.strip() + release_refs[commit_hash] = version_str + + +if __name__ == '__main__': + module_tag_prefix = '' if module == 'gstreamer' else f'{module}-' + + populate_release_tags_for_monorepo_subproject() + + with open(output_fn, 'w') as f: + sys.stdout = f + + # Force writing of head tag + if head_tag and head_tag not in release_refs.values(): + print(f'=== release {head_tag} ===\n') + + # Output all commits from start_tag onwards, otherwise output full history. + # (We assume the start_tag is after the monorepo merge if it's specified.) + if start_tag and start_tag != 'start': + output_commits(module, start_tag, 'HEAD', f'subprojects/{module}/') + else: + # First output all post-monorepo commits or commits from start_tag if specified + output_commits(module, 'monorepo-start', + 'HEAD', f'subprojects/{module}/') + + populate_release_tags_for_premonorepo_module(module_tag_prefix) + + # Next output all pre-monorepo commits (modules have their own root) + if not start_tag: + module_start = f'{module_tag_prefix}1.0.0' + elif start_tag == 'start': + module_start = changelog_starts[module] + else: + module_start = f'{module_tag_prefix}{start_tag}' + + output_commits(module, module_start, + f'{module_tag_prefix}1.19.2', None) + + # Write start tag at end for clarity + if not start_tag: + print(f'=== release 1.0.0 ===\n') + elif start_tag != 'start': + print(f'=== release {start_tag} ===\n') diff --git a/subprojects/gst-plugins-ugly/meson.build b/subprojects/gst-plugins-ugly/meson.build index b97465d643..2d035b51e2 100644 --- a/subprojects/gst-plugins-ugly/meson.build +++ b/subprojects/gst-plugins-ugly/meson.build @@ -329,6 +329,8 @@ endif configure_file(output : 'config.h', configuration : cdata) +meson.add_dist_script('scripts/gen-changelog.py', meson.project_name(), '1.20.0', meson.project_version()) + plugin_names = [] gst_plugins = [] foreach plugin: plugins diff --git a/subprojects/gst-plugins-ugly/scripts/gen-changelog.py b/subprojects/gst-plugins-ugly/scripts/gen-changelog.py new file mode 100755 index 0000000000..3924e6ea32 --- /dev/null +++ b/subprojects/gst-plugins-ugly/scripts/gen-changelog.py @@ -0,0 +1,240 @@ +#!/usr/bin/env python3 +# +# Makes a GNU-Style ChangeLog from a git repository +import os +import sys +import subprocess +import re + +meson_source_root = os.environ.get('MESON_SOURCE_ROOT') + +meson_dist_root = os.environ.get('MESON_DIST_ROOT') +if meson_dist_root: + output_fn = os.path.join(meson_dist_root, 'ChangeLog') +else: + output_fn = sys.stdout.fileno() + +# commit hash => release version tag string +release_refs = {} + +# These are the pre-monorepo module beginnings +changelog_starts = { + 'gstreamer': '70521179a75db0c7230cc47c6d7f9d63cf73d351', + 'gst-plugins-base': '68746a38d5e48e6f7c220663dcc2f175ff55cb3c', + 'gst-plugins-good': '81f63142d65b62b0971c19ceb79956c49ffc2f06', + 'gst-plugins-ugly': '7d7c3e478e32b7b66c44cc4442d571fbab534740', + 'gst-plugins-bad': 'ea6821e2934fe8d356ea89d5610f0630b3446877', + 'gst-libav': '3c440154c60d1ec0a54186f0fad4aebfd2ecc3ea', + 'gst-rtsp-server': '5029c85a46a8c366c4bf272d503e22bbcd624ece', + 'gst-editing-services': 'ee8bf88ebf131cf7c7161356540efc20bf411e14', + 'gst-python': 'b3e564eff577e2f577d795051bbcca85d47c89dc', + 'gstreamer-vaapi': 'c89e9afc5d43837c498a55f8f13ddf235442b83b', + 'gst-omx': 'd2463b017f222e678978582544a9c9a80edfd330', + 'gst-devtools': 'da962d096af9460502843e41b7d25fdece7ff1c2', + 'gstreamer-sharp': 'b94528f8e7979df49fedf137dfa228d8fe475e1b', +} + + +def print_help(): + print('', file=sys.stderr) + print('gen-changelog: generate GNU-style changelog from git history', + file=sys.stderr) + print('', file=sys.stderr) + print('Usage: {} [OPTIONS] GSTREAMER-MODULE [START-TAG] [HEAD-TAG]'.format( + sys.argv[0]), file=sys.stderr) + print('', file=sys.stderr) + sys.exit(1) + + +if len(sys.argv) < 2 or len(sys.argv) > 4 or '--help' in sys.argv: + print_help() + +module = sys.argv[1] + +if len(sys.argv) > 2: + start_tag = sys.argv[2] +else: + start_tag = None + +if len(sys.argv) > 3: + head_tag = sys.argv[3] +else: + head_tag = None + +if module not in changelog_starts: + print(f'Unknown module {module}', file=sys.stderr) + print_help() + + +def process_commit(lines, files, subtree_path=None): + # DATE NAME + # BLANK LINE + # Subject + # BLANK LINE + # ... + # FILES + fileincommit = False + lines = [x.strip() for x in lines if x.strip() + and not x.startswith('git-svn-id')] + files = [x.strip() for x in files if x.strip()] + for line in lines: + if line.startswith('* ') and ':' in line: + fileincommit = True + break + + top_line = lines[0] + print(top_line.strip()) + print() + if not fileincommit: + for f in files: + if subtree_path and f.startswith(subtree_path): + # requires Python 3.9 + print('\t* %s:' % f.removeprefix(subtree_path)) + else: + print('\t* %s:' % f) + for line in lines[1:]: + print('\t ', line) + print() + + +def output_commits(module, start_tag, end_tag, subtree_path=None): + # retrieve commit date for start tag so we can filter the log for commits + # after that date. That way we don't include commits from merged-in + # plugin-move branches that go back to the beginning of time. + start_date = get_commit_date_for_ref(start_tag) + + cmd = ['git', 'log', + '--pretty=format:--START-COMMIT--%H%n%ai %an <%ae>%n%n%s%n%b%n--END-COMMIT--', + '--date=short', + '--name-only', + f'--since={start_date}', + f'{start_tag}..{end_tag}', + ] + + if subtree_path: + cmd += ['--', '.'] + + p = subprocess.Popen(args=cmd, shell=False, + stdout=subprocess.PIPE, cwd=meson_source_root) + buf = [] + files = [] + filemode = False + for lin in [x.decode('utf8', errors='replace') for x in p.stdout.readlines()]: + if lin.startswith("--START-COMMIT--"): + commit_hash = lin[16:].strip() + if buf != []: + process_commit(buf, files, subtree_path) + + if commit_hash in release_refs: + version_str = release_refs[commit_hash] + print(f'=== release {version_str} ===\n') + + buf = [] + files = [] + filemode = False + elif lin.startswith("--END-COMMIT--"): + filemode = True + elif filemode is True: + files.append(lin) + else: + buf.append(lin) + if buf != []: + process_commit(buf, files, subtree_path) + + +def get_commit_date_for_ref(ref): + cmd = ['git', 'log', '--pretty=format:%cI', '-1', ref] + r = subprocess.run(cmd, capture_output=True, text=True, + check=True, cwd=meson_source_root) + commit_date = r.stdout.strip() + return commit_date + + +def populate_release_tags_for_premonorepo_module(module_tag_prefix): + if module_tag_prefix != '': + cmd = ['git', 'tag', '--list', f'{module_tag_prefix}*'] + else: + cmd = ['git', 'tag', '--list', '1.*', 'RELEASE-*'] + + p = subprocess.Popen(args=cmd, shell=False, + stdout=subprocess.PIPE, cwd=meson_source_root) + for line in [x.decode('utf8') for x in p.stdout.readlines()]: + git_tag = line.strip() + version_str = git_tag.removeprefix(module_tag_prefix).removeprefix('RELEASE-').split('-')[0].replace('_', '.') + # might have been populated with post-monorepo tags already for gstreamer core + if version_str not in release_refs: + # find last commit before tag in module subdirectory + cmd = ['git', 'log', '--pretty=format:%H', '-1', git_tag] + r = subprocess.run(cmd, capture_output=True, + text=True, check=True, cwd=meson_source_root) + commit_hash = r.stdout.strip() + release_refs[commit_hash] = version_str + + # print(f'{git_tag} => {version_str} => {commit_hash}') + + +def populate_release_tags_for_monorepo_subproject(): + cmd = ['git', 'tag', '--list', '1.*'] + p = subprocess.Popen(args=cmd, shell=False, + stdout=subprocess.PIPE, cwd=meson_source_root) + for line in [x.decode('utf8') for x in p.stdout.readlines()]: + version_str = line.strip() + version_arr = version_str.split('.') + major = int(version_arr[0]) + minor = int(version_arr[1]) + micro = int(version_arr[2]) + # ignore pre-monorepo versions + if major < 1: + continue + if major == 1 and minor < 19: + continue + if major == 1 and minor == 19 and micro < 2: + continue + # find last commit before tag in module subdirectory + cmd = ['git', 'log', '--pretty=format:%H', + '-1', version_str, '--', '.'] + r = subprocess.run(cmd, capture_output=True, text=True, + check=True, cwd=meson_source_root) + commit_hash = r.stdout.strip() + release_refs[commit_hash] = version_str + + +if __name__ == '__main__': + module_tag_prefix = '' if module == 'gstreamer' else f'{module}-' + + populate_release_tags_for_monorepo_subproject() + + with open(output_fn, 'w') as f: + sys.stdout = f + + # Force writing of head tag + if head_tag and head_tag not in release_refs.values(): + print(f'=== release {head_tag} ===\n') + + # Output all commits from start_tag onwards, otherwise output full history. + # (We assume the start_tag is after the monorepo merge if it's specified.) + if start_tag and start_tag != 'start': + output_commits(module, start_tag, 'HEAD', f'subprojects/{module}/') + else: + # First output all post-monorepo commits or commits from start_tag if specified + output_commits(module, 'monorepo-start', + 'HEAD', f'subprojects/{module}/') + + populate_release_tags_for_premonorepo_module(module_tag_prefix) + + # Next output all pre-monorepo commits (modules have their own root) + if not start_tag: + module_start = f'{module_tag_prefix}1.0.0' + elif start_tag == 'start': + module_start = changelog_starts[module] + else: + module_start = f'{module_tag_prefix}{start_tag}' + + output_commits(module, module_start, + f'{module_tag_prefix}1.19.2', None) + + # Write start tag at end for clarity + if not start_tag: + print(f'=== release 1.0.0 ===\n') + elif start_tag != 'start': + print(f'=== release {start_tag} ===\n') diff --git a/subprojects/gst-python/meson.build b/subprojects/gst-python/meson.build index 209b2d7a94..dd5706c404 100644 --- a/subprojects/gst-python/meson.build +++ b/subprojects/gst-python/meson.build @@ -87,6 +87,8 @@ cdata.set('PYTHON_VERSION', '"@0@"'.format(python_dep.version())) configure_file(output : 'config.h', configuration : cdata) configinc = include_directories('.') +meson.add_dist_script('scripts/gen-changelog.py', meson.project_name(), '1.20.0', meson.project_version()) + pkgconfig = import('pkgconfig') plugins_install_dir = join_paths(libdir, 'gstreamer-1.0') plugins_pkgconfig_install_dir = join_paths(plugins_install_dir, 'pkgconfig') diff --git a/subprojects/gst-python/scripts/gen-changelog.py b/subprojects/gst-python/scripts/gen-changelog.py new file mode 100755 index 0000000000..3924e6ea32 --- /dev/null +++ b/subprojects/gst-python/scripts/gen-changelog.py @@ -0,0 +1,240 @@ +#!/usr/bin/env python3 +# +# Makes a GNU-Style ChangeLog from a git repository +import os +import sys +import subprocess +import re + +meson_source_root = os.environ.get('MESON_SOURCE_ROOT') + +meson_dist_root = os.environ.get('MESON_DIST_ROOT') +if meson_dist_root: + output_fn = os.path.join(meson_dist_root, 'ChangeLog') +else: + output_fn = sys.stdout.fileno() + +# commit hash => release version tag string +release_refs = {} + +# These are the pre-monorepo module beginnings +changelog_starts = { + 'gstreamer': '70521179a75db0c7230cc47c6d7f9d63cf73d351', + 'gst-plugins-base': '68746a38d5e48e6f7c220663dcc2f175ff55cb3c', + 'gst-plugins-good': '81f63142d65b62b0971c19ceb79956c49ffc2f06', + 'gst-plugins-ugly': '7d7c3e478e32b7b66c44cc4442d571fbab534740', + 'gst-plugins-bad': 'ea6821e2934fe8d356ea89d5610f0630b3446877', + 'gst-libav': '3c440154c60d1ec0a54186f0fad4aebfd2ecc3ea', + 'gst-rtsp-server': '5029c85a46a8c366c4bf272d503e22bbcd624ece', + 'gst-editing-services': 'ee8bf88ebf131cf7c7161356540efc20bf411e14', + 'gst-python': 'b3e564eff577e2f577d795051bbcca85d47c89dc', + 'gstreamer-vaapi': 'c89e9afc5d43837c498a55f8f13ddf235442b83b', + 'gst-omx': 'd2463b017f222e678978582544a9c9a80edfd330', + 'gst-devtools': 'da962d096af9460502843e41b7d25fdece7ff1c2', + 'gstreamer-sharp': 'b94528f8e7979df49fedf137dfa228d8fe475e1b', +} + + +def print_help(): + print('', file=sys.stderr) + print('gen-changelog: generate GNU-style changelog from git history', + file=sys.stderr) + print('', file=sys.stderr) + print('Usage: {} [OPTIONS] GSTREAMER-MODULE [START-TAG] [HEAD-TAG]'.format( + sys.argv[0]), file=sys.stderr) + print('', file=sys.stderr) + sys.exit(1) + + +if len(sys.argv) < 2 or len(sys.argv) > 4 or '--help' in sys.argv: + print_help() + +module = sys.argv[1] + +if len(sys.argv) > 2: + start_tag = sys.argv[2] +else: + start_tag = None + +if len(sys.argv) > 3: + head_tag = sys.argv[3] +else: + head_tag = None + +if module not in changelog_starts: + print(f'Unknown module {module}', file=sys.stderr) + print_help() + + +def process_commit(lines, files, subtree_path=None): + # DATE NAME + # BLANK LINE + # Subject + # BLANK LINE + # ... + # FILES + fileincommit = False + lines = [x.strip() for x in lines if x.strip() + and not x.startswith('git-svn-id')] + files = [x.strip() for x in files if x.strip()] + for line in lines: + if line.startswith('* ') and ':' in line: + fileincommit = True + break + + top_line = lines[0] + print(top_line.strip()) + print() + if not fileincommit: + for f in files: + if subtree_path and f.startswith(subtree_path): + # requires Python 3.9 + print('\t* %s:' % f.removeprefix(subtree_path)) + else: + print('\t* %s:' % f) + for line in lines[1:]: + print('\t ', line) + print() + + +def output_commits(module, start_tag, end_tag, subtree_path=None): + # retrieve commit date for start tag so we can filter the log for commits + # after that date. That way we don't include commits from merged-in + # plugin-move branches that go back to the beginning of time. + start_date = get_commit_date_for_ref(start_tag) + + cmd = ['git', 'log', + '--pretty=format:--START-COMMIT--%H%n%ai %an <%ae>%n%n%s%n%b%n--END-COMMIT--', + '--date=short', + '--name-only', + f'--since={start_date}', + f'{start_tag}..{end_tag}', + ] + + if subtree_path: + cmd += ['--', '.'] + + p = subprocess.Popen(args=cmd, shell=False, + stdout=subprocess.PIPE, cwd=meson_source_root) + buf = [] + files = [] + filemode = False + for lin in [x.decode('utf8', errors='replace') for x in p.stdout.readlines()]: + if lin.startswith("--START-COMMIT--"): + commit_hash = lin[16:].strip() + if buf != []: + process_commit(buf, files, subtree_path) + + if commit_hash in release_refs: + version_str = release_refs[commit_hash] + print(f'=== release {version_str} ===\n') + + buf = [] + files = [] + filemode = False + elif lin.startswith("--END-COMMIT--"): + filemode = True + elif filemode is True: + files.append(lin) + else: + buf.append(lin) + if buf != []: + process_commit(buf, files, subtree_path) + + +def get_commit_date_for_ref(ref): + cmd = ['git', 'log', '--pretty=format:%cI', '-1', ref] + r = subprocess.run(cmd, capture_output=True, text=True, + check=True, cwd=meson_source_root) + commit_date = r.stdout.strip() + return commit_date + + +def populate_release_tags_for_premonorepo_module(module_tag_prefix): + if module_tag_prefix != '': + cmd = ['git', 'tag', '--list', f'{module_tag_prefix}*'] + else: + cmd = ['git', 'tag', '--list', '1.*', 'RELEASE-*'] + + p = subprocess.Popen(args=cmd, shell=False, + stdout=subprocess.PIPE, cwd=meson_source_root) + for line in [x.decode('utf8') for x in p.stdout.readlines()]: + git_tag = line.strip() + version_str = git_tag.removeprefix(module_tag_prefix).removeprefix('RELEASE-').split('-')[0].replace('_', '.') + # might have been populated with post-monorepo tags already for gstreamer core + if version_str not in release_refs: + # find last commit before tag in module subdirectory + cmd = ['git', 'log', '--pretty=format:%H', '-1', git_tag] + r = subprocess.run(cmd, capture_output=True, + text=True, check=True, cwd=meson_source_root) + commit_hash = r.stdout.strip() + release_refs[commit_hash] = version_str + + # print(f'{git_tag} => {version_str} => {commit_hash}') + + +def populate_release_tags_for_monorepo_subproject(): + cmd = ['git', 'tag', '--list', '1.*'] + p = subprocess.Popen(args=cmd, shell=False, + stdout=subprocess.PIPE, cwd=meson_source_root) + for line in [x.decode('utf8') for x in p.stdout.readlines()]: + version_str = line.strip() + version_arr = version_str.split('.') + major = int(version_arr[0]) + minor = int(version_arr[1]) + micro = int(version_arr[2]) + # ignore pre-monorepo versions + if major < 1: + continue + if major == 1 and minor < 19: + continue + if major == 1 and minor == 19 and micro < 2: + continue + # find last commit before tag in module subdirectory + cmd = ['git', 'log', '--pretty=format:%H', + '-1', version_str, '--', '.'] + r = subprocess.run(cmd, capture_output=True, text=True, + check=True, cwd=meson_source_root) + commit_hash = r.stdout.strip() + release_refs[commit_hash] = version_str + + +if __name__ == '__main__': + module_tag_prefix = '' if module == 'gstreamer' else f'{module}-' + + populate_release_tags_for_monorepo_subproject() + + with open(output_fn, 'w') as f: + sys.stdout = f + + # Force writing of head tag + if head_tag and head_tag not in release_refs.values(): + print(f'=== release {head_tag} ===\n') + + # Output all commits from start_tag onwards, otherwise output full history. + # (We assume the start_tag is after the monorepo merge if it's specified.) + if start_tag and start_tag != 'start': + output_commits(module, start_tag, 'HEAD', f'subprojects/{module}/') + else: + # First output all post-monorepo commits or commits from start_tag if specified + output_commits(module, 'monorepo-start', + 'HEAD', f'subprojects/{module}/') + + populate_release_tags_for_premonorepo_module(module_tag_prefix) + + # Next output all pre-monorepo commits (modules have their own root) + if not start_tag: + module_start = f'{module_tag_prefix}1.0.0' + elif start_tag == 'start': + module_start = changelog_starts[module] + else: + module_start = f'{module_tag_prefix}{start_tag}' + + output_commits(module, module_start, + f'{module_tag_prefix}1.19.2', None) + + # Write start tag at end for clarity + if not start_tag: + print(f'=== release 1.0.0 ===\n') + elif start_tag != 'start': + print(f'=== release {start_tag} ===\n') diff --git a/subprojects/gst-rtsp-server/meson.build b/subprojects/gst-rtsp-server/meson.build index 5bc75d66dc..b9037a654d 100644 --- a/subprojects/gst-rtsp-server/meson.build +++ b/subprojects/gst-rtsp-server/meson.build @@ -219,6 +219,8 @@ endif configure_file(output: 'config.h', configuration: cdata) +meson.add_dist_script('scripts/gen-changelog.py', meson.project_name(), '1.20.0', meson.project_version()) + plugin_names = [] gst_plugins = [] foreach plugin: plugins diff --git a/subprojects/gst-rtsp-server/scripts/gen-changelog.py b/subprojects/gst-rtsp-server/scripts/gen-changelog.py new file mode 100755 index 0000000000..3924e6ea32 --- /dev/null +++ b/subprojects/gst-rtsp-server/scripts/gen-changelog.py @@ -0,0 +1,240 @@ +#!/usr/bin/env python3 +# +# Makes a GNU-Style ChangeLog from a git repository +import os +import sys +import subprocess +import re + +meson_source_root = os.environ.get('MESON_SOURCE_ROOT') + +meson_dist_root = os.environ.get('MESON_DIST_ROOT') +if meson_dist_root: + output_fn = os.path.join(meson_dist_root, 'ChangeLog') +else: + output_fn = sys.stdout.fileno() + +# commit hash => release version tag string +release_refs = {} + +# These are the pre-monorepo module beginnings +changelog_starts = { + 'gstreamer': '70521179a75db0c7230cc47c6d7f9d63cf73d351', + 'gst-plugins-base': '68746a38d5e48e6f7c220663dcc2f175ff55cb3c', + 'gst-plugins-good': '81f63142d65b62b0971c19ceb79956c49ffc2f06', + 'gst-plugins-ugly': '7d7c3e478e32b7b66c44cc4442d571fbab534740', + 'gst-plugins-bad': 'ea6821e2934fe8d356ea89d5610f0630b3446877', + 'gst-libav': '3c440154c60d1ec0a54186f0fad4aebfd2ecc3ea', + 'gst-rtsp-server': '5029c85a46a8c366c4bf272d503e22bbcd624ece', + 'gst-editing-services': 'ee8bf88ebf131cf7c7161356540efc20bf411e14', + 'gst-python': 'b3e564eff577e2f577d795051bbcca85d47c89dc', + 'gstreamer-vaapi': 'c89e9afc5d43837c498a55f8f13ddf235442b83b', + 'gst-omx': 'd2463b017f222e678978582544a9c9a80edfd330', + 'gst-devtools': 'da962d096af9460502843e41b7d25fdece7ff1c2', + 'gstreamer-sharp': 'b94528f8e7979df49fedf137dfa228d8fe475e1b', +} + + +def print_help(): + print('', file=sys.stderr) + print('gen-changelog: generate GNU-style changelog from git history', + file=sys.stderr) + print('', file=sys.stderr) + print('Usage: {} [OPTIONS] GSTREAMER-MODULE [START-TAG] [HEAD-TAG]'.format( + sys.argv[0]), file=sys.stderr) + print('', file=sys.stderr) + sys.exit(1) + + +if len(sys.argv) < 2 or len(sys.argv) > 4 or '--help' in sys.argv: + print_help() + +module = sys.argv[1] + +if len(sys.argv) > 2: + start_tag = sys.argv[2] +else: + start_tag = None + +if len(sys.argv) > 3: + head_tag = sys.argv[3] +else: + head_tag = None + +if module not in changelog_starts: + print(f'Unknown module {module}', file=sys.stderr) + print_help() + + +def process_commit(lines, files, subtree_path=None): + # DATE NAME + # BLANK LINE + # Subject + # BLANK LINE + # ... + # FILES + fileincommit = False + lines = [x.strip() for x in lines if x.strip() + and not x.startswith('git-svn-id')] + files = [x.strip() for x in files if x.strip()] + for line in lines: + if line.startswith('* ') and ':' in line: + fileincommit = True + break + + top_line = lines[0] + print(top_line.strip()) + print() + if not fileincommit: + for f in files: + if subtree_path and f.startswith(subtree_path): + # requires Python 3.9 + print('\t* %s:' % f.removeprefix(subtree_path)) + else: + print('\t* %s:' % f) + for line in lines[1:]: + print('\t ', line) + print() + + +def output_commits(module, start_tag, end_tag, subtree_path=None): + # retrieve commit date for start tag so we can filter the log for commits + # after that date. That way we don't include commits from merged-in + # plugin-move branches that go back to the beginning of time. + start_date = get_commit_date_for_ref(start_tag) + + cmd = ['git', 'log', + '--pretty=format:--START-COMMIT--%H%n%ai %an <%ae>%n%n%s%n%b%n--END-COMMIT--', + '--date=short', + '--name-only', + f'--since={start_date}', + f'{start_tag}..{end_tag}', + ] + + if subtree_path: + cmd += ['--', '.'] + + p = subprocess.Popen(args=cmd, shell=False, + stdout=subprocess.PIPE, cwd=meson_source_root) + buf = [] + files = [] + filemode = False + for lin in [x.decode('utf8', errors='replace') for x in p.stdout.readlines()]: + if lin.startswith("--START-COMMIT--"): + commit_hash = lin[16:].strip() + if buf != []: + process_commit(buf, files, subtree_path) + + if commit_hash in release_refs: + version_str = release_refs[commit_hash] + print(f'=== release {version_str} ===\n') + + buf = [] + files = [] + filemode = False + elif lin.startswith("--END-COMMIT--"): + filemode = True + elif filemode is True: + files.append(lin) + else: + buf.append(lin) + if buf != []: + process_commit(buf, files, subtree_path) + + +def get_commit_date_for_ref(ref): + cmd = ['git', 'log', '--pretty=format:%cI', '-1', ref] + r = subprocess.run(cmd, capture_output=True, text=True, + check=True, cwd=meson_source_root) + commit_date = r.stdout.strip() + return commit_date + + +def populate_release_tags_for_premonorepo_module(module_tag_prefix): + if module_tag_prefix != '': + cmd = ['git', 'tag', '--list', f'{module_tag_prefix}*'] + else: + cmd = ['git', 'tag', '--list', '1.*', 'RELEASE-*'] + + p = subprocess.Popen(args=cmd, shell=False, + stdout=subprocess.PIPE, cwd=meson_source_root) + for line in [x.decode('utf8') for x in p.stdout.readlines()]: + git_tag = line.strip() + version_str = git_tag.removeprefix(module_tag_prefix).removeprefix('RELEASE-').split('-')[0].replace('_', '.') + # might have been populated with post-monorepo tags already for gstreamer core + if version_str not in release_refs: + # find last commit before tag in module subdirectory + cmd = ['git', 'log', '--pretty=format:%H', '-1', git_tag] + r = subprocess.run(cmd, capture_output=True, + text=True, check=True, cwd=meson_source_root) + commit_hash = r.stdout.strip() + release_refs[commit_hash] = version_str + + # print(f'{git_tag} => {version_str} => {commit_hash}') + + +def populate_release_tags_for_monorepo_subproject(): + cmd = ['git', 'tag', '--list', '1.*'] + p = subprocess.Popen(args=cmd, shell=False, + stdout=subprocess.PIPE, cwd=meson_source_root) + for line in [x.decode('utf8') for x in p.stdout.readlines()]: + version_str = line.strip() + version_arr = version_str.split('.') + major = int(version_arr[0]) + minor = int(version_arr[1]) + micro = int(version_arr[2]) + # ignore pre-monorepo versions + if major < 1: + continue + if major == 1 and minor < 19: + continue + if major == 1 and minor == 19 and micro < 2: + continue + # find last commit before tag in module subdirectory + cmd = ['git', 'log', '--pretty=format:%H', + '-1', version_str, '--', '.'] + r = subprocess.run(cmd, capture_output=True, text=True, + check=True, cwd=meson_source_root) + commit_hash = r.stdout.strip() + release_refs[commit_hash] = version_str + + +if __name__ == '__main__': + module_tag_prefix = '' if module == 'gstreamer' else f'{module}-' + + populate_release_tags_for_monorepo_subproject() + + with open(output_fn, 'w') as f: + sys.stdout = f + + # Force writing of head tag + if head_tag and head_tag not in release_refs.values(): + print(f'=== release {head_tag} ===\n') + + # Output all commits from start_tag onwards, otherwise output full history. + # (We assume the start_tag is after the monorepo merge if it's specified.) + if start_tag and start_tag != 'start': + output_commits(module, start_tag, 'HEAD', f'subprojects/{module}/') + else: + # First output all post-monorepo commits or commits from start_tag if specified + output_commits(module, 'monorepo-start', + 'HEAD', f'subprojects/{module}/') + + populate_release_tags_for_premonorepo_module(module_tag_prefix) + + # Next output all pre-monorepo commits (modules have their own root) + if not start_tag: + module_start = f'{module_tag_prefix}1.0.0' + elif start_tag == 'start': + module_start = changelog_starts[module] + else: + module_start = f'{module_tag_prefix}{start_tag}' + + output_commits(module, module_start, + f'{module_tag_prefix}1.19.2', None) + + # Write start tag at end for clarity + if not start_tag: + print(f'=== release 1.0.0 ===\n') + elif start_tag != 'start': + print(f'=== release {start_tag} ===\n') diff --git a/subprojects/gstreamer-sharp/meson.build b/subprojects/gstreamer-sharp/meson.build index 6c286ce353..adff8ed876 100644 --- a/subprojects/gstreamer-sharp/meson.build +++ b/subprojects/gstreamer-sharp/meson.build @@ -183,3 +183,5 @@ if bindinator.get_variable('found') else warning('Bindinator not usable as some required dependencies are not avalaible.') endif + +meson.add_dist_script('scripts/gen-changelog.py', meson.project_name(), '1.20.0', meson.project_version()) diff --git a/subprojects/gstreamer-sharp/scripts/gen-changelog.py b/subprojects/gstreamer-sharp/scripts/gen-changelog.py new file mode 100755 index 0000000000..3924e6ea32 --- /dev/null +++ b/subprojects/gstreamer-sharp/scripts/gen-changelog.py @@ -0,0 +1,240 @@ +#!/usr/bin/env python3 +# +# Makes a GNU-Style ChangeLog from a git repository +import os +import sys +import subprocess +import re + +meson_source_root = os.environ.get('MESON_SOURCE_ROOT') + +meson_dist_root = os.environ.get('MESON_DIST_ROOT') +if meson_dist_root: + output_fn = os.path.join(meson_dist_root, 'ChangeLog') +else: + output_fn = sys.stdout.fileno() + +# commit hash => release version tag string +release_refs = {} + +# These are the pre-monorepo module beginnings +changelog_starts = { + 'gstreamer': '70521179a75db0c7230cc47c6d7f9d63cf73d351', + 'gst-plugins-base': '68746a38d5e48e6f7c220663dcc2f175ff55cb3c', + 'gst-plugins-good': '81f63142d65b62b0971c19ceb79956c49ffc2f06', + 'gst-plugins-ugly': '7d7c3e478e32b7b66c44cc4442d571fbab534740', + 'gst-plugins-bad': 'ea6821e2934fe8d356ea89d5610f0630b3446877', + 'gst-libav': '3c440154c60d1ec0a54186f0fad4aebfd2ecc3ea', + 'gst-rtsp-server': '5029c85a46a8c366c4bf272d503e22bbcd624ece', + 'gst-editing-services': 'ee8bf88ebf131cf7c7161356540efc20bf411e14', + 'gst-python': 'b3e564eff577e2f577d795051bbcca85d47c89dc', + 'gstreamer-vaapi': 'c89e9afc5d43837c498a55f8f13ddf235442b83b', + 'gst-omx': 'd2463b017f222e678978582544a9c9a80edfd330', + 'gst-devtools': 'da962d096af9460502843e41b7d25fdece7ff1c2', + 'gstreamer-sharp': 'b94528f8e7979df49fedf137dfa228d8fe475e1b', +} + + +def print_help(): + print('', file=sys.stderr) + print('gen-changelog: generate GNU-style changelog from git history', + file=sys.stderr) + print('', file=sys.stderr) + print('Usage: {} [OPTIONS] GSTREAMER-MODULE [START-TAG] [HEAD-TAG]'.format( + sys.argv[0]), file=sys.stderr) + print('', file=sys.stderr) + sys.exit(1) + + +if len(sys.argv) < 2 or len(sys.argv) > 4 or '--help' in sys.argv: + print_help() + +module = sys.argv[1] + +if len(sys.argv) > 2: + start_tag = sys.argv[2] +else: + start_tag = None + +if len(sys.argv) > 3: + head_tag = sys.argv[3] +else: + head_tag = None + +if module not in changelog_starts: + print(f'Unknown module {module}', file=sys.stderr) + print_help() + + +def process_commit(lines, files, subtree_path=None): + # DATE NAME + # BLANK LINE + # Subject + # BLANK LINE + # ... + # FILES + fileincommit = False + lines = [x.strip() for x in lines if x.strip() + and not x.startswith('git-svn-id')] + files = [x.strip() for x in files if x.strip()] + for line in lines: + if line.startswith('* ') and ':' in line: + fileincommit = True + break + + top_line = lines[0] + print(top_line.strip()) + print() + if not fileincommit: + for f in files: + if subtree_path and f.startswith(subtree_path): + # requires Python 3.9 + print('\t* %s:' % f.removeprefix(subtree_path)) + else: + print('\t* %s:' % f) + for line in lines[1:]: + print('\t ', line) + print() + + +def output_commits(module, start_tag, end_tag, subtree_path=None): + # retrieve commit date for start tag so we can filter the log for commits + # after that date. That way we don't include commits from merged-in + # plugin-move branches that go back to the beginning of time. + start_date = get_commit_date_for_ref(start_tag) + + cmd = ['git', 'log', + '--pretty=format:--START-COMMIT--%H%n%ai %an <%ae>%n%n%s%n%b%n--END-COMMIT--', + '--date=short', + '--name-only', + f'--since={start_date}', + f'{start_tag}..{end_tag}', + ] + + if subtree_path: + cmd += ['--', '.'] + + p = subprocess.Popen(args=cmd, shell=False, + stdout=subprocess.PIPE, cwd=meson_source_root) + buf = [] + files = [] + filemode = False + for lin in [x.decode('utf8', errors='replace') for x in p.stdout.readlines()]: + if lin.startswith("--START-COMMIT--"): + commit_hash = lin[16:].strip() + if buf != []: + process_commit(buf, files, subtree_path) + + if commit_hash in release_refs: + version_str = release_refs[commit_hash] + print(f'=== release {version_str} ===\n') + + buf = [] + files = [] + filemode = False + elif lin.startswith("--END-COMMIT--"): + filemode = True + elif filemode is True: + files.append(lin) + else: + buf.append(lin) + if buf != []: + process_commit(buf, files, subtree_path) + + +def get_commit_date_for_ref(ref): + cmd = ['git', 'log', '--pretty=format:%cI', '-1', ref] + r = subprocess.run(cmd, capture_output=True, text=True, + check=True, cwd=meson_source_root) + commit_date = r.stdout.strip() + return commit_date + + +def populate_release_tags_for_premonorepo_module(module_tag_prefix): + if module_tag_prefix != '': + cmd = ['git', 'tag', '--list', f'{module_tag_prefix}*'] + else: + cmd = ['git', 'tag', '--list', '1.*', 'RELEASE-*'] + + p = subprocess.Popen(args=cmd, shell=False, + stdout=subprocess.PIPE, cwd=meson_source_root) + for line in [x.decode('utf8') for x in p.stdout.readlines()]: + git_tag = line.strip() + version_str = git_tag.removeprefix(module_tag_prefix).removeprefix('RELEASE-').split('-')[0].replace('_', '.') + # might have been populated with post-monorepo tags already for gstreamer core + if version_str not in release_refs: + # find last commit before tag in module subdirectory + cmd = ['git', 'log', '--pretty=format:%H', '-1', git_tag] + r = subprocess.run(cmd, capture_output=True, + text=True, check=True, cwd=meson_source_root) + commit_hash = r.stdout.strip() + release_refs[commit_hash] = version_str + + # print(f'{git_tag} => {version_str} => {commit_hash}') + + +def populate_release_tags_for_monorepo_subproject(): + cmd = ['git', 'tag', '--list', '1.*'] + p = subprocess.Popen(args=cmd, shell=False, + stdout=subprocess.PIPE, cwd=meson_source_root) + for line in [x.decode('utf8') for x in p.stdout.readlines()]: + version_str = line.strip() + version_arr = version_str.split('.') + major = int(version_arr[0]) + minor = int(version_arr[1]) + micro = int(version_arr[2]) + # ignore pre-monorepo versions + if major < 1: + continue + if major == 1 and minor < 19: + continue + if major == 1 and minor == 19 and micro < 2: + continue + # find last commit before tag in module subdirectory + cmd = ['git', 'log', '--pretty=format:%H', + '-1', version_str, '--', '.'] + r = subprocess.run(cmd, capture_output=True, text=True, + check=True, cwd=meson_source_root) + commit_hash = r.stdout.strip() + release_refs[commit_hash] = version_str + + +if __name__ == '__main__': + module_tag_prefix = '' if module == 'gstreamer' else f'{module}-' + + populate_release_tags_for_monorepo_subproject() + + with open(output_fn, 'w') as f: + sys.stdout = f + + # Force writing of head tag + if head_tag and head_tag not in release_refs.values(): + print(f'=== release {head_tag} ===\n') + + # Output all commits from start_tag onwards, otherwise output full history. + # (We assume the start_tag is after the monorepo merge if it's specified.) + if start_tag and start_tag != 'start': + output_commits(module, start_tag, 'HEAD', f'subprojects/{module}/') + else: + # First output all post-monorepo commits or commits from start_tag if specified + output_commits(module, 'monorepo-start', + 'HEAD', f'subprojects/{module}/') + + populate_release_tags_for_premonorepo_module(module_tag_prefix) + + # Next output all pre-monorepo commits (modules have their own root) + if not start_tag: + module_start = f'{module_tag_prefix}1.0.0' + elif start_tag == 'start': + module_start = changelog_starts[module] + else: + module_start = f'{module_tag_prefix}{start_tag}' + + output_commits(module, module_start, + f'{module_tag_prefix}1.19.2', None) + + # Write start tag at end for clarity + if not start_tag: + print(f'=== release 1.0.0 ===\n') + elif start_tag != 'start': + print(f'=== release {start_tag} ===\n') diff --git a/subprojects/gstreamer-vaapi/meson.build b/subprojects/gstreamer-vaapi/meson.build index 21cb8bc096..e7349c37f7 100644 --- a/subprojects/gstreamer-vaapi/meson.build +++ b/subprojects/gstreamer-vaapi/meson.build @@ -237,6 +237,8 @@ endif configure_file(output: 'config.h', configuration: cdata) +meson.add_dist_script('scripts/gen-changelog.py', meson.project_name(), '1.20.0', meson.project_version()) + pkgconfig = import('pkgconfig') plugins_pkgconfig_install_dir = join_paths(plugins_install_dir, 'pkgconfig') diff --git a/subprojects/gstreamer-vaapi/scripts/gen-changelog.py b/subprojects/gstreamer-vaapi/scripts/gen-changelog.py new file mode 100755 index 0000000000..3924e6ea32 --- /dev/null +++ b/subprojects/gstreamer-vaapi/scripts/gen-changelog.py @@ -0,0 +1,240 @@ +#!/usr/bin/env python3 +# +# Makes a GNU-Style ChangeLog from a git repository +import os +import sys +import subprocess +import re + +meson_source_root = os.environ.get('MESON_SOURCE_ROOT') + +meson_dist_root = os.environ.get('MESON_DIST_ROOT') +if meson_dist_root: + output_fn = os.path.join(meson_dist_root, 'ChangeLog') +else: + output_fn = sys.stdout.fileno() + +# commit hash => release version tag string +release_refs = {} + +# These are the pre-monorepo module beginnings +changelog_starts = { + 'gstreamer': '70521179a75db0c7230cc47c6d7f9d63cf73d351', + 'gst-plugins-base': '68746a38d5e48e6f7c220663dcc2f175ff55cb3c', + 'gst-plugins-good': '81f63142d65b62b0971c19ceb79956c49ffc2f06', + 'gst-plugins-ugly': '7d7c3e478e32b7b66c44cc4442d571fbab534740', + 'gst-plugins-bad': 'ea6821e2934fe8d356ea89d5610f0630b3446877', + 'gst-libav': '3c440154c60d1ec0a54186f0fad4aebfd2ecc3ea', + 'gst-rtsp-server': '5029c85a46a8c366c4bf272d503e22bbcd624ece', + 'gst-editing-services': 'ee8bf88ebf131cf7c7161356540efc20bf411e14', + 'gst-python': 'b3e564eff577e2f577d795051bbcca85d47c89dc', + 'gstreamer-vaapi': 'c89e9afc5d43837c498a55f8f13ddf235442b83b', + 'gst-omx': 'd2463b017f222e678978582544a9c9a80edfd330', + 'gst-devtools': 'da962d096af9460502843e41b7d25fdece7ff1c2', + 'gstreamer-sharp': 'b94528f8e7979df49fedf137dfa228d8fe475e1b', +} + + +def print_help(): + print('', file=sys.stderr) + print('gen-changelog: generate GNU-style changelog from git history', + file=sys.stderr) + print('', file=sys.stderr) + print('Usage: {} [OPTIONS] GSTREAMER-MODULE [START-TAG] [HEAD-TAG]'.format( + sys.argv[0]), file=sys.stderr) + print('', file=sys.stderr) + sys.exit(1) + + +if len(sys.argv) < 2 or len(sys.argv) > 4 or '--help' in sys.argv: + print_help() + +module = sys.argv[1] + +if len(sys.argv) > 2: + start_tag = sys.argv[2] +else: + start_tag = None + +if len(sys.argv) > 3: + head_tag = sys.argv[3] +else: + head_tag = None + +if module not in changelog_starts: + print(f'Unknown module {module}', file=sys.stderr) + print_help() + + +def process_commit(lines, files, subtree_path=None): + # DATE NAME + # BLANK LINE + # Subject + # BLANK LINE + # ... + # FILES + fileincommit = False + lines = [x.strip() for x in lines if x.strip() + and not x.startswith('git-svn-id')] + files = [x.strip() for x in files if x.strip()] + for line in lines: + if line.startswith('* ') and ':' in line: + fileincommit = True + break + + top_line = lines[0] + print(top_line.strip()) + print() + if not fileincommit: + for f in files: + if subtree_path and f.startswith(subtree_path): + # requires Python 3.9 + print('\t* %s:' % f.removeprefix(subtree_path)) + else: + print('\t* %s:' % f) + for line in lines[1:]: + print('\t ', line) + print() + + +def output_commits(module, start_tag, end_tag, subtree_path=None): + # retrieve commit date for start tag so we can filter the log for commits + # after that date. That way we don't include commits from merged-in + # plugin-move branches that go back to the beginning of time. + start_date = get_commit_date_for_ref(start_tag) + + cmd = ['git', 'log', + '--pretty=format:--START-COMMIT--%H%n%ai %an <%ae>%n%n%s%n%b%n--END-COMMIT--', + '--date=short', + '--name-only', + f'--since={start_date}', + f'{start_tag}..{end_tag}', + ] + + if subtree_path: + cmd += ['--', '.'] + + p = subprocess.Popen(args=cmd, shell=False, + stdout=subprocess.PIPE, cwd=meson_source_root) + buf = [] + files = [] + filemode = False + for lin in [x.decode('utf8', errors='replace') for x in p.stdout.readlines()]: + if lin.startswith("--START-COMMIT--"): + commit_hash = lin[16:].strip() + if buf != []: + process_commit(buf, files, subtree_path) + + if commit_hash in release_refs: + version_str = release_refs[commit_hash] + print(f'=== release {version_str} ===\n') + + buf = [] + files = [] + filemode = False + elif lin.startswith("--END-COMMIT--"): + filemode = True + elif filemode is True: + files.append(lin) + else: + buf.append(lin) + if buf != []: + process_commit(buf, files, subtree_path) + + +def get_commit_date_for_ref(ref): + cmd = ['git', 'log', '--pretty=format:%cI', '-1', ref] + r = subprocess.run(cmd, capture_output=True, text=True, + check=True, cwd=meson_source_root) + commit_date = r.stdout.strip() + return commit_date + + +def populate_release_tags_for_premonorepo_module(module_tag_prefix): + if module_tag_prefix != '': + cmd = ['git', 'tag', '--list', f'{module_tag_prefix}*'] + else: + cmd = ['git', 'tag', '--list', '1.*', 'RELEASE-*'] + + p = subprocess.Popen(args=cmd, shell=False, + stdout=subprocess.PIPE, cwd=meson_source_root) + for line in [x.decode('utf8') for x in p.stdout.readlines()]: + git_tag = line.strip() + version_str = git_tag.removeprefix(module_tag_prefix).removeprefix('RELEASE-').split('-')[0].replace('_', '.') + # might have been populated with post-monorepo tags already for gstreamer core + if version_str not in release_refs: + # find last commit before tag in module subdirectory + cmd = ['git', 'log', '--pretty=format:%H', '-1', git_tag] + r = subprocess.run(cmd, capture_output=True, + text=True, check=True, cwd=meson_source_root) + commit_hash = r.stdout.strip() + release_refs[commit_hash] = version_str + + # print(f'{git_tag} => {version_str} => {commit_hash}') + + +def populate_release_tags_for_monorepo_subproject(): + cmd = ['git', 'tag', '--list', '1.*'] + p = subprocess.Popen(args=cmd, shell=False, + stdout=subprocess.PIPE, cwd=meson_source_root) + for line in [x.decode('utf8') for x in p.stdout.readlines()]: + version_str = line.strip() + version_arr = version_str.split('.') + major = int(version_arr[0]) + minor = int(version_arr[1]) + micro = int(version_arr[2]) + # ignore pre-monorepo versions + if major < 1: + continue + if major == 1 and minor < 19: + continue + if major == 1 and minor == 19 and micro < 2: + continue + # find last commit before tag in module subdirectory + cmd = ['git', 'log', '--pretty=format:%H', + '-1', version_str, '--', '.'] + r = subprocess.run(cmd, capture_output=True, text=True, + check=True, cwd=meson_source_root) + commit_hash = r.stdout.strip() + release_refs[commit_hash] = version_str + + +if __name__ == '__main__': + module_tag_prefix = '' if module == 'gstreamer' else f'{module}-' + + populate_release_tags_for_monorepo_subproject() + + with open(output_fn, 'w') as f: + sys.stdout = f + + # Force writing of head tag + if head_tag and head_tag not in release_refs.values(): + print(f'=== release {head_tag} ===\n') + + # Output all commits from start_tag onwards, otherwise output full history. + # (We assume the start_tag is after the monorepo merge if it's specified.) + if start_tag and start_tag != 'start': + output_commits(module, start_tag, 'HEAD', f'subprojects/{module}/') + else: + # First output all post-monorepo commits or commits from start_tag if specified + output_commits(module, 'monorepo-start', + 'HEAD', f'subprojects/{module}/') + + populate_release_tags_for_premonorepo_module(module_tag_prefix) + + # Next output all pre-monorepo commits (modules have their own root) + if not start_tag: + module_start = f'{module_tag_prefix}1.0.0' + elif start_tag == 'start': + module_start = changelog_starts[module] + else: + module_start = f'{module_tag_prefix}{start_tag}' + + output_commits(module, module_start, + f'{module_tag_prefix}1.19.2', None) + + # Write start tag at end for clarity + if not start_tag: + print(f'=== release 1.0.0 ===\n') + elif start_tag != 'start': + print(f'=== release {start_tag} ===\n') diff --git a/subprojects/gstreamer/meson.build b/subprojects/gstreamer/meson.build index 33ab344401..5c17c31826 100644 --- a/subprojects/gstreamer/meson.build +++ b/subprojects/gstreamer/meson.build @@ -657,6 +657,8 @@ endif configure_file(output : 'config.h', configuration : cdata) install_data('gst-element-check-1.0.m4', install_dir : join_paths(get_option('datadir'), 'aclocal')) +meson.add_dist_script('scripts/gen-changelog.py', meson.project_name(), '1.20.0', meson.project_version()) + plugin_names = [] gst_plugins = [] foreach plugin: plugins diff --git a/subprojects/gstreamer/scripts/gen-changelog.py b/subprojects/gstreamer/scripts/gen-changelog.py new file mode 100755 index 0000000000..3924e6ea32 --- /dev/null +++ b/subprojects/gstreamer/scripts/gen-changelog.py @@ -0,0 +1,240 @@ +#!/usr/bin/env python3 +# +# Makes a GNU-Style ChangeLog from a git repository +import os +import sys +import subprocess +import re + +meson_source_root = os.environ.get('MESON_SOURCE_ROOT') + +meson_dist_root = os.environ.get('MESON_DIST_ROOT') +if meson_dist_root: + output_fn = os.path.join(meson_dist_root, 'ChangeLog') +else: + output_fn = sys.stdout.fileno() + +# commit hash => release version tag string +release_refs = {} + +# These are the pre-monorepo module beginnings +changelog_starts = { + 'gstreamer': '70521179a75db0c7230cc47c6d7f9d63cf73d351', + 'gst-plugins-base': '68746a38d5e48e6f7c220663dcc2f175ff55cb3c', + 'gst-plugins-good': '81f63142d65b62b0971c19ceb79956c49ffc2f06', + 'gst-plugins-ugly': '7d7c3e478e32b7b66c44cc4442d571fbab534740', + 'gst-plugins-bad': 'ea6821e2934fe8d356ea89d5610f0630b3446877', + 'gst-libav': '3c440154c60d1ec0a54186f0fad4aebfd2ecc3ea', + 'gst-rtsp-server': '5029c85a46a8c366c4bf272d503e22bbcd624ece', + 'gst-editing-services': 'ee8bf88ebf131cf7c7161356540efc20bf411e14', + 'gst-python': 'b3e564eff577e2f577d795051bbcca85d47c89dc', + 'gstreamer-vaapi': 'c89e9afc5d43837c498a55f8f13ddf235442b83b', + 'gst-omx': 'd2463b017f222e678978582544a9c9a80edfd330', + 'gst-devtools': 'da962d096af9460502843e41b7d25fdece7ff1c2', + 'gstreamer-sharp': 'b94528f8e7979df49fedf137dfa228d8fe475e1b', +} + + +def print_help(): + print('', file=sys.stderr) + print('gen-changelog: generate GNU-style changelog from git history', + file=sys.stderr) + print('', file=sys.stderr) + print('Usage: {} [OPTIONS] GSTREAMER-MODULE [START-TAG] [HEAD-TAG]'.format( + sys.argv[0]), file=sys.stderr) + print('', file=sys.stderr) + sys.exit(1) + + +if len(sys.argv) < 2 or len(sys.argv) > 4 or '--help' in sys.argv: + print_help() + +module = sys.argv[1] + +if len(sys.argv) > 2: + start_tag = sys.argv[2] +else: + start_tag = None + +if len(sys.argv) > 3: + head_tag = sys.argv[3] +else: + head_tag = None + +if module not in changelog_starts: + print(f'Unknown module {module}', file=sys.stderr) + print_help() + + +def process_commit(lines, files, subtree_path=None): + # DATE NAME + # BLANK LINE + # Subject + # BLANK LINE + # ... + # FILES + fileincommit = False + lines = [x.strip() for x in lines if x.strip() + and not x.startswith('git-svn-id')] + files = [x.strip() for x in files if x.strip()] + for line in lines: + if line.startswith('* ') and ':' in line: + fileincommit = True + break + + top_line = lines[0] + print(top_line.strip()) + print() + if not fileincommit: + for f in files: + if subtree_path and f.startswith(subtree_path): + # requires Python 3.9 + print('\t* %s:' % f.removeprefix(subtree_path)) + else: + print('\t* %s:' % f) + for line in lines[1:]: + print('\t ', line) + print() + + +def output_commits(module, start_tag, end_tag, subtree_path=None): + # retrieve commit date for start tag so we can filter the log for commits + # after that date. That way we don't include commits from merged-in + # plugin-move branches that go back to the beginning of time. + start_date = get_commit_date_for_ref(start_tag) + + cmd = ['git', 'log', + '--pretty=format:--START-COMMIT--%H%n%ai %an <%ae>%n%n%s%n%b%n--END-COMMIT--', + '--date=short', + '--name-only', + f'--since={start_date}', + f'{start_tag}..{end_tag}', + ] + + if subtree_path: + cmd += ['--', '.'] + + p = subprocess.Popen(args=cmd, shell=False, + stdout=subprocess.PIPE, cwd=meson_source_root) + buf = [] + files = [] + filemode = False + for lin in [x.decode('utf8', errors='replace') for x in p.stdout.readlines()]: + if lin.startswith("--START-COMMIT--"): + commit_hash = lin[16:].strip() + if buf != []: + process_commit(buf, files, subtree_path) + + if commit_hash in release_refs: + version_str = release_refs[commit_hash] + print(f'=== release {version_str} ===\n') + + buf = [] + files = [] + filemode = False + elif lin.startswith("--END-COMMIT--"): + filemode = True + elif filemode is True: + files.append(lin) + else: + buf.append(lin) + if buf != []: + process_commit(buf, files, subtree_path) + + +def get_commit_date_for_ref(ref): + cmd = ['git', 'log', '--pretty=format:%cI', '-1', ref] + r = subprocess.run(cmd, capture_output=True, text=True, + check=True, cwd=meson_source_root) + commit_date = r.stdout.strip() + return commit_date + + +def populate_release_tags_for_premonorepo_module(module_tag_prefix): + if module_tag_prefix != '': + cmd = ['git', 'tag', '--list', f'{module_tag_prefix}*'] + else: + cmd = ['git', 'tag', '--list', '1.*', 'RELEASE-*'] + + p = subprocess.Popen(args=cmd, shell=False, + stdout=subprocess.PIPE, cwd=meson_source_root) + for line in [x.decode('utf8') for x in p.stdout.readlines()]: + git_tag = line.strip() + version_str = git_tag.removeprefix(module_tag_prefix).removeprefix('RELEASE-').split('-')[0].replace('_', '.') + # might have been populated with post-monorepo tags already for gstreamer core + if version_str not in release_refs: + # find last commit before tag in module subdirectory + cmd = ['git', 'log', '--pretty=format:%H', '-1', git_tag] + r = subprocess.run(cmd, capture_output=True, + text=True, check=True, cwd=meson_source_root) + commit_hash = r.stdout.strip() + release_refs[commit_hash] = version_str + + # print(f'{git_tag} => {version_str} => {commit_hash}') + + +def populate_release_tags_for_monorepo_subproject(): + cmd = ['git', 'tag', '--list', '1.*'] + p = subprocess.Popen(args=cmd, shell=False, + stdout=subprocess.PIPE, cwd=meson_source_root) + for line in [x.decode('utf8') for x in p.stdout.readlines()]: + version_str = line.strip() + version_arr = version_str.split('.') + major = int(version_arr[0]) + minor = int(version_arr[1]) + micro = int(version_arr[2]) + # ignore pre-monorepo versions + if major < 1: + continue + if major == 1 and minor < 19: + continue + if major == 1 and minor == 19 and micro < 2: + continue + # find last commit before tag in module subdirectory + cmd = ['git', 'log', '--pretty=format:%H', + '-1', version_str, '--', '.'] + r = subprocess.run(cmd, capture_output=True, text=True, + check=True, cwd=meson_source_root) + commit_hash = r.stdout.strip() + release_refs[commit_hash] = version_str + + +if __name__ == '__main__': + module_tag_prefix = '' if module == 'gstreamer' else f'{module}-' + + populate_release_tags_for_monorepo_subproject() + + with open(output_fn, 'w') as f: + sys.stdout = f + + # Force writing of head tag + if head_tag and head_tag not in release_refs.values(): + print(f'=== release {head_tag} ===\n') + + # Output all commits from start_tag onwards, otherwise output full history. + # (We assume the start_tag is after the monorepo merge if it's specified.) + if start_tag and start_tag != 'start': + output_commits(module, start_tag, 'HEAD', f'subprojects/{module}/') + else: + # First output all post-monorepo commits or commits from start_tag if specified + output_commits(module, 'monorepo-start', + 'HEAD', f'subprojects/{module}/') + + populate_release_tags_for_premonorepo_module(module_tag_prefix) + + # Next output all pre-monorepo commits (modules have their own root) + if not start_tag: + module_start = f'{module_tag_prefix}1.0.0' + elif start_tag == 'start': + module_start = changelog_starts[module] + else: + module_start = f'{module_tag_prefix}{start_tag}' + + output_commits(module, module_start, + f'{module_tag_prefix}1.19.2', None) + + # Write start tag at end for clarity + if not start_tag: + print(f'=== release 1.0.0 ===\n') + elif start_tag != 'start': + print(f'=== release {start_tag} ===\n')