Merge lp:~stefan.goetz-deactivatedaccount/hipl/commitguard into lp:hipl

Proposed by Stefan Götz
Status: Merged
Merged at revision: 6261
Proposed branch: lp:~stefan.goetz-deactivatedaccount/hipl/commitguard
Merge into: lp:hipl
Diff against target: 581 lines (+533/-5)
6 files modified
.commitguards/author-attribution.guard (+31/-0)
.commitguards/copyright-guard-space.guard (+27/-0)
.commitguards/copyright-guard-space.py (+63/-0)
.commitguards/copyright-year.guard (+36/-0)
doc/HACKING (+27/-5)
tools/bazaar/plugins/commitguard.py (+349/-0)
To merge this branch: bzr merge lp:~stefan.goetz-deactivatedaccount/hipl/commitguard
Reviewer Review Type Date Requested Status
Diego Biurrun Needs Fixing
René Hummen Approve
Stefan Götz Pending
Miika Komu Pending
Review via email: mp+89627@code.launchpad.net

This proposal supersedes a proposal from 2012-01-19.

Description of the change

Adds a bazaar pre-commit hook for checking file contents before a commit and to aborting the commit if necessary. Also includes a few guards that enforce some aspects of HIPL code style policy.

To post a comment you must log in.
Revision history for this message
Diego Biurrun (diego-biurrun) wrote : Posted in a previous version of this proposal

 review needs-fixing

On Thu, Jan 19, 2012 at 07:36:24AM +0000, Stefan Götz wrote:
> Stefan Götz has proposed merging lp:~stefan.goetz/hipl/commitguard into lp:hipl.

Looks mostly good to me. I don't speak Python, so this review is
necessarily superficial.

> --- .commitguards/author-attribution.guard 1970-01-01 00:00:00 +0000
> +++ .commitguards/author-attribution.guard 2012-01-19 07:35:28 +0000
> @@ -0,0 +1,4 @@
> +[guard]
> +files=\.(c|h|am|ac|in|py|sh)$
> +actions=amr
> +command=if egrep -q "\*.*@author\b" "{}"; then echo "{}: files should not contain author attributions"; false; fi

Do we really need to restrict this to certain file types?

> --- .commitguards/copyright-guard-space.py 1970-01-01 00:00:00 +0000
> +++ .commitguards/copyright-guard-space.py 2012-01-19 07:35:28 +0000
> @@ -0,0 +1,68 @@
> +#!/usr/bin/env python
> +# -*- coding: latin-1 -*-

Please use UTF-8, this is the 21st century (for some time already).
I'm also not sure if you need to tell emacs about this, the file
should be ASCII anyway.

> --- .commitguards/copyright-year.guard 1970-01-01 00:00:00 +0000
> +++ .commitguards/copyright-year.guard 2012-01-19 07:35:28 +0000
> @@ -0,0 +1,4 @@
> +[guard]
> +files=\.(c|h|am|ac|in|py|sh)$
> +actions=amr
> +command=CR_TOKEN=" Copyright \(c\) "; CR_HOLDER=" Aalto "; Y=$(date +%Y); if ! egrep "$CR_TOKEN.*$CR_HOLDER" "{}" | egrep -q "\b$Y\b"; then echo "{}: The copyright statement is not up-to-date"; sed -r "/ Copyright \(c\) / { /\b$Y\b/ ! s/ ([0-9, -]+) ([a-zA-Z]+)/ $Y \2/ }" "{}" | diff -u "{}" - >&2; false; fi
>
> === added file 'tools/bazaar/plugins/commitguard.py'
> --- tools/bazaar/plugins/commitguard.py 1970-01-01 00:00:00 +0000
> +++ tools/bazaar/plugins/commitguard.py 2012-01-19 07:35:28 +0000
> @@ -0,0 +1,353 @@
> +#!/usr/bin/env python
> +# -*- coding: latin-1 -*-

ditto

> +_commitguard_tutorial = """
> +Bazaar plugin for checking code modifications at pre-commit time.
> +
> +About
> +-----
> +
> +Installation
> +------------
> +Copy this file into the bazaar plugin directory (usually .bazaar/plugins/ in

Bazaar

> + The commitguard plugin offers the user to apply such a patch automatically
> + for convenience.

For added convenience the commitguard plugin offers the user the option
of applying such a patch automatically.

Diego

review: Needs Fixing
Revision history for this message
Stefan Götz (stefan.goetz-deactivatedaccount) wrote : Posted in a previous version of this proposal

> Looks mostly good to me. I don't speak Python, so this review is
> necessarily superficial.

Thanks for the review(s)!

>> --- .commitguards/author-attribution.guard 1970-01-01 00:00:00 +0000
>> +++ .commitguards/author-attribution.guard 2012-01-19 07:35:28 +0000
>> @@ -0,0 +1,4 @@
>> +[guard]
>> +files=\.(c|h|am|ac|in|py|sh)$
>> +actions=amr
>> +command=if egrep -q "\*.*@author\b" "{}"; then echo "{}: files should not contain author attributions"; false; fi
>
> Do we really need to restrict this to certain file types?

Not really, no. I changed it so it applies to all files.

>> --- .commitguards/copyright-guard-space.py 1970-01-01 00:00:00 +0000
>> +++ .commitguards/copyright-guard-space.py 2012-01-19 07:35:28 +0000
>> @@ -0,0 +1,68 @@
>> +#!/usr/bin/env python
>> +# -*- coding: latin-1 -*-
>
> Please use UTF-8, this is the 21st century (for some time already).

You're right. Done (removed).

> I'm also not sure if you need to tell emacs about this, the file
> should be ASCII anyway.

This comment is also obeyed by the python interpreter. In fact, it is
necessary as soon as non-plain-ASCII characters are in a python script.

>> bazaar
> Bazaar
>
>> + The commitguard plugin offers the user to apply such a patch automatically
>> + for convenience.
>
> For added convenience the commitguard plugin offers the user the option
> of applying such a patch automatically.

Done.

Cheers,
 Stefan

Revision history for this message
Miika Komu (miika-iki) wrote : Posted in a previous version of this proposal

How does the differ from tools/bazaar/plugins/stylecheck.py or what is the relationship with it? And why do we need now two different hooks?

Revision history for this message
Stefan Götz (stefan.goetz-deactivatedaccount) wrote : Posted in a previous version of this proposal

> How does the differ from tools/bazaar/plugins/stylecheck.py or what is the relationship with it?

stylecheck.py is specifically tailored towards running a code
beautifier, uncrustify in our case.

commitguard.py makes it much simpler to run arbitrary commands at
pre-commit time and adds a little bit of user convenience. This is
useful for checks that uncrustify cannot perform and is very easy to extend.

> And why do we need now two different hooks?

It would be possible to run uncrustify via the commitguard plugin
instead of the stylecheck plugin. However, some stylecheck features make
it much more usable with uncrustify than commitguard. In particular,
uncrustify can operate on multiple files with stylecheck while
commitguard aborts the commit after the first inconsistent file found,
which can be annoying if there several files need uncrustification.

I'd say that both plugins have their use.

Cheers,
 Stefan

Revision history for this message
Miika Komu (miika-iki) wrote : Posted in a previous version of this proposal

Hi,

On 01/19/2012 06:16 PM, Stefan Götz wrote:
>> How does the differ from tools/bazaar/plugins/stylecheck.py or what is the relationship with it?
>
> stylecheck.py is specifically tailored towards running a code
> beautifier, uncrustify in our case.
>
> commitguard.py makes it much simpler to run arbitrary commands at
> pre-commit time and adds a little bit of user convenience. This is
> useful for checks that uncrustify cannot perform and is very easy to extend.
>
>> And why do we need now two different hooks?
>
> It would be possible to run uncrustify via the commitguard plugin
> instead of the stylecheck plugin. However, some stylecheck features make
> it much more usable with uncrustify than commitguard. In particular,
> uncrustify can operate on multiple files with stylecheck while
> commitguard aborts the commit after the first inconsistent file found,
> which can be annoying if there several files need uncrustification.
>
> I'd say that both plugins have their use.

sorry if I forgot some earlier discussions on the topic but until I see
a clear and concrete plan yet to replace stylecheck with commitguard, I
would suggest to sticking to a single tool (stylecheck.py) instead of
introducing another alternative as an extra maintenance burden.

Revision history for this message
Stefan Götz (stefan.goetz-deactivatedaccount) wrote : Posted in a previous version of this proposal

> sorry if I forgot some earlier discussions on the topic but until I see
> a clear and concrete plan yet to replace stylecheck with commitguard, I
> would suggest to sticking to a single tool (stylecheck.py) instead of
> introducing another alternative as an extra maintenance burden.

Running uncrustify via commitguard results in a definite and annoying
loss of usability. Thus I strongly recommend keeping stylecheck around.
Otherwise, I'd be worried that users abandon the use of pre-commit hooks
altogether because using uncrustify became more cumbersome.

Note that the commitguard plugin, as is, runs checks that are orthogonal
to what uncrustify does. So this plugin is useful to HIPL developers in
itself. I'm not sure whether this became sufficiently clear.

How about this: I'll create a commit guard that runs uncrustify but
leave it disabled. Should the maintenance burden of having both
commitguard and stylecheck become a real issue, we could always drop
stylecheck at that point. Ok?

Stefan

Revision history for this message
Miika Komu (miika-iki) wrote : Posted in a previous version of this proposal

Hi,

On 20/01/12 16:52, Stefan Götz wrote:
>> sorry if I forgot some earlier discussions on the topic but until I see
>> a clear and concrete plan yet to replace stylecheck with commitguard, I
>> would suggest to sticking to a single tool (stylecheck.py) instead of
>> introducing another alternative as an extra maintenance burden.
>
> Running uncrustify via commitguard results in a definite and annoying
> loss of usability. Thus I strongly recommend keeping stylecheck around.
> Otherwise, I'd be worried that users abandon the use of pre-commit hooks
> altogether because using uncrustify became more cumbersome.
>
> Note that the commitguard plugin, as is, runs checks that are orthogonal
> to what uncrustify does. So this plugin is useful to HIPL developers in
> itself. I'm not sure whether this became sufficiently clear.

thanks for making this explicit, I understood this now better. I guess
there's more policies coming to the commitguard plugin?

> How about this: I'll create a commit guard that runs uncrustify but
> leave it disabled.

If it's orthogonal instead of redundant, then no need to.

> Should the maintenance burden of having both
> commitguard and stylecheck become a real issue, we could always drop
> stylecheck at that point. Ok?

Ok.

Revision history for this message
Miika Komu (miika-iki) wrote : Posted in a previous version of this proposal

So go ahead with this one.

review: Approve
Revision history for this message
René Hummen (rene-hummen) wrote : Posted in a previous version of this proposal

Thanks a lot for the automated commit guards. Very good documentation and extensibility!

I just got a suggested workflow that would allow merging of the stylechecker with this script:
1) Make a local copy of the files touched in the current commit.
2) Apply the commit guards (including uncrustify) one after the other to each of the local copies.
2.1) Tell the user which guard failed on which file.
2.2) Apply an eventual change of a commit guard to the local copy.
3) After all commit guards have been executed (and the corresponding changes have been applied to the local copies incrementally), show the user the diff between the local files and the files in the commit.
3.1) Apply diff, if accepted by the user.

I know that this workflow would require some restructuring of the code. Hence, I don't mind having two scripts for now. However, the benefit would be a single pre-commit hook and the check of all committed files with _all_ hooks in one go. Right now, we need to commit as often as the commit contains "errors" until finally the commit is pushed to the repository.

Additionally, it might be worth having an install_bzr_hooks.sh script that copies the scripts to one of the two valid bazaar plugin locations in order to increase usage and acceptance.

Revision history for this message
Diego Biurrun (diego-biurrun) wrote : Posted in a previous version of this proposal

On Thu, Jan 19, 2012 at 04:16:56PM +0000, Stefan Götz wrote:
> > And why do we need now two different hooks?
>
> It would be possible to run uncrustify via the commitguard plugin
> instead of the stylecheck plugin. However, some stylecheck features make
> it much more usable with uncrustify than commitguard. In particular,
> uncrustify can operate on multiple files with stylecheck while
> commitguard aborts the commit after the first inconsistent file found,
> which can be annoying if there several files need uncrustification.

This is a considerable shortcoming IMO. Ideally all issues in all
files should be detected and be complained about. Otherwise you have
to run through multiple iterations of commit guard as you fix issue
after issue...

Diego

Revision history for this message
Stefan Götz (stefan.goetz-deactivatedaccount) wrote : Posted in a previous version of this proposal

Hi Rene!

> I just got a suggested workflow that would allow merging of the stylechecker with this script:
> 1) Make a local copy of the files touched in the current commit.
> 2) Apply the commit guards (including uncrustify) one after the other to each of the local copies.
> 2.1) Tell the user which guard failed on which file.
> 2.2) Apply an eventual change of a commit guard to the local copy.
> 3) After all commit guards have been executed (and the corresponding changes have been applied to the local copies incrementally), show the user the diff between the local files and the files in the commit.
> 3.1) Apply diff, if accepted by the user.

That makes a lot of sense and is certainly more usable than the current
approach. I'll work on it on the usability branch.

> Additionally, it might be worth having an install_bzr_hooks.sh script that copies the scripts to one of the two valid bazaar plugin locations in order to increase usage and acceptance.

Yeah, well, I don't think the difference between a single cp command and a
script will change something about usage and acceptance - so I'll let someone
else write that script :)

Stefan

Revision history for this message
Miika Komu (miika-iki) wrote : Posted in a previous version of this proposal

I just realized that the only the documentation is in the script itself and there's nothing in the HACKING - is this intentional?

Revision history for this message
René Hummen (rene-hummen) wrote :

I should be mentioned in HACKING. There is already some hint at stylecheck. So this would be the right location to tell developers to use commitguard as well.

Otherwise, I am fine with the script.

review: Approve
Revision history for this message
Stefan Götz (stefan.goetz-deactivatedaccount) wrote :

> Review: Approve
>
> I should be mentioned in HACKING.

I agree. I think you mixed up the 'approve' and the 'needs fixing'
buttons, though ;-)

Revision history for this message
Diego Biurrun (diego-biurrun) wrote :

On Mon, Jan 23, 2012 at 10:39:49AM +0000, René Hummen wrote:
> Review: Approve
>
> I should be mentioned in HACKING.

I want to be mentioned in HACKING as well!

SCNR, Diego

Revision history for this message
René Hummen (rene-hummen) wrote :

On 23.01.2012, at 12:46, Stefan Götz wrote:
>> Review: Approve
>>
>> I should be mentioned in HACKING.
>
> I agree. I think you mixed up the 'approve' and the 'needs fixing'
> buttons, though ;-)

While the "I" should of course be an "It", I approved your proposal because I don't require a new merge proposal for the additional text in HACKING.

--
Dipl.-Inform. Rene Hummen, Ph.D. Student
Chair of Communication and Distributed Systems
RWTH Aachen University, Germany
tel: +49 241 80 20772
web: http://www.comsys.rwth-aachen.de/team/rene-hummen/

6250. By Diego Biurrun

Ignore test/check_hipd unit test executable.

6251. By Diego Biurrun

hipd: Fix some typos that the DEB package lintian program complained about.

6252. By Diego Biurrun

debian: Abort on errors during dnsproxy postinst script.

6253. By Diego Biurrun

debian: Register HIPL documentation with doc-base.

6254. By Diego Biurrun

debian: Extend package descriptions.

6255. By Diego Biurrun

packaging: Add dependency of hipdnsproxy on hipd.

hipdnsproxy reads etc/hip/hosts, which only exists if hipd is installed.

6256. By Diego Biurrun

hadb: Vastly simplify match_peer_addr().

6257. By Diego Biurrun

Rename nsupdate.pl ---> nsupdate.

It's more sensible to leave out the unnecessary language extension from the
program name. It does not really add information and would have to be
changed in the case the program was rewritten some day.

6258. By Miika Komu

A bug fix to hipfw unit tests on 32-bit machines

Fixed bug id #918374 in launchpad. Now two failing hipfw tests are
disabled on 32-bit machines. Tested on both 32-bit and 64-bit machines.

6259. By Stefan Götz

Compare host IDs across all address bytes instead of comparing only the first few bytes equal to the width of a pointer.

Revision history for this message
Diego Biurrun (diego-biurrun) wrote :
Download full text (6.2 KiB)

 review needs-fixing

On Mon, Jan 23, 2012 at 06:56:27AM +0000, Stefan Götz wrote:
> Stefan Götz has proposed merging lp:~stefan.goetz/hipl/commitguard into lp:hipl.
>
> Requested reviews:
> Miika Komu (miika-iki)
> Diego Biurrun (diego-biurrun)

This looks good to me as far as I can review Python code.

A few questions remain:

- Should we merge all guard declarations into a single config file?
- Does the commitguard script still abort after the first violation
  or does it report all violations? Does it abort after the first
  violating file?

> --- .commitguards/copyright-guard-space.py 1970-01-01 00:00:00 +0000
> +++ .commitguards/copyright-guard-space.py 2012-01-23 06:55:32 +0000
> @@ -0,0 +1,65 @@
> +#!/usr/bin/env python
> +
> +#
> +# Copyright (c) 2012 Aalto University and RWTH Aachen University.
> +#
> +# Permission is hereby granted, free of charge, to any person
> +# obtaining a copy of this software and associated documentation
> +# files (the "Software"), to deal in the Software without
> +# restriction, including without limitation the rights to use,
> +# copy, modify, merge, publish, distribute, sublicense, and/or sell
> +# copies of the Software, and to permit persons to whom the
> +# Software is furnished to do so, subject to the following
> +# conditions:
> +#
> +# The above copyright notice and this permission notice shall be
> +# included in all copies or substantial portions of the Software.
> +#
> +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
> +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
> +# OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
> +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
> +# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
> +# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
> +# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
> +# OTHER DEALINGS IN THE SOFTWARE.
> +#

nit++: we usually have no empty line after the shebang or empty
comment lines after the license header.

> --- .commitguards/copyright-year.guard 1970-01-01 00:00:00 +0000
> +++ .commitguards/copyright-year.guard 2012-01-23 06:55:32 +0000
> @@ -0,0 +1,36 @@
> +
> +[guard]
> +files=\.(c|h|am|ac|in|py|sh|guard)$
> +actions=amr
> +command=
> + CR_TOKEN=" Copyright \(c\) "
> + CR_HOLDER=" Aalto "
> + Y=$(date +%Y)
> + if ! egrep "$CR_TOKEN.*$CR_HOLDER" "{}" | egrep -q "\b$Y\b"; then

egrep is GNU-specific, 'grep -E' should be more portable.

I'd use ${} for referencing variables here. There can be tricky sideeffects
when variable references are not followed by whitespace. The special
characters used here should not cause issues, but the poor sould that
modifies the command could step into a trap.

> + echo "{}: The copyright statement is not up-to-date"
> + L=$(( $Y - 1 ))
> + sed -r "/ Copyright \(c\) / { /\b$Y\b/ ! { /-$L / s/-$L /-$Y /; s/ $L / $L-$Y /; /\b$Y\b/ ! s/ ([0-9, -]+) ([a-zA-Z]+)/ \1, $Y \2/ } }" "{}" | diff -u "{}" - >&2

Hmmm, more GNUisms, -r is not a POSIX option for sed.

What are these \b patterns that you use? I cannot find them in any
manual.

> --- tools/bazaar/plugins/com...

Read more...

review: Needs Fixing
6260. By Stefan Götz

Merge lp:~stefan.goetz/hipl/hidb-db, approved by Rene and Diego

Revision history for this message
Stefan Götz (stefan.goetz-deactivatedaccount) wrote :

Hi Diego!

Thanks for the review!

> - Should we merge all guard declarations into a single config file?

Technically, that's possible. I don't see any big advantages or
disadvantages with a central vs. separate files.

> - Does the commitguard script still abort after the first violation
> or does it report all violations? Does it abort after the first
> violating file?

Yes. I've started working on this issue in the commitguard-usability
branch, though.

>> +# OTHER DEALINGS IN THE SOFTWARE.
>> +#
>
> nit++: we usually have no empty line after the shebang or empty
> comment lines after the license header.

Fixed

>> + if ! egrep "$CR_TOKEN.*$CR_HOLDER" "{}" | egrep -q "\b$Y\b"; then
>
> egrep is GNU-specific, 'grep -E' should be more portable.

Fixed

> I'd use ${} for referencing variables here.

Fixed

> Hmmm, more GNUisms, -r is not a POSIX option for sed.

Fixed

> What are these \b patterns that you use? I cannot find them in any
> manual.

Word delimiters. I removed them.

>> +1) A set of file-name patterns the guard is to be applied to.
>
> filename
>
>> + The configuration value is a regular expression.
>
> I think that would be a POSIX extended regular expression.
>
>> + characters a, m, and r, representing added, modified, and renamed files
>
> 'a', 'm', and 'r'
>
>> + Before executing this command, all occurrences of the sub-string {} are
>
> substring
>
>> + For added convenience, the commitguard plugin offers the user to apply such
>> + a patch straight away.
>
> offers the user the option of applying such

Fixed

> Is there a reason why you have moved each sentence to a separate line?

When a line is changed, only that sentence needs to be rewrapped instead
of a whole paragraph.

Cheers,
 Stefan

Revision history for this message
Diego Biurrun (diego-biurrun) wrote :

On Wed, Jan 25, 2012 at 09:48:52PM +0100, Stefan Götz wrote:
> > - Should we merge all guard declarations into a single config file?
>
> Technically, that's possible. I don't see any big advantages or
> disadvantages with a central vs. separate files.

Me neither.

> > - Does the commitguard script still abort after the first violation
> > or does it report all violations? Does it abort after the first
> > violating file?
>
> Yes. I've started working on this issue in the commitguard-usability
> branch, though.

So what's your plan? Merge once the usability branch is ready or
merge this one first, then the usability branch?

> > What are these \b patterns that you use? I cannot find them in any
> > manual.
>
> Word delimiters. I removed them.

I'm still mildly curious - where did you find them documented?

Diego

Revision history for this message
Stefan Götz (stefan.goetz-deactivatedaccount) wrote :

Hi Diego!

> So what's your plan? Merge once the usability branch is ready or
> merge this one first, then the usability branch?

The plan is to merge the commitguard branch now because a) the plugin is
useful in its current state, b) the plugin is not enabled by default so
it doesn't hurt, and c) early merging avoids bitrot.

That depends on your 'approve' vote, though. If you think that this
branch is now ready for merging, please approve the merge request.

>>> What are these \b patterns that you use? I cannot find them in any
>>> manual.

The grep man-page (http://linux.die.net/man/1/grep) has it, for example.

Cheers,
 Stefan

6281. By Stefan Götz

Briefly mention the commitguard (and the stylecheck) plugin in doc/HACKING

6282. By Stefan Götz

Remove empty leading and trailing comment lines in copyright blocks.

6283. By Stefan Götz

Remove GNU-isms from scripts

6284. By Stefan Götz

Fix grammar in documentation

6285. By Stefan Götz

Place references to shell variables into curly braces to avoid expansion problems

6286. By Stefan Götz

Remove '\b' from regular expression for portability

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== added directory '.commitguards'
2=== added file '.commitguards/author-attribution.guard'
3--- .commitguards/author-attribution.guard 1970-01-01 00:00:00 +0000
4+++ .commitguards/author-attribution.guard 2012-01-27 06:18:23 +0000
5@@ -0,0 +1,31 @@
6+# Copyright (c) 2012 Aalto University and RWTH Aachen University.
7+#
8+# Permission is hereby granted, free of charge, to any person
9+# obtaining a copy of this software and associated documentation
10+# files (the "Software"), to deal in the Software without
11+# restriction, including without limitation the rights to use,
12+# copy, modify, merge, publish, distribute, sublicense, and/or sell
13+# copies of the Software, and to permit persons to whom the
14+# Software is furnished to do so, subject to the following
15+# conditions:
16+#
17+# The above copyright notice and this permission notice shall be
18+# included in all copies or substantial portions of the Software.
19+#
20+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
22+# OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
24+# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
25+# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26+# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
27+# OTHER DEALINGS IN THE SOFTWARE.
28+
29+[guard]
30+files=.*
31+actions=amr
32+command=
33+ if AUTHORS="$(egrep "@author\b" "{}")"; then
34+ echo "{}: files should not contain author attributions such as '$(echo "${AUTHORS}" | head -n 1)'"
35+ false
36+ fi
37
38=== added file '.commitguards/copyright-guard-space.guard'
39--- .commitguards/copyright-guard-space.guard 1970-01-01 00:00:00 +0000
40+++ .commitguards/copyright-guard-space.guard 2012-01-27 06:18:23 +0000
41@@ -0,0 +1,27 @@
42+# Copyright (c) 2012 Aalto University and RWTH Aachen University.
43+#
44+# Permission is hereby granted, free of charge, to any person
45+# obtaining a copy of this software and associated documentation
46+# files (the "Software"), to deal in the Software without
47+# restriction, including without limitation the rights to use,
48+# copy, modify, merge, publish, distribute, sublicense, and/or sell
49+# copies of the Software, and to permit persons to whom the
50+# Software is furnished to do so, subject to the following
51+# conditions:
52+#
53+# The above copyright notice and this permission notice shall be
54+# included in all copies or substantial portions of the Software.
55+#
56+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
57+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
58+# OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
59+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
60+# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
61+# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
62+# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
63+# OTHER DEALINGS IN THE SOFTWARE.
64+
65+[guard]
66+files=\.(c|h|am|ac|in|py|sh|guard)$
67+actions=amr
68+command=copyright-guard-space.py "{}"
69
70=== added file '.commitguards/copyright-guard-space.py'
71--- .commitguards/copyright-guard-space.py 1970-01-01 00:00:00 +0000
72+++ .commitguards/copyright-guard-space.py 2012-01-27 06:18:23 +0000
73@@ -0,0 +1,63 @@
74+#!/usr/bin/env python
75+
76+# Copyright (c) 2012 Aalto University and RWTH Aachen University.
77+#
78+# Permission is hereby granted, free of charge, to any person
79+# obtaining a copy of this software and associated documentation
80+# files (the "Software"), to deal in the Software without
81+# restriction, including without limitation the rights to use,
82+# copy, modify, merge, publish, distribute, sublicense, and/or sell
83+# copies of the Software, and to permit persons to whom the
84+# Software is furnished to do so, subject to the following
85+# conditions:
86+#
87+# The above copyright notice and this permission notice shall be
88+# included in all copies or substantial portions of the Software.
89+#
90+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
91+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
92+# OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
93+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
94+# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
95+# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
96+# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
97+# OTHER DEALINGS IN THE SOFTWARE.
98+
99+#
100+# Test whether a copyright comment block is followed by a blank line
101+#
102+
103+import os, re, sys
104+
105+class CommentStyle:
106+ def __init__(self, header, body, footer):
107+ self.header = header
108+ self.body = body
109+ self.footer = footer
110+
111+
112+c_style = CommentStyle(' \* Copyright ', ' \*', ' \*/')
113+hash_style = CommentStyle('# Copyright ', '#', '#.*')
114+
115+styles = {
116+ '.c': c_style,
117+ '.h': c_style,
118+ '.am': hash_style,
119+ '.ac': hash_style,
120+ '.in': hash_style,
121+ '.py': hash_style,
122+ '.sh': hash_style,
123+}
124+
125+extension = os.path.splitext(sys.argv[1])[1]
126+if extension in styles:
127+ style = styles[extension]
128+ pattern = re.compile('^' + style.header + '[^\n]*\n(^' + style.body + '[^\n]*\n)+^' + style.footer + '\n\n', re.MULTILINE)
129+
130+ fh = open(sys.argv[1], 'r')
131+ match = pattern.search(fh.read())
132+ fh.close()
133+
134+ if not match:
135+ print 'The copyright header in file %s should be followed by an empty line' % (sys.argv[1])
136+ sys.exit(1)
137
138=== added file '.commitguards/copyright-year.guard'
139--- .commitguards/copyright-year.guard 1970-01-01 00:00:00 +0000
140+++ .commitguards/copyright-year.guard 2012-01-27 06:18:23 +0000
141@@ -0,0 +1,36 @@
142+# Copyright (c) 2012 Aalto University and RWTH Aachen University.
143+#
144+# Permission is hereby granted, free of charge, to any person
145+# obtaining a copy of this software and associated documentation
146+# files (the "Software"), to deal in the Software without
147+# restriction, including without limitation the rights to use,
148+# copy, modify, merge, publish, distribute, sublicense, and/or sell
149+# copies of the Software, and to permit persons to whom the
150+# Software is furnished to do so, subject to the following
151+# conditions:
152+#
153+# The above copyright notice and this permission notice shall be
154+# included in all copies or substantial portions of the Software.
155+#
156+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
157+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
158+# OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
159+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
160+# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
161+# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
162+# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
163+# OTHER DEALINGS IN THE SOFTWARE.
164+
165+[guard]
166+files=\.(c|h|am|ac|in|py|sh|guard)$
167+actions=amr
168+command=
169+ CR_TOKEN=" Copyright \(c\) "
170+ CR_HOLDER=" Aalto "
171+ Y=$(date +%Y)
172+ if ! grep -E "${CR_TOKEN}.*${CR_HOLDER}" "{}" | grep -Eq "[^0-9]${Y}[^0-9]"; then
173+ echo "{}: The copyright statement is not up-to-date"
174+ L=$(( ${Y} - 1 ))
175+ sed "/ Copyright (c) / { /[^0-9]${Y}[^0-9]/ ! { /-${L} / s/-${L} /-${Y} /; s/ ${L} / ${L}-${Y} /; /[^0-9]${Y}[^0-9]/ ! s/ \([0-9, -]\+\) \([a-zA-Z]\+\)/ \1, ${Y} \2/ } }" "{}" | diff -u "{}" - >&2
176+ false
177+ fi
178
179=== modified file 'doc/HACKING'
180--- doc/HACKING 2012-01-15 15:36:14 +0000
181+++ doc/HACKING 2012-01-27 06:18:23 +0000
182@@ -45,6 +45,17 @@
183 bzr whoami "#FIRST_NAME# #LAST_NAME# <#EMAIL_ADDRESS#>"
184
185
186+Bazaar plugins
187+--------------
188+
189+HIPL comes with Bazaar plugins which are very strongly recommended because
190+they help with improving code style and quality.
191+They can be installed with the following commands:
192+
193+#> mkdir -p ~/.bazaar/plugins
194+#> cp tools/bazaar/plugins/* ~/.bazaar/plugins/
195+
196+
197 Creating a local shared repository (optional, but recommended)
198 --------------------------------------------------------------
199
200@@ -620,11 +631,22 @@
201 Style Checking
202 --------------
203
204-As a tool to help with good style, please use the stylecheck pre-commit
205-hook found in tools/bazaar/plugins/stylecheck.py - this script contains its own
206-documentation, including how to set it up.
207-
208-You are strongly recommended to use this hook based on the code beautifier
209+As a tool to help with good style, please use the pre-commit hooks in the
210+directory tools/bazaar/plugins/ - installing them should be as easy as
211+copying them to your Bazaar plugin directory:
212+
213+#> cp tools/bazaar/plugins/* ~/.bazaar/plugins/
214+
215+Currently, there are two bazaar plugins:
216+- The commit guard plugin implements a set of pre-commit hooks that check
217+ general style conventions in HIPL, e.g., that all files must have UNIX-
218+ style line breaks.
219+- The stylecheck plugin specifically uses a code beautifier to check for
220+ C code-style violations. More on it below.
221+
222+Both scripts contain their own documentation, including how to set them up.
223+
224+You are strongly recommended to use stylecheck based on the code beautifier
225 uncrustify because it gets things right almost all the time. So you can and
226 should throw all code at uncrustify (via the commit hook) to have it checked.
227
228
229=== added file 'tools/bazaar/plugins/commitguard.py'
230--- tools/bazaar/plugins/commitguard.py 1970-01-01 00:00:00 +0000
231+++ tools/bazaar/plugins/commitguard.py 2012-01-27 06:18:23 +0000
232@@ -0,0 +1,349 @@
233+#!/usr/bin/env python
234+
235+# Copyright (c) 2012 Aalto University and RWTH Aachen University.
236+#
237+# Permission is hereby granted, free of charge, to any person
238+# obtaining a copy of this software and associated documentation
239+# files (the "Software"), to deal in the Software without
240+# restriction, including without limitation the rights to use,
241+# copy, modify, merge, publish, distribute, sublicense, and/or sell
242+# copies of the Software, and to permit persons to whom the
243+# Software is furnished to do so, subject to the following
244+# conditions:
245+#
246+# The above copyright notice and this permission notice shall be
247+# included in all copies or substantial portions of the Software.
248+#
249+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
250+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
251+# OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
252+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
253+# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
254+# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
255+# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
256+# OTHER DEALINGS IN THE SOFTWARE.
257+
258+_commitguard_tutorial = """
259+Bazaar plugin for checking code modifications at pre-commit time.
260+
261+About
262+-----
263+
264+Installation
265+------------
266+Copy this file into the Bazaar plugin directory (usually .bazaar/plugins/ in
267+your home directory) or add the directory this file resides in to the
268+environment variable BZR_PLUGIN_PATH (export BZR_PLUGIN_PATH="<dir>") before
269+running 'bzr commit'.
270+
271+The pre-commit checks (or 'guards') are described in configuration files with
272+the extension .guard. This script looks for such files in two directories:
273+ 1) $HOME/.bazaar/plugins/commitguards/
274+ 2) <repository>/.commitguards/
275+This allows to set up commit guards both per user and per repository.
276+
277+Usage
278+-----
279+This hook is called automatically when running the command 'bzr commit' after
280+the commit message has been provided. All available commit guards are then
281+applied to the files in the commit. If a file fails a commit guard, the
282+commit is aborted with an error message detailing the failure. The commit
283+message is printed again for convenience. A commit guard can optionally
284+suggest a patch to the file so that it meets the guard's requirements.
285+
286+At the moment, a commit is aborted on the first failing commit guard.
287+
288+Commit Guards
289+-------------
290+Commit guards are described in plain-text configuration files in .ini
291+style with the extension .guard. The basic format of these files is
292+
293+[guard]
294+files=<value>
295+actions=<value>
296+command=<value>
297+
298+Each guard configuration file provides three pieces of information about a
299+commit guard:
300+
301+1) A set of filename patterns the guard is to be applied to.
302+ The configuration key is 'files'.
303+ The configuration value is a POSIX extended regular expression.
304+ For example, the entry 'files=\.(c|C)$' makes sure that the guard is applied
305+ to all files with the extension .c or .C
306+
307+2) A set of commit actions specifying if the guard is to be applied to
308+ added, modified, and/or renamed files.
309+ The configuration key is 'actions'.
310+ The configuration value is a string consisting of one or more of the
311+ characters 'a', 'm', and 'r', representing added, modified, and renamed files
312+ respectively.
313+ For example, the entry 'actions=am' makes sure that the guard is applied to
314+ new and modified files in a commit but not to renamed files.
315+
316+3) A command that is executed and which implements the actual guard action.
317+ The configuration key is 'command'.
318+ The configuration value is a string containing a shell command.
319+ Before executing this command, all occurrences of the substring {} are
320+ replaced with the name of the (added, modified, or renamed) file in the
321+ repository and commit to apply the guard to.
322+ If the guard considers the given file valid as is, the command should exit
323+ with an exit code of 0.
324+ In this case, the remaining guards are applied to the remaining files in the
325+ commit.
326+ If the guard considers a given file as invalid, it should exit with a
327+ non-zero exit code.
328+ In this case, it may print a message to stdout to inform the user why the
329+ commit was aborted.
330+ Optionally, the command may print a patch in unified diff format on stderr
331+ that, if applied, would bring the file into compliance with the guard's
332+ requirements.
333+ For added convenience, the commitguard plugin offers the user the option of
334+ applying such a patch straight away.
335+ Helper executables can be placed into the same directory as a .guard file.
336+ The guard command can then invoke these executables as if they were system
337+ commands.
338+
339+
340+
341+"""
342+
343+version_info = (0, 1, 0, 'dev', 0)
344+plugin_name = 'commitguard'
345+
346+from bzrlib import branch, help_topics
347+import bzrlib
348+import subprocess
349+import os
350+import os.path
351+import sys
352+import tempfile
353+import re
354+import ConfigParser
355+
356+
357+def get_local_file_name(branch, file_name):
358+ """Determine the absolute path of the file in a local Bazaar working branch.
359+
360+ Arguments:
361+ branch -- an instance of bzrlib's Branch representing a local working
362+ branch. file_name is resolved relative to the base location of branch.
363+ file_name -- a string containing the relative path of a file in the file
364+ tree of branch.
365+
366+ This function returns a string that contains the absolute path of the
367+ specified file. This file is the actual on-disk working copy and can be
368+ accessed and modified. If file_name does not exist in branch or the
369+ corresponding local file cannot be found, a RuntimeError is raised.
370+
371+ """
372+ base = branch.base
373+ if base.startswith('file://'):
374+ base = base[7:]
375+ local_file_name = os.path.join(base, file_name)
376+ if os.path.exists(local_file_name):
377+ return local_file_name
378+ else:
379+ raise RuntimeError("The file '%s' in branch '%s' could not be found at \
380+'%s' as expected!" % (file_name, branch, local_file_name))
381+
382+
383+
384+class Guard(object):
385+ """A tool that inspects the new state a commit introduces and allows or
386+ aborts the commit.
387+
388+ Each instance of this class wraps a 'guard' tool which may analyse and check
389+ the set of modifications of a commit. It may then let the commit pass or
390+ prevent it.
391+
392+ """
393+ def __init__(self, cfg_file_name):
394+ """Creates and initializes a Guard object and its attributes.
395+
396+ If the initialization fails, e.g., because a tool is not available or
397+ the configuration is invalid, an Exception is raised.
398+
399+ cfg_file_name -- The path of a guard configuration file from which to
400+ initialize this object.
401+
402+ """
403+ self.configure(cfg_file_name)
404+
405+ def configure(self, cfg_file_name):
406+ """Initialize a Guard object from a configuration file.
407+
408+ cfg_file_name -- The path of a guard configuration file from which to
409+ initialize this object.
410+
411+ """
412+ config = ConfigParser.RawConfigParser()
413+ config.read(cfg_file_name)
414+ self.files = re.compile(config.get('guard', 'files'), re.IGNORECASE)
415+ self.actions = config.get('guard', 'actions')
416+ self.command = unicode(config.get('guard', 'command'), encoding='utf-8')
417+ self.filename = cfg_file_name
418+ self.dirname = os.path.dirname(cfg_file_name)
419+
420+ def applies_to(self, file_name, file_action):
421+ """Checks whether this guard applies to a given file or not.
422+
423+ file_name -- the name of the file in the working repository which is
424+ compared against this guard's file name pattern (not case sensitive).
425+ file_action -- one of the characters 'a', 'm', or 'r' to indicate
426+ whether a commit adds, modifies, or renames the given file. In the case
427+ of a renamed file, the file_name parameter is expected to be the new
428+ name of the file.
429+
430+ This function returns True if the given file name and action match this
431+ guard and False otherwise.
432+
433+ """
434+ return file_action in self.actions and self.files.search(file_name) is not None
435+
436+ def run(self, local_file_name, action, msg, diff):
437+ """Execute a guard to determine whether a commit may proceed or not.
438+
439+ Arguments:
440+ local_file_name -- the path of a local file to run the guard on. The
441+ guard may not modify this file.
442+ file_action -- one of the characters 'a', 'm', or 'r' to indicate
443+ whether a commit adds, modifies, or renames the given file. In the case
444+ of a renamed file, the local_file_name parameter is expected to be the
445+ new name of the file.
446+ msg -- a file-like object to which the guard may write a message for the
447+ user.
448+ diff -- a file-like object to which the guard may write a patch in
449+ unified diff format which shows how to modify the file contents in order
450+ to comply with this guard and let the commit proceed.
451+
452+ If this function returns true, the commit may proceed. If it returns
453+ false, the commit is aborted.
454+
455+ """
456+ if self.applies_to(local_file_name, action):
457+ cmd = self.command.replace('{}', local_file_name)
458+ env = os.environ
459+ if not self.dirname in env['PATH']:
460+ env['PATH'] += (':' + self.dirname)
461+ p = subprocess.Popen(cmd,
462+ shell = True,
463+ stdout = msg,
464+ stderr = diff,
465+ env = env)
466+ return p.wait() == 0
467+ else:
468+ return True
469+
470+
471+def create_guards_from_dir(cfgdir, guards):
472+ for wroot, wdirs, wfiles in os.walk(cfgdir):
473+ for f in wfiles:
474+ if f.endswith('.guard'):
475+ guards.append(Guard(os.path.join(wroot, f)))
476+ return guards
477+
478+
479+def create_guards(branch):
480+ guards = []
481+ cfgdirs = [os.path.join(os.path.expanduser('~'), '.bazaar/plugins/commitguards')]
482+ try:
483+ cfgdirs.append(get_local_file_name(branch, '.commitguards'))
484+ except:
485+ pass
486+ for cfgdir in cfgdirs:
487+ if os.path.exists(cfgdir):
488+ create_guards_from_dir(cfgdir, guards)
489+ return guards
490+
491+
492+def get_commit_files(tree_delta):
493+ """From all modifications in a commit, retrieve those files which should be
494+ run through the guards.
495+
496+ That is: added, modified, and renamed files, ignoring meta-data changes.
497+
498+ The return value is a list of tuples. Each tuple consists of a the path name
499+ of a file in the Bazaar repository tree as the first element and the
500+ character 'a', 'm', or 'r' indicating the action this commit performs on the
501+ file.
502+
503+ """
504+ # include added, modified, and renamed, skip removed and changed
505+ files = [(path, 'a') for path, file_id, kind in tree_delta.added if kind == 'file']
506+ files.extend([(path, 'm') for (path, file_id, kind, text_modified, _) in
507+ tree_delta.modified if kind == 'file'])
508+ files.extend([(newpath, 'r') for (oldpath, newpath, file_id, kind, text_modified, _) in
509+ tree_delta.renamed if kind == 'file'])
510+ return files
511+
512+
513+def get_commit_message(local, master, revid):
514+ """Returns the commit message of a branch revision."""
515+ branch = local or master
516+ revision = branch.repository.get_revision(revid)
517+ return revision.message
518+
519+
520+def apply_patch(diff_file):
521+ """Apply a patch to a local Bazaar branch.
522+
523+ diff_file -- a file-like object from which the patch can be read. The patch
524+ is expected to be in unified diff format.
525+
526+ If applying the beautification fails, a CalledProcessError is raised.
527+
528+ """
529+ subprocess.check_call(['patch', '-p0', '-i', diff_file.name])
530+
531+
532+def pre_commit_hook(local, master, old_revno, old_revid, future_revno,
533+ future_revid, tree_delta, future_tree):
534+ """Run the files modified by this commit through the configured guards and
535+ abort the commit if the guards veto it.
536+
537+ This is the pre-commit hook interface of bzrlib.
538+
539+ """
540+ guards = create_guards(local or master)
541+
542+ veto = False
543+ diff_file = tempfile.NamedTemporaryFile(prefix = plugin_name + "-diff-")
544+
545+ for tree_file_name, action in get_commit_files(tree_delta):
546+ local_file_name = get_local_file_name(local or master, tree_file_name)
547+ for guard in guards:
548+ if not guard.run(local_file_name, action, sys.stdout, diff_file):
549+ veto = True
550+ break
551+
552+ if veto:
553+ break
554+
555+ if veto:
556+ diff_file.flush()
557+ if diff_file.tell():
558+ print "\nThe following patch is suggested so as to comply with the commit guard requirements:\n"
559+ diff_file.seek(0)
560+ print diff_file.read()
561+ print "\nWould you like to apply these changes to your local branch now? [y/N] ",
562+ reply = sys.stdin.readline()
563+ if reply.strip() == 'y':
564+ apply_patch(diff_file)
565+ print "Changes successfully applied.\n"
566+ diff_file.close()
567+
568+ msg_file = tempfile.NamedTemporaryFile(prefix = 'commit-msg-%d-' % future_revno, delete = False)
569+ msg_file.write(get_commit_message(local, master, future_revid))
570+ msg_file.close()
571+
572+ raise bzrlib.errors.BzrError("This commit has been aborted. The original commit message, stored in %s, was:\n--\n%s\n--" % (msg_file.name, get_commit_message(local, master, future_revid)))
573+ diff_file.close()
574+
575+
576+help_topics.topic_registry.register(plugin_name + '-tutorial',
577+ _commitguard_tutorial,
578+ 'How to use the plugin ' + plugin_name)
579+
580+branch.Branch.hooks.install_named_hook('pre_commit', pre_commit_hook,
581+ plugin_name)

Subscribers

People subscribed via source and target branches

to all changes: