mirror of
git://sourceware.org/git/glibc.git
synced 2024-12-15 04:20:28 +08:00
f2144b7874
Co-authored-by: Gabriel F. T. Gomes <gabriel@inconstante.net.br> Reviewed-by: Gabriel F. T. Gomes <gabriel@inconstante.net.br> Reviewed-by: Joseph Myers <joseph@codesourcery.com> The utility of a ChangeLog file has been discussed in various mailing list threads and GNU Tools Cauldrons in the past years and the general consensus is that while the file may have been very useful in the past when revision control did not exist or was not as powerful as it is today, it's current utility is fast diminishing. Further, the ChangeLog format gets in the way of modernisation of processes since it almost always results in rewriting of a commit, thus preventing use of any code review tools to automatically manage patches in the glibc project. There is consensus in the glibc community that documentation of why a change was done (i.e. a detailed description in a git commit) is more useful than what changed (i.e. a ChangeLog entry) since the latter can be deduced from the patch. The GNU community would however like to keep the option of ascertaining what changed through a ChangeLog-like output and as a compromise, it was proposed that a script be developed that generates this output. The script below is the result of these discussions. This script takes two git revisions references as input and generates the git log between those revisions in a form that resembles a ChangeLog. Its capabilities and limitations are listed in a comment in the script. On a high level it is capable of parsing C code and telling what changed at the top level, but not within constructs such as functions. Design ------ At a high level, the script analyses the raw output of a VCS, parses the source files that have changed and attempts to determine what changed. The script driver needs three distinct components to be fully functional for a repository: - A vcstocl_quirks.py file that helps it parse weird patterns in sources that may result from preprocessor defines. - A VCS plugin backend; the git backend is implemented for glibc - A programming language parser plugin. C is currently implemented. Additional programming language parsers can be added to give more detailed output for changes in those types of files. For input in languages other than those that have a parser, the script only identifies if a file has been added, removed, modified, permissions changed, etc. but cannot understand the change in content. The C Parser ------------ The C parser is capable of parsing C programs with preprocessor macros in place, as if they were part of the language. This presents some challenges with parsing code that expands macros on the fly and to help work around that, a vcstocl_quirks.py file has transformations to ease things. The C parser currently can identify macro definitions and scopes and all global and static declarations and definitions. It cannot parse (and compare) changes inside functions yet, it could be a future enhancement if the need for it arises. Testing ------- The script has been tested with the glibc repository up to glibc-2.29 and also in the past with emacs. While it would be ideal to have something like this in a repository like gnulib, that should not be a bottleneck for glibc to start using this, so this patch proposes to add these scripts into glibc. And here is (hopefully!) one of the last ChangeLog entries we'd have to write for glibc: * scripts/gitlog_to_changelog.py: New script to auto-generate ChangeLog. * scripts/vcs_to_changelog/frontend_c.py: New file. * scripts/vcs_to_changelog/misc_util.py: New file. * scripts/vcs_to_changelog/vcs_git.py: New file. * scripts/vcs_to_changelog/vcstocl_quirks.py: Likewise.
139 lines
4.7 KiB
Python
Executable File
139 lines
4.7 KiB
Python
Executable File
#!/usr/bin/python3
|
|
# Main VCSToChangeLog script.
|
|
# Copyright (C) 2019 Free Software Foundation, Inc.
|
|
#
|
|
# This program 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 of the License, or
|
|
# (at your option) any later version.
|
|
#
|
|
# This program 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 this program. If not, see <https://www.gnu.org/licenses/>.
|
|
|
|
''' Generate a ChangeLog style output based on a VCS log.
|
|
|
|
This script takes two revisions as input and generates a ChangeLog style output
|
|
for all revisions between the two revisions.
|
|
|
|
This script is intended to be executed from the project parent directory.
|
|
|
|
The vcs_to_changelog directory has a file vcstocl_quirks.py that defines a
|
|
function called get_project_quirks that returns a object of class type
|
|
ProjectQuirks or a subclass of the same. The definition of the ProjectQuirks
|
|
class is below and it specifies the properties that the project must set to
|
|
ensure correct parsing of its contents.
|
|
|
|
Among other things, ProjectQurks specifies the VCS to read from; the default is
|
|
assumed to be git. The script then studies the VCS log and for each change,
|
|
list out the nature of changes in the constituent files.
|
|
|
|
Each file type may have parser frontends that can read files and construct
|
|
objects that may be compared to determine the minimal changes that occured in
|
|
each revision. For files that do not have parsers, we may only know the nature
|
|
of changes at the top level depending on the information that the VCS stores.
|
|
|
|
The parser frontend must have a compare() method that takes the old and new
|
|
files as arrays of strings and prints the output in ChangeLog format.
|
|
|
|
Currently implemented VCS:
|
|
|
|
git
|
|
|
|
Currently implemented frontends:
|
|
|
|
C
|
|
'''
|
|
import sys
|
|
import os
|
|
import re
|
|
import argparse
|
|
from vcs_to_changelog.misc_util import *
|
|
from vcs_to_changelog import frontend_c
|
|
from vcs_to_changelog.vcs_git import *
|
|
|
|
debug = DebugUtil(False)
|
|
|
|
class ProjectQuirks:
|
|
# This is a list of regex substitutions for C/C++ macros that are known to
|
|
# break parsing of the C programs. Each member of this list is a dict with
|
|
# the key 'orig' having the regex and 'sub' having the substitution of the
|
|
# regex.
|
|
MACRO_QUIRKS = []
|
|
|
|
# This is a list of macro definitions that are extensively used and are
|
|
# known to break parsing due to some characteristic, mainly the lack of a
|
|
# semicolon at the end.
|
|
C_MACROS = []
|
|
|
|
# The repo type, defaults to git.
|
|
repo = 'git'
|
|
|
|
# List of files to ignore either because they are not needed (such as the
|
|
# ChangeLog) or because they are non-parseable. For example, glibc has a
|
|
# header file that is only assembly code, which breaks the C parser.
|
|
IGNORE_LIST = ['ChangeLog']
|
|
|
|
|
|
# Load quirks file. We assume that the script is run from the top level source
|
|
# directory.
|
|
sys.path.append('/'.join([os.getcwd(), 'scripts', 'vcs_to_changelog']))
|
|
try:
|
|
from vcstocl_quirks import *
|
|
project_quirks = get_project_quirks(debug)
|
|
except:
|
|
project_quirks = ProjectQuirks()
|
|
|
|
def analyze_diff(filename, oldfile, newfile, frontends):
|
|
''' Parse the output of the old and new files and print the difference.
|
|
|
|
For input files OLDFILE and NEWFILE with name FILENAME, generate reduced
|
|
trees for them and compare them. We limit our comparison to only C source
|
|
files.
|
|
'''
|
|
name, ext = os.path.splitext(filename)
|
|
|
|
if not ext in frontends.keys():
|
|
return None
|
|
else:
|
|
frontend = frontends[ext]
|
|
frontend.compare(oldfile, newfile)
|
|
|
|
|
|
def main(repo, frontends, refs):
|
|
''' ChangeLog Generator Entry Point.
|
|
'''
|
|
commits = repo.list_commits(args.refs)
|
|
for commit in commits:
|
|
repo.list_changes(commit, frontends)
|
|
|
|
|
|
if __name__ == '__main__':
|
|
parser = argparse.ArgumentParser()
|
|
|
|
parser.add_argument('refs', metavar='ref', type=str, nargs=2,
|
|
help='Refs to print ChangeLog entries between')
|
|
|
|
parser.add_argument('-d', '--debug', required=False, action='store_true',
|
|
help='Run the file parser debugger.')
|
|
|
|
args = parser.parse_args()
|
|
|
|
debug.debug = args.debug
|
|
|
|
if len(args.refs) < 2:
|
|
debug.eprint('Two refs needed to get a ChangeLog.')
|
|
sys.exit(os.EX_USAGE)
|
|
|
|
REPO = {'git': GitRepo(project_quirks.IGNORE_LIST, debug)}
|
|
|
|
fe_c = frontend_c.Frontend(project_quirks, debug)
|
|
FRONTENDS = {'.c': fe_c,
|
|
'.h': fe_c}
|
|
|
|
main(REPO[project_quirks.repo], FRONTENDS, args.refs)
|