3 # A hook script to verify what is about to be committed.
4 # Called by "git commit" with no arguments. The hook should
5 # exit with non-zero status after issuing an appropriate message
6 # if it wants to stop the commit.
9 use lib
"solenv/clang-format";
15 sub check_whitespaces
($)
18 my $src_limited = "c|cpp|cxx|h|hrc|hxx|idl|inl|java|swift|map|MK|pmk|pl|pm|sdi|sh|src|tab|ui|xcu|xml|xsl|py";
19 my $src_full = "c|cpp|cxx|h|hrc|hxx|idl|inl|java|swift|map|mk|MK|pmk|pl|pm|sdi|sh|src|tab|ui|xcu|xml|xsl|py";
23 my $reported_filename = "";
27 my ($why, $line, $file_filter) = @_;
28 if (!defined $file_filter || $filename =~ /\.($file_filter)$/)
33 print STDERR
"* You have some suspicious patch lines:\n";
37 if ($reported_filename ne $filename)
39 print STDERR
"* In $filename\n";
40 $reported_filename = $filename;
42 print STDERR
"* $why (line $lineno)\n";
43 print STDERR
"$filename:$lineno:$line\n";
46 open( FILES
, "git-diff-index -p -M --cached $h |" ) || die "Cannot run git diff-index.";
49 if (m
|^diff
--git a
/(.*) b/\
1$|)
54 if (/^@@ -\S+ \+(\d+)/)
70 bad_line
("trailing whitespace", $_ , $src_limited);
74 bad_line
("DOS lineends", $_ , $src_limited);
78 bad_line
("indent with Tab", $_, $src_limited);
82 bad_line
("unresolved merge conflict", $src_full);
86 bad_line
("temporary debug in commit", $_, $src_limited);
88 if ((/OOXMLIMPORT/) and ($filename =~ /ooxmlexport/))
90 bad_line
("OOXMLIMPORT definition used in a ooxmlexport file", $_, "cxx");
92 if ((/OOXMLEXPORT/) and ($filename =~ /ooxmlimport/))
94 bad_line
("OOXMLEXPORT definition used in a ooxmlimport file", $_, "cxx");
96 if (/<property name="use_markup">True<\/property
>/)
98 bad_line
("use font attributes instead of use-markup", $_, "ui");
100 if (/<property name="tooltip_markup"/ )
102 bad_line
("use tooltip_text instead of tooltip_markup", $_, "ui");
104 if ((/translatable="yes"/) and not(/context=/))
106 bad_line
("translatable .ui file line without context", $_, "ui");
108 if ((/requires/) and (/lib="gtk+/) and not (/version="3.20/))
110 bad_line
("min supported version of gtk3 is 3.20", $_, "ui");
112 if ((/<interface/) and not(/domain=/))
114 bad_line
(".ui file without translation domain", $_, "ui");
126 my $author = `git var GIT_AUTHOR_IDENT`;
128 if ($author =~ /^Your Name <you\@example.com>/)
130 print("ERROR: You have a suspicious author identity: '$author'\n");
137 if (! -e
"solenv/clang-format/ClangFormat.pm")
139 # Commit happens in a submodule.
144 ClangFormat
->import();
147 my $src = ClangFormat
::get_extension_regex
();
149 my $clang_format = ClangFormat
::find
();
151 ## Check if ClangFormat has get_excludelist or the old
153 my $excluded_list_names;
154 eval { ClangFormat
::get_excludelist
() };
155 if ($@
) { $excluded_list_names = ClangFormat
::get_blacklist
(); }
156 else { $excluded_list_names = ClangFormat
::get_excludelist
(); }
158 # Get a list of non-deleted changed files.
159 open (FILES
, "git diff-index --cached --diff-filter=AM --name-only $h |") || die "Cannot run git diff.";
160 while (my $filename = <FILES
>)
163 if ($filename =~ /\.($src)$/ and !exists($excluded_list_names->{$filename}))
165 if (!defined($clang_format))
167 my $version = ClangFormat
::get_wanted_version
();
168 my $opt_lo = ClangFormat
::get_own_directory
();
170 print("\nWARNING: Commit touches new (non-excluded) files, but no clang-format"
172 print(" found (via CLANG_FORMAT or PATH env vars, or in ${opt_lo}).\n\n");
174 my $platform = "linux64";
175 my $download = "wget";
178 $platform = "win.exe";
180 elsif ($^O
eq "darwin")
183 $download = "curl -O";
186 print("To get a suitable binary, please do:\n\n");
187 print("mkdir -p $opt_lo\n");
188 print("cd $opt_lo\n");
189 print("$download https://dev-www.libreoffice.org/bin/clang-format-$version-$platform\n");
190 print("cp clang-format-$version-$platform clang-format\n");
191 print("chmod +x clang-format\n\n");
193 print("(Or read solenv/clang-format/README on how to build it yourself.\n");
196 if (!ClangFormat
::check_style
($clang_format, $filename))
198 push @bad_names, $filename;
204 if (scalar @bad_names)
206 my $autostyle = `git config libreoffice.autostyle`;
208 if ($autostyle ne "true")
210 print("\nThe above differences were found between the code to commit \n");
211 print("and the clang-format rules. You can apply these changes with:\n");
212 print("\n$clang_format -i " . join(" ", @bad_names) . "\n\n");
213 print("Aborting commit. Apply changes and commit again or skip checking\n");
214 print("with --no-verify (not recommended).\n");
219 # 'git config libreoffice.autostyle true' was invoked to run
220 # clang-format automatically.
221 print("\nThe above differences were found between the code to commit \n");
222 print("and the clang-format rules. Fixing these now automatically.\n");
223 print("Running '$clang_format -i " . join(" ", @bad_names) . "' for you...\n");
224 system("$clang_format -i " . join(" ", @bad_names));
225 # TODO this stages all local modifications, staging originally
227 system("git add " . join(" ", @bad_names));
233 sub check_submodules
($)
237 my $toplevel = `git rev-parse --show-toplevel`;
240 # trick to get a list of submodules - directly read from the .gitmodules
241 open(SUBMODULES
, "git config --file '$toplevel'/.gitmodules --get-regexp path | awk '{ print \$2 }' |" ) || die "Cannot run git config on the .gitmodules.";
246 my $ignore = `git config submodule.$_.ignore`;
248 if ($ignore eq 'all')
251 Error: Your git configuration has submodule.$_.ignore set to 'all'.
253 This is dangerous and can lead to accidentally pushing unwanted changes to
256 To fix it, please do:
258 git config --unset submodule.$_.ignore
264 my $diff = `git diff --cached --name-only -z $h -- $_`;
269 Error: You are trying to commit changes to submodule $_ from the main repo.
271 Please do not do that, commit only to the submodule, the git hook on the
272 server will make sure the appropriate change is mirrored in the main repo.
274 To remove the change, you can do:
276 git submodule update $_
278 If it fails with 'error: Server does not allow request for unadvertised object',
282 git submodule update $_
292 # Initial commit: diff against an empty tree object
293 my $against="4b825dc642cb6eb9a060e54bf8d69288fbee4904";
294 if ( system( "git rev-parse --verify HEAD >/dev/null 2>&1" ) == 0 )
299 # If you want to allow non-ascii filenames set this variable to true.
300 my $allownonascii=`git config hooks.allownonascii`;
301 chomp $allownonascii;
303 # Cross platform projects tend to avoid non-ascii filenames; prevent
304 # them from being added to the repository. We exploit the fact that the
305 # printable range starts at the space character and ends with tilde.
306 if ( $allownonascii ne "true" &&
307 # Note that the use of brackets around a tr range is ok here, (it's
308 # even required, for portability to Solaris 10's /usr/bin/tr), since
309 # the square bracket bytes happen to fall in the designated range.
310 `git diff --cached --name-only --diff-filter=A -z $against | \
311 LC_ALL=C tr -d '[ -~]\\0'` ne "" )
314 Error: Attempt to add a non-ascii file name.
316 This can cause problems if you want to work
317 with people on other platforms.
319 To be portable it is advisable to rename the file ...
321 If you know what you are doing you can disable this
324 git config hooks.allownonascii true
331 open( FILES
, "git diff --cached --name-only --diff-filter=A -z $against |" ) || die "Cannot run git diff-index.";
334 if (/\.ui$/) # .ui files can get large
342 my $size = `git cat-file -s :$_`;
343 # For now let's say large is 500KB
345 if ($size > $limit * 1024)
347 print "Error: Attempt to add a large file: $_, pleasy try to fit into $limit KB.\n";
352 # fix whitespace in code
353 check_whitespaces
( $against);
356 check_style
($against);
358 # catch missing author info
361 # catch commits to the submodules
362 check_submodules
($against);
366 # vi:set shiftwidth=4 expandtab: