# HG changeset patch
# User Georges Racinet <georges.racinet@octobus.net>
# Date 1680451661 -7200
#      Sun Apr 02 18:07:41 2023 +0200
# Node ID f4e5c429582de9e3bde3f2e3b218a2f9b21b9a1d
# Parent  555e544f724443f5e405c2de74b4edc4f1250204
CI/CD: Rust lints (rustfmt, clippy and line widths)

As we don't want to resort ot unstable features of rustfmt, we
wrote a simple checker in Python.

Also we have to run after the tests, because
we need the protocol source files (e.g., `gitaly.rs` to be present).
Without them, `cargo fmt` fails at the `use` statement.

diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -70,6 +70,7 @@
   script:
     - ci/prepare-rhgitaly
     - cargo test --manifest-path rust/Cargo.toml
+    - rust/lint
   artifacts:
     expire_in: 1d
     paths:
diff --git a/rust/check-line-width b/rust/check-line-width
new file mode 100755
--- /dev/null
+++ b/rust/check-line-width
@@ -0,0 +1,48 @@
+#!/usr/bin/env python3
+"""Check line length for all Rust source files in rhgitaly/
+
+Excludes any directory named `generated`
+"""
+import argparse
+import os
+import sys
+
+LINE_MAX_LENGTH = 100
+BASE_DIR = os.path.dirname(__file__)
+
+
+def check_file(path):
+    res = True
+    with open(path, 'r') as fobj:
+        for i, line in enumerate(fobj):
+            if line[-1] == '\n':
+                line = line[:-1]
+            if len(line) > LINE_MAX_LENGTH:
+                print("File %s: line %d is over %d long." % (
+                    path, i+1, LINE_MAX_LENGTH))
+                res = False
+    return res
+
+
+parser = argparse.ArgumentParser(description=__doc__)
+parser.add_argument('path', help="The directory to check, relative to this "
+                    "script parent directory")
+
+cl_args = parser.parse_args()
+
+target = os.path.join(BASE_DIR, cl_args.path)
+
+ok = True
+for dirpath, dirnames, filenames in os.walk(target):
+    try:
+        # allowed with topdown=True (the default)
+        dirnames.remove('generated')
+    except ValueError:  # was not present
+        pass
+    for fname in filenames:
+        if fname.endswith('.rs') and not fname.startswith('.#'):
+            fpath = os.path.join(dirpath, fname)
+            ok = ok and check_file(fpath)
+
+if not ok:
+    sys.exit(1)
diff --git a/rust/lint b/rust/lint
new file mode 100755
--- /dev/null
+++ b/rust/lint
@@ -0,0 +1,14 @@
+#!/bin/sh
+
+set -eu
+
+cd `dirname $0`
+echo "Checking line widths"
+./check-line-width rhgitaly
+
+echo "Checking Rust format"
+cd rhgitaly
+cargo fmt --check
+
+echo "Running Clippy"
+cargo clippy -- -Dwarnings --no-deps