3 # log-police.py: Ensure that log messages end with a single newline.
4 # See usage() function for details, or just run with no arguments.
10 my_getopt
= getopt
.gnu_getopt
11 except AttributeError:
12 my_getopt
= getopt
.getopt
20 # Pretend we have true booleans on older python versions
28 def fix_log_message(log_message
):
29 """Return a fixed version of LOG_MESSAGE. By default, this just
30 means ensuring that the result ends with exactly one newline and no
31 other whitespace. But if you want to do other kinds of fixups, this
32 function is the place to implement them -- all log message fixing in
33 this script happens here."""
34 return log_message
.rstrip() + "\n"
37 def fix_txn(fs
, txn_name
):
38 "Fix up the log message for txn TXN_NAME in FS. See fix_log_message()."
39 txn
= svn
.fs
.svn_fs_open_txn(fs
, txn_name
)
40 log_message
= svn
.fs
.svn_fs_txn_prop(txn
, "svn:log")
41 if log_message
is not None:
42 new_message
= fix_log_message(log_message
)
43 if new_message
!= log_message
:
44 svn
.fs
.svn_fs_change_txn_prop(txn
, "svn:log", new_message
)
47 def fix_rev(fs
, revnum
):
48 "Fix up the log message for revision REVNUM in FS. See fix_log_message()."
49 log_message
= svn
.fs
.svn_fs_revision_prop(fs
, revnum
, 'svn:log')
50 if log_message
is not None:
51 new_message
= fix_log_message(log_message
)
52 if new_message
!= log_message
:
53 svn
.fs
.svn_fs_change_rev_prop(fs
, revnum
, "svn:log", new_message
)
56 def usage_and_exit(error_msg
=None):
57 """Write usage information and exit. If ERROR_MSG is provide, that
58 error message is printed first (to stderr), the usage info goes to
59 stderr, and the script exits with a non-zero status. Otherwise,
60 usage info goes to stdout and the script exits with a zero status."""
62 stream
= error_msg
and sys
.stderr
or sys
.stdout
64 stream
.write("ERROR: %s\n\n" % error_msg
)
65 stream
.write("USAGE: %s [-t TXN_NAME | -r REV_NUM | --all-revs] REPOS\n"
66 % (os
.path
.basename(sys
.argv
[0])))
68 Ensure that log messages end with exactly one newline and no other
69 whitespace characters. Use as a pre-commit hook by passing '-t TXN_NAME';
70 fix up a single revision by passing '-r REV_NUM'; fix up all revisions by
71 passing '--all-revs'. (When used as a pre-commit hook, may modify the
72 svn:log property on the txn.)
74 sys
.exit(error_msg
and 1 or 0)
77 def main(ignored_pool
, argv
):
84 opts
, args
= my_getopt(argv
[1:], 't:r:h?', ["help", "all-revs"])
86 usage_and_exit("problem processing arguments / options.")
87 for opt
, value
in opts
:
88 if opt
== '--help' or opt
== '-h' or opt
== '-?':
94 elif opt
== '--all-revs':
97 usage_and_exit("unknown option '%s'." % opt
)
99 if txn_name
is not None and rev_name
is not None:
100 usage_and_exit("cannot pass both -t and -r.")
101 if txn_name
is not None and all_revs
:
102 usage_and_exit("cannot pass --all-revs with -t.")
103 if rev_name
is not None and all_revs
:
104 usage_and_exit("cannot pass --all-revs with -r.")
105 if rev_name
is None and txn_name
is None and not all_revs
:
106 usage_and_exit("must provide exactly one of -r, -t, or --all-revs.")
108 usage_and_exit("only one argument allowed (the repository).")
110 repos_path
= svn
.core
.svn_path_canonicalize(args
[0])
112 # A non-bindings version of this could be implemented by calling out
113 # to 'svnlook getlog' and 'svnadmin setlog'. However, using the
114 # bindings results in much simpler code.
116 fs
= svn
.repos
.svn_repos_fs(svn
.repos
.svn_repos_open(repos_path
))
117 if txn_name
is not None:
118 fix_txn(fs
, txn_name
)
119 elif rev_name
is not None:
120 fix_rev(fs
, int(rev_name
))
122 # Do it such that if we're running on a live repository, we'll
123 # catch up even with commits that came in after we started.
126 youngest
= svn
.fs
.svn_fs_youngest_rev(fs
)
127 if youngest
>= last_youngest
:
128 for this_rev
in range(last_youngest
, youngest
+ 1):
129 fix_rev(fs
, this_rev
)
130 last_youngest
= youngest
+ 1
135 if __name__
== '__main__':
136 sys
.exit(svn
.core
.run_app(main
, sys
.argv
))