Bläddra i källkod

Add config linting utility for CI

Martijn Braam 8 månader sedan
förälder
incheckning
2b9d9cf71b
7 ändrade filer med 119 tillägg och 14 borttagningar
  1. 15 2
      .gitlab-ci.yml
  2. 4 0
      CMakeLists.txt
  3. 22 0
      configtest.sh
  4. 3 0
      include/libmegapixels.h
  5. 5 0
      meson.build
  6. 35 12
      src/parse.c
  7. 35 0
      util/configlint.c

+ 15 - 2
.gitlab-ci.yml

@@ -1,5 +1,5 @@
 build:
-  stage: test
+  stage: build
   image: alpine:edge
   before_script:
     - apk add --no-cache build-base meson samurai linux-headers libconfig-dev scdoc
@@ -7,9 +7,12 @@ build:
     - meson build --buildtype release --werror
     - ninja -C build
     - cd build && meson test --no-rebuild
+  artifacts:
+    paths:
+      - build
 
 docs:
-  stage: test
+  stage: build
   image: alpine:edge
   before_script:
     - apk add --no-cache python3 py3-sphinx make
@@ -17,6 +20,16 @@ docs:
     - cd docs
     - make html
 
+lint:
+  stage: test
+  dependencies:
+    - build
+  image: alpine:edge
+  before_script:
+    - apk add --no-cache libconfig bash
+  script:
+    - bash ./configtest.sh
+
 pages:
   stage: deploy
   image: alpine:edge

+ 4 - 0
CMakeLists.txt

@@ -28,6 +28,10 @@ add_executable(sensorprofile util/sensorprofile.c)
 target_include_directories(sensorprofile PUBLIC include)
 target_link_libraries(sensorprofile PUBLIC megapixels)
 
+add_executable(configlint util/configlint.c)
+target_include_directories(configlint PUBLIC include)
+target_link_libraries(configlint PUBLIC megapixels)
+
 add_compile_definitions(SYSCONFDIR="/etc")
 add_compile_definitions(DATADIR="/usr/share")
 

+ 22 - 0
configtest.sh

@@ -0,0 +1,22 @@
+#!/bin/bash
+
+RED='\033[0;31m'
+BOLDRED='\033[1;31m'
+GREEN='\033[0;32m'
+CLEAR='\033[0m'
+
+ret=0
+for cfg in $(find config/ -type f -iname *.conf)
+do
+  printf "%s: " $cfg
+  errors=$(./build/megapixels-configlint "$cfg" 2>&1)
+  if [ -z "$errors" ] ; then
+    echo -e "${GREEN}PASS${CLEAR}"
+  else
+    ret=1
+    echo -e "${BOLDRED}FAIL${CLEAR}"
+    echo -e "${RED}$errors${CLEAR}"
+    echo ""
+  fi
+done
+exit $ret

+ 3 - 0
include/libmegapixels.h

@@ -129,6 +129,9 @@ libmegapixels_loglevel(int loglevel);
 EXPORT int
 libmegapixels_load_file(libmegapixels_devconfig *config, const char *file);
 
+EXPORT int
+libmegapixels_load_file_lint(libmegapixels_devconfig *config, const char *file, int linting);
+
 EXPORT int
 libmegapixels_load_uvc(libmegapixels_devconfig *config);
 

+ 5 - 0
meson.build

@@ -64,6 +64,11 @@ executable('megapixels-getframe', 'util/getframe.c',
     include_directories: inc,
     install: true,
     )
+executable('megapixels-configlint', 'util/configlint.c',
+    link_with: libmegapixels,
+    include_directories: inc,
+    install: true,
+    )
 
 cc = meson.get_compiler('c')
 m_dep = cc.find_library('m', required : false)

+ 35 - 12
src/parse.c

@@ -177,7 +177,7 @@ find_media_node(libmegapixels_camera *camera, const char *media_name, const char
 }
 
 int
-load_camera(libmegapixels_devconfig *config, config_t *cfg, const char *name)
+load_camera(libmegapixels_devconfig *config, config_t *cfg, const char *name, int lint)
 {
 	const char *sensor_driver, *bridge_driver;
 	config_setting_t *root = config_lookup(cfg, name);
@@ -196,11 +196,14 @@ load_camera(libmegapixels_devconfig *config, config_t *cfg, const char *name)
 	camera->media_fd = 0;
 	camera->video_fd = 0;
 
-	int res = find_media_node(camera, bridge_driver, sensor_driver);
-	if (res < 0) {
-		log_debug("  Could not find media node with this sensor\n");
-		free(camera);
-		return -1;
+	// Don't access hardware in linting mode
+	if (lint == 0) {
+		int res = find_media_node(camera, bridge_driver, sensor_driver);
+		if (res < 0) {
+			log_debug("  Could not find media node with this sensor\n");
+			free(camera);
+			return -1;
+		}
 	}
 
 	camera->name = strdup(name);
@@ -216,6 +219,11 @@ load_camera(libmegapixels_devconfig *config, config_t *cfg, const char *name)
 	config_setting_t *modes = config_setting_lookup(root, "Modes");
 	config_setting_t *mode;
 
+	if (modes == NULL) {
+		log_error("Sensor '%s' does not define any modes\n", camera->name);
+		return -1;
+	}
+
 	int num_modes = config_setting_length(modes);
 	camera->modes = malloc(num_modes * sizeof(libmegapixels_mode *));
 	camera->num_modes = num_modes;
@@ -381,11 +389,22 @@ load_camera(libmegapixels_devconfig *config, config_t *cfg, const char *name)
 		n++;
 	}
 
+	if (n == 0) {
+		log_debug("No modes defined for sensor '%s'\n", camera->name);
+		return -1;
+	}
+
 	return 0;
 }
 
 int
 libmegapixels_load_file(libmegapixels_devconfig *config, const char *file)
+{
+	return libmegapixels_load_file_lint(config, file, 0);
+}
+
+int
+libmegapixels_load_file_lint(libmegapixels_devconfig *config, const char *file, int linting)
 {
 	if (config->loaded_config) {
 		log_error("Config already loaded\n");
@@ -403,9 +422,13 @@ libmegapixels_load_file(libmegapixels_devconfig *config, const char *file)
 
 	config_init(&cfg);
 	if (!config_read_file(&cfg, file)) {
-		fprintf(stderr, "Could not read %s\n", file);
-		fprintf(stderr, "%s:%d - %s\n",
-			config_error_file(&cfg), config_error_line(&cfg), config_error_text(&cfg));
+		if (config_error_type(&cfg) == CONFIG_ERR_FILE_IO) {
+			fprintf(stderr, "Could not read %s: %s\n", file, config_error_text(&cfg));
+		} else {
+			fprintf(stderr, "Could not read %s:\n", file);
+			fprintf(stderr, "\t%s:%d - %s\n",
+				config_error_file(&cfg), config_error_line(&cfg), config_error_text(&cfg));
+		}
 		config_destroy(&cfg);
 		return 0;
 	}
@@ -413,11 +436,11 @@ libmegapixels_load_file(libmegapixels_devconfig *config, const char *file)
 	int version = 0;
 	if (config_lookup_int(&cfg, "Version", &version)) {
 		if (version != 1) {
-			fprintf(stderr, "Invalid version %d\n", version);
+			fprintf(stderr, "Could not load '%s': Invalid version %d\n", file, version);
 			return 0;
 		}
 	} else {
-		fprintf(stderr, "Missing version\n");
+		fprintf(stderr, "Could not load '%s': Missing version\n", file);
 		return 0;
 	}
 
@@ -446,7 +469,7 @@ libmegapixels_load_file(libmegapixels_devconfig *config, const char *file)
 		if (strcmp(member->name, "Model") == 0) {
 			continue;
 		}
-		load_camera(config, &cfg, member->name);
+		load_camera(config, &cfg, member->name, linting);
 	}
 
 	return 1;

+ 35 - 0
util/configlint.c

@@ -0,0 +1,35 @@
+#include <libmegapixels.h>
+#include <stdio.h>
+#include <stdbool.h>
+
+int
+main(int argc, char *argv[])
+{
+	if (argc != 2) {
+		fprintf(stderr, "Usage: %s <configfile>\n", argv[0]);
+		return 1;
+	}
+
+	libmegapixels_devconfig *config = {0};
+	libmegapixels_init(&config);
+	if (!libmegapixels_load_file_lint(config, argv[1], 1)) {
+		return 1;
+	}
+
+	if (config->count == 0) {
+		fprintf(stderr, "Config file does not define any cameras\n");
+		return 1;
+	}
+
+	bool faulty = false;
+	for (int i = 0; i < config->count; i++) {
+		if (config->cameras[i]->num_modes == 0) {
+			fprintf(stderr, "No modes are defined for sensor '%s'\n", config->cameras[i]->name);
+			faulty = true;
+		}
+	}
+	if (faulty) {
+		return 1;
+	}
+	return 0;
+}