aboutsummaryrefslogtreecommitdiff
path: root/contrib/gcc-changelog/git_update_version.py
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/gcc-changelog/git_update_version.py')
-rwxr-xr-xcontrib/gcc-changelog/git_update_version.py145
1 files changed, 145 insertions, 0 deletions
diff --git a/contrib/gcc-changelog/git_update_version.py b/contrib/gcc-changelog/git_update_version.py
new file mode 100755
index 0000000..d2cadb8
--- /dev/null
+++ b/contrib/gcc-changelog/git_update_version.py
@@ -0,0 +1,145 @@
+#!/usr/bin/env python3
+#
+# This file is part of GCC.
+#
+# GCC is free software; you can redistribute it and/or modify it under
+# the terms of the GNU General Public License as published by the Free
+# Software Foundation; either version 3, or (at your option) any later
+# version.
+#
+# GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+# WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GCC; see the file COPYING3. If not see
+# <http://www.gnu.org/licenses/>. */
+
+import argparse
+import datetime
+import os
+
+from git import Repo
+
+from git_repository import parse_git_revisions
+
+current_timestamp = datetime.datetime.now().strftime('%Y%m%d\n')
+
+
+def read_timestamp(path):
+ with open(path) as f:
+ return f.read()
+
+
+def prepend_to_changelog_files(repo, folder, git_commit, add_to_git):
+ if not git_commit.success:
+ for error in git_commit.errors:
+ print(error)
+ raise AssertionError()
+ for entry, output in git_commit.to_changelog_entries(use_commit_ts=True):
+ full_path = os.path.join(folder, entry, 'ChangeLog')
+ print('writing to %s' % full_path)
+ if os.path.exists(full_path):
+ with open(full_path) as f:
+ content = f.read()
+ else:
+ content = ''
+ with open(full_path, 'w+') as f:
+ f.write(output)
+ if content:
+ f.write('\n\n')
+ f.write(content)
+ if add_to_git:
+ repo.git.add(full_path)
+
+
+active_refs = ['master', 'releases/gcc-8', 'releases/gcc-9', 'releases/gcc-10']
+
+parser = argparse.ArgumentParser(description='Update DATESTAMP and generate '
+ 'ChangeLog entries')
+parser.add_argument('-g', '--git-path', default='.',
+ help='Path to git repository')
+parser.add_argument('-p', '--push', action='store_true',
+ help='Push updated active branches')
+parser.add_argument('-d', '--dry-mode',
+ help='Generate patch for ChangeLog entries and do it'
+ ' even if DATESTAMP is unchanged; folder argument'
+ ' is expected')
+parser.add_argument('-c', '--current', action='store_true',
+ help='Modify current branch (--push argument is ignored)')
+args = parser.parse_args()
+
+repo = Repo(args.git_path)
+origin = repo.remotes['origin']
+
+
+def update_current_branch():
+ commit = repo.head.commit
+ commit_count = 1
+ while commit:
+ if (commit.author.email == 'gccadmin@gcc.gnu.org'
+ and commit.message.strip() == 'Daily bump.'):
+ break
+ # We support merge commits but only with 2 parensts
+ assert len(commit.parents) <= 2
+ commit = commit.parents[-1]
+ commit_count += 1
+
+ print('%d revisions since last Daily bump' % commit_count)
+ datestamp_path = os.path.join(args.git_path, 'gcc/DATESTAMP')
+ if (read_timestamp(datestamp_path) != current_timestamp
+ or args.dry_mode or args.current):
+ head = repo.head.commit
+ # if HEAD is a merge commit, start with second parent
+ # (branched that is being merged into the current one)
+ assert len(head.parents) <= 2
+ if len(head.parents) == 2:
+ head = head.parents[1]
+ commits = parse_git_revisions(args.git_path, '%s..%s'
+ % (commit.hexsha, head.hexsha))
+ for git_commit in reversed(commits):
+ prepend_to_changelog_files(repo, args.git_path, git_commit,
+ not args.dry_mode)
+ if args.dry_mode:
+ diff = repo.git.diff('HEAD')
+ patch = os.path.join(args.dry_mode,
+ branch.name.split('/')[-1] + '.patch')
+ with open(patch, 'w+') as f:
+ f.write(diff)
+ print('branch diff written to %s' % patch)
+ repo.git.checkout(force=True)
+ else:
+ # update timestamp
+ print('DATESTAMP will be changed:')
+ with open(datestamp_path, 'w+') as f:
+ f.write(current_timestamp)
+ repo.git.add(datestamp_path)
+ if not args.current:
+ repo.index.commit('Daily bump.')
+ if args.push:
+ repo.git.push('origin', branch)
+ print('branch is pushed')
+ else:
+ print('DATESTAMP unchanged')
+
+
+if args.current:
+ print('=== Working on the current branch ===', flush=True)
+ update_current_branch()
+else:
+ for ref in origin.refs:
+ assert ref.name.startswith('origin/')
+ name = ref.name[len('origin/'):]
+ if name in active_refs:
+ if name in repo.branches:
+ branch = repo.branches[name]
+ else:
+ branch = repo.create_head(name, ref).set_tracking_branch(ref)
+ print('=== Working on: %s ===' % branch, flush=True)
+ branch.checkout()
+ origin.pull(rebase=True)
+ print('branch pulled and checked out')
+ update_current_branch()
+ assert not repo.index.diff(None)
+ print('branch is done\n', flush=True)