3 # This file is part of GCC.
5 # GCC is free software; you can redistribute it and/or modify it under
6 # the terms of the GNU General Public License as published by the Free
7 # Software Foundation; either version 3, or (at your option) any later
10 # GCC is distributed in the hope that it will be useful, but WITHOUT ANY
11 # WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 # FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15 # You should have received a copy of the GNU General Public License
16 # along with GCC; see the file COPYING3. If not see
17 # <http://www.gnu.org/licenses/>. */
25 from git_repository
import parse_git_revisions
27 current_timestamp
= datetime
.datetime
.now().strftime('%Y%m%d\n')
29 # Skip the following commits, they cannot be correctly processed
31 'c2be82058fb40f3ae891c68d185ff53e07f14f45',
32 '04a040d907a83af54e0a98bdba5bfabc0ef4f700',
33 '2e96b5f14e4025691b57d2301d71aa6092ed44bc')
36 def read_timestamp(path
):
41 def prepend_to_changelog_files(repo
, folder
, git_commit
, add_to_git
):
42 if not git_commit
.success
:
43 for error
in git_commit
.errors
:
45 raise AssertionError()
46 for entry
, output
in git_commit
.to_changelog_entries(use_commit_ts
=True):
47 full_path
= os
.path
.join(folder
, entry
, 'ChangeLog')
48 print('writing to %s' % full_path
)
49 if os
.path
.exists(full_path
):
50 with
open(full_path
) as f
:
54 with
open(full_path
, 'w+') as f
:
60 repo
.git
.add(full_path
)
63 active_refs
= ['master', 'releases/gcc-9', 'releases/gcc-10',
66 parser
= argparse
.ArgumentParser(description
='Update DATESTAMP and generate '
68 parser
.add_argument('-g', '--git-path', default
='.',
69 help='Path to git repository')
70 parser
.add_argument('-p', '--push', action
='store_true',
71 help='Push updated active branches')
72 parser
.add_argument('-d', '--dry-mode',
73 help='Generate patch for ChangeLog entries and do it'
74 ' even if DATESTAMP is unchanged; folder argument'
76 parser
.add_argument('-c', '--current', action
='store_true',
77 help='Modify current branch (--push argument is ignored)')
78 args
= parser
.parse_args()
80 repo
= Repo(args
.git_path
)
81 origin
= repo
.remotes
['origin']
84 def update_current_branch(ref_name
):
85 commit
= repo
.head
.commit
88 if (commit
.author
.email
== 'gccadmin@gcc.gnu.org'
89 and commit
.message
.strip() == 'Daily bump.'):
91 # We support merge commits but only with 2 parensts
92 assert len(commit
.parents
) <= 2
93 commit
= commit
.parents
[-1]
96 print('%d revisions since last Daily bump' % commit_count
)
97 datestamp_path
= os
.path
.join(args
.git_path
, 'gcc/DATESTAMP')
98 if (read_timestamp(datestamp_path
) != current_timestamp
99 or args
.dry_mode
or args
.current
):
100 head
= repo
.head
.commit
101 # if HEAD is a merge commit, start with second parent
102 # (branched that is being merged into the current one)
103 assert len(head
.parents
) <= 2
104 if len(head
.parents
) == 2:
105 head
= head
.parents
[1]
106 commits
= parse_git_revisions(args
.git_path
, '%s..%s'
107 % (commit
.hexsha
, head
.hexsha
), ref_name
)
108 commits
= [c
for c
in commits
if c
.info
.hexsha
not in IGNORED_COMMITS
]
109 for git_commit
in reversed(commits
):
110 prepend_to_changelog_files(repo
, args
.git_path
, git_commit
,
113 diff
= repo
.git
.diff('HEAD')
114 patch
= os
.path
.join(args
.dry_mode
,
115 branch
.name
.split('/')[-1] + '.patch')
116 with
open(patch
, 'w+') as f
:
118 print('branch diff written to %s' % patch
)
119 repo
.git
.checkout(force
=True)
122 print('DATESTAMP will be changed:')
123 with
open(datestamp_path
, 'w+') as f
:
124 f
.write(current_timestamp
)
125 repo
.git
.add(datestamp_path
)
127 repo
.index
.commit('Daily bump.')
129 repo
.git
.push('origin', branch
)
130 print('branch is pushed')
132 print('DATESTAMP unchanged')
136 print('=== Working on the current branch ===', flush
=True)
137 update_current_branch()
139 for ref
in origin
.refs
:
140 assert ref
.name
.startswith('origin/')
141 name
= ref
.name
[len('origin/'):]
142 if name
in active_refs
:
143 if name
in repo
.branches
:
144 branch
= repo
.branches
[name
]
146 branch
= repo
.create_head(name
, ref
).set_tracking_branch(ref
)
147 print('=== Working on: %s ===' % branch
, flush
=True)
149 origin
.pull(rebase
=True)
150 print('branch pulled and checked out')
151 update_current_branch(name
)
152 assert not repo
.index
.diff(None)
153 print('branch is done\n', flush
=True)