spacecheck.pl 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153
  1. #!/usr/bin/env perl
  2. #***************************************************************************
  3. # _ _ ____ _
  4. # Project ___| | | | _ \| |
  5. # / __| | | | |_) | |
  6. # | (__| |_| | _ <| |___
  7. # \___|\___/|_| \_\_____|
  8. #
  9. # Copyright (C) Viktor Szakats
  10. #
  11. # This software is licensed as described in the file COPYING, which
  12. # you should have received as part of this distribution. The terms
  13. # are also available at https://curl.se/docs/copyright.html.
  14. #
  15. # You may opt to use, copy, modify, merge, publish, distribute and/or sell
  16. # copies of the Software, and permit persons to whom the Software is
  17. # furnished to do so, under the terms of the COPYING file.
  18. #
  19. # This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
  20. # KIND, either express or implied.
  21. #
  22. # SPDX-License-Identifier: curl
  23. #
  24. ###########################################################################
  25. use strict;
  26. use warnings;
  27. my @tabs = (
  28. "^m4/zz40-xc-ovr.m4",
  29. "Makefile\\.[a-z]+\$",
  30. "/mkfile",
  31. "\\.(bat|sln|vc)\$",
  32. "^tests/certs/.+\\.der\$",
  33. "^tests/data/test",
  34. );
  35. my @mixed_eol = (
  36. "^tests/certs/.+\\.(crt|der)\$",
  37. "^tests/certs/Server-localhost0h-sv.pem",
  38. "^tests/data/test",
  39. );
  40. my @need_crlf = (
  41. "\\.(bat|sln)\$",
  42. "^winbuild/.+\\.md\$",
  43. );
  44. my @space_at_eol = (
  45. "^tests/.+\\.(cacert|crt|pem)\$",
  46. "^tests/data/test",
  47. );
  48. my @eol_at_eof = (
  49. "^tests/certs/.+\\.der\$",
  50. );
  51. sub fn_match {
  52. my ($filename, @masklist) = @_;
  53. foreach my $mask (@masklist) {
  54. if ($filename =~ $mask) {
  55. return 1;
  56. }
  57. }
  58. return 0;
  59. }
  60. sub eol_detect {
  61. my ($content) = @_;
  62. my $cr = () = $content =~ /\r/g;
  63. my $lf = () = $content =~ /\n/g;
  64. if ($cr > 0 && $lf == 0) {
  65. return "cr"
  66. }
  67. elsif ($cr == 0 && $lf > 0) {
  68. return "lf"
  69. }
  70. elsif ($cr == 0 && $lf == 0) {
  71. return "bin"
  72. }
  73. elsif ($cr == $lf) {
  74. return "crlf"
  75. }
  76. return ""
  77. }
  78. my $issues = 0;
  79. open my $git_ls_files, '-|', 'git ls-files' or die "Failed running git ls-files: $!";
  80. while (my $filename = <$git_ls_files>) {
  81. chomp $filename;
  82. open my $fh, '<', $filename or die "Cannot open '$filename': $!";
  83. my $content = do { local $/; <$fh> };
  84. close $fh;
  85. my @err = ();
  86. if (!fn_match($filename, @tabs) &&
  87. $content =~ /\t/) {
  88. push @err, "content: has tab";
  89. }
  90. my $eol = eol_detect($content);
  91. if ($eol eq "" &&
  92. !fn_match($filename, @mixed_eol)) {
  93. push @err, "content: has mixed EOL types";
  94. }
  95. if ($eol ne "crlf" &&
  96. fn_match($filename, @need_crlf)) {
  97. push @err, "content: must use CRLF EOL for this file type";
  98. }
  99. if ($eol ne "lf" && $content ne "" &&
  100. !fn_match($filename, @need_crlf) &&
  101. !fn_match($filename, @mixed_eol)) {
  102. push @err, "content: must use LF EOL for this file type";
  103. }
  104. if (!fn_match($filename, @space_at_eol) &&
  105. $content =~ /[ \t]\n/) {
  106. push @err, "content: has line-ending whitespace";
  107. }
  108. if ($content ne "" &&
  109. !fn_match($filename, @eol_at_eof) &&
  110. $content !~ /\n\z/) {
  111. push @err, "content: has no EOL at EOF";
  112. }
  113. if ($content =~ /\n\n\z/ ||
  114. $content =~ /\r\n\r\n\z/) {
  115. push @err, "content: has multiple EOL at EOF";
  116. }
  117. if (@err) {
  118. $issues++;
  119. foreach my $err (@err) {
  120. print "$filename: $err\n";
  121. }
  122. }
  123. }
  124. close $git_ls_files;
  125. if ($issues) {
  126. exit 1;
  127. }