[{"id":35940,"web_url":"https://patchwork.libcamera.org/comment/35940/","msgid":"<20250921050951.GI10985@pendragon.ideasonboard.com>","date":"2025-09-21T05:09:51","subject":"Re: [PATCH v18 11/12] config: Make configuration file locations\n\tconfigurable","submitter":{"id":2,"url":"https://patchwork.libcamera.org/api/people/2/","name":"Laurent Pinchart","email":"laurent.pinchart@ideasonboard.com"},"content":"Hi Milan,\n\nThank you for the patch.\n\nOn Fri, Sep 12, 2025 at 04:29:13PM +0200, Milan Zamazal wrote:\n> To support easy switching of configurations, let's introduce\n> LIBCAMERA_CONFIG_DIR and LIBCAMERA_CONFIG_NAME environment variables.\n> \n> LIBCAMERA_CONFIG_DIR environment variable specifies a directory or a\n> list of directories separated by colons where to look for the libcamera\n> configuration file before trying the standard locations.  This override\n> can be useful in a meson devenv.\n> \n> LIBCAMERA_CONFIG_NAME\n> - specifies the path of the configuration file to load if it is an\n>   absolute path (useful to quickly try some configuration); or\n> - prevents any configuration file from loading if it is defined and\n>   empty (useful to disable all configuration files); or\n> - specifies the path of the configuration file to load, relative to\n>   the configuration directories (useful to quickly select between\n>   different configurations).\n\nThis last part I'm not thrilled about. Do we really need such a complex\nscheme ? Wouldn't a single variable that overrides the configuration\nfile lookup be enough ?\n\nI'll merge the rest of the series already without this patch while we\ndiscuss the issue.\n\n> If a configuration file specified by those environment variables doesn't\n> exist, no configuration file is loaded.\n> \n> Reviewed-by: Paul Elder <paul.elder@ideasonboard.com>\n> Signed-off-by: Milan Zamazal <mzamazal@redhat.com>\n> ---\n>  Documentation/runtime_configuration.rst | 13 +++++++\n>  src/libcamera/global_configuration.cpp  | 50 +++++++++++++++++--------\n>  2 files changed, 47 insertions(+), 16 deletions(-)\n> \n> diff --git a/Documentation/runtime_configuration.rst b/Documentation/runtime_configuration.rst\n> index 702139544..5307f3645 100644\n> --- a/Documentation/runtime_configuration.rst\n> +++ b/Documentation/runtime_configuration.rst\n> @@ -19,6 +19,19 @@ order:\n>  - LIBCAMERA_SYSCONF_DIR/configuration.yaml\n>  - LIBCAMERA_DATA_DIR/libcamera/configuration.yaml\n>  \n> +If LIBCAMERA_CONFIG_DIR environment variable is non-empty then it\n> +specifies additional directories where to look for the configuration\n> +file, before looking at the standard locations. It can be a single\n> +directory or multiple directories separated by colons.\n> +\n> +The default name of the configuration file, configuration.yaml, can be\n> +overridden in LIBCAMERA_CONFIG_NAME environment variable. The variable\n> +can specify just an alternative configuration file name to be looked up\n> +in the locations above, or a whole absolute path. If an absolute path is\n> +specified then it is the only location that is used; if the given file\n> +doesn't exist then no configuration file is read. If the variable is\n> +defined but empty, no configuration is loaded.\n> +\n>  The first configuration file found wins, configuration files in other\n>  locations are ignored.\n>  \n> diff --git a/src/libcamera/global_configuration.cpp b/src/libcamera/global_configuration.cpp\n> index 592edcf30..8c2670e03 100644\n> --- a/src/libcamera/global_configuration.cpp\n> +++ b/src/libcamera/global_configuration.cpp\n> @@ -23,13 +23,6 @@\n>  \n>  namespace libcamera {\n>  \n> -namespace {\n> -const std::vector<std::filesystem::path> globalConfigurationFiles = {\n> -\tstd::filesystem::path(LIBCAMERA_SYSCONF_DIR) / \"configuration.yaml\",\n> -\tstd::filesystem::path(LIBCAMERA_DATA_DIR) / \"configuration.yaml\",\n> -};\n> -}\n> -\n>  LOG_DEFINE_CATEGORY(Configuration)\n>  \n>  /**\n> @@ -80,6 +73,33 @@ bool GlobalConfiguration::loadFile(const std::filesystem::path &fileName)\n>  \n>  void GlobalConfiguration::load()\n>  {\n> +\tconst char *libcameraConfigName =\n> +\t\tutils::secure_getenv(\"LIBCAMERA_CONFIG_NAME\");\n> +\tif (libcameraConfigName && libcameraConfigName[0] == '\\0')\n> +\t\treturn;\n> +\tif (!libcameraConfigName)\n> +\t\tlibcameraConfigName = \"\";\n> +\n> +\tstd::filesystem::path configName(libcameraConfigName);\n> +\n> +\tif (configName.is_absolute()) {\n> +\t\tloadFile(configName);\n> +\t\treturn;\n> +\t}\n> +\n> +\tif (configName.empty())\n> +\t\tconfigName = std::filesystem::path(\"configuration.yaml\");\n> +\n> +\tstd::vector<std::filesystem::path> configurationDirectories;\n> +\n> +\tconst char *configDir = utils::secure_getenv(\"LIBCAMERA_CONFIG_DIR\");\n> +\tif (configDir) {\n> +\t\tfor (auto const &path : utils::split(configDir, \":\")) {\n> +\t\t\tif (!path.empty())\n> +\t\t\t\tconfigurationDirectories.push_back(path);\n> +\t\t}\n> +\t}\n> +\n>  \tstd::filesystem::path userConfigurationDirectory;\n>  \tconst char *xdgConfigHome = utils::secure_getenv(\"XDG_CONFIG_HOME\");\n>  \tif (xdgConfigHome) {\n> @@ -90,18 +110,16 @@ void GlobalConfiguration::load()\n>  \t\t\tuserConfigurationDirectory =\n>  \t\t\t\tstd::filesystem::path(home) / \".config\";\n>  \t}\n> +\tif (!userConfigurationDirectory.empty())\n> +\t\tconfigurationDirectories.push_back(\n> +\t\t\tuserConfigurationDirectory / \"libcamera\");\n>  \n> -\tif (!userConfigurationDirectory.empty()) {\n> -\t\tstd::filesystem::path user_configuration_file =\n> -\t\t\tuserConfigurationDirectory / \"libcamera\" / \"configuration.yaml\";\n> -\t\tif (loadFile(user_configuration_file))\n> -\t\t\treturn;\n> -\t}\n> +\tconfigurationDirectories.push_back(LIBCAMERA_SYSCONF_DIR);\n> +\tconfigurationDirectories.push_back(LIBCAMERA_DATA_DIR);\n>  \n> -\tfor (const auto &path : globalConfigurationFiles) {\n> -\t\tif (loadFile(path))\n> +\tfor (const auto &path : configurationDirectories)\n> +\t\tif (loadFile(path / configName))\n>  \t\t\treturn;\n> -\t}\n>  }\n>  \n>  /**","headers":{"Return-Path":"<libcamera-devel-bounces@lists.libcamera.org>","X-Original-To":"parsemail@patchwork.libcamera.org","Delivered-To":"parsemail@patchwork.libcamera.org","Received":["from lancelot.ideasonboard.com (lancelot.ideasonboard.com\n\t[92.243.16.209])\n\tby patchwork.libcamera.org (Postfix) with ESMTPS id E8D12BE173\n\tfor <parsemail@patchwork.libcamera.org>;\n\tSun, 21 Sep 2025 05:10:26 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id B578F6B59C;\n\tSun, 21 Sep 2025 07:10:25 +0200 (CEST)","from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[213.167.242.64])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id D313C62C35\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tSun, 21 Sep 2025 07:10:23 +0200 (CEST)","from pendragon.ideasonboard.com (81-175-209-231.bb.dnainternet.fi\n\t[81.175.209.231])\n\tby perceval.ideasonboard.com (Postfix) with UTF8SMTPSA id DDE8163F;\n\tSun, 21 Sep 2025 07:09:01 +0200 (CEST)"],"Authentication-Results":"lancelot.ideasonboard.com; dkim=pass (1024-bit key;\n\tunprotected) header.d=ideasonboard.com header.i=@ideasonboard.com\n\theader.b=\"l1UVFbOA\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1758431342;\n\tbh=h4leuRQXUJyVbhiQaUBiLTgwEniUtPPzw/4gvMiHfzk=;\n\th=Date:From:To:Cc:Subject:References:In-Reply-To:From;\n\tb=l1UVFbOAI17+c2zdtmrqhZykgf1uxL5LU3MN/yGE22+6j13RS6jyJzgJ5sa6vmdKl\n\tZD9p95Jcms7IHX24EBwmULIzpsNXS5to2xarNbDJJong2AdgyPhErYzMcIx05p50qe\n\tmykVoc2lFa07828yTJXIjLTzZ+A7l0B9QpVrAOvo=","Date":"Sun, 21 Sep 2025 08:09:51 +0300","From":"Laurent Pinchart <laurent.pinchart@ideasonboard.com>","To":"Milan Zamazal <mzamazal@redhat.com>","Cc":"libcamera-devel@lists.libcamera.org, Kieran Bingham\n\t<kieran.bingham@ideasonboard.com>, =?utf-8?q?Barnab=C3=A1s_P=C5=91cze?=\n\t<barnabas.pocze@ideasonboard.com>, Paul Elder\n\t<paul.elder@ideasonboard.com>","Subject":"Re: [PATCH v18 11/12] config: Make configuration file locations\n\tconfigurable","Message-ID":"<20250921050951.GI10985@pendragon.ideasonboard.com>","References":"<20250912142915.53949-1-mzamazal@redhat.com>\n\t<20250912142915.53949-13-mzamazal@redhat.com>","MIME-Version":"1.0","Content-Type":"text/plain; charset=utf-8","Content-Disposition":"inline","In-Reply-To":"<20250912142915.53949-13-mzamazal@redhat.com>","X-BeenThere":"libcamera-devel@lists.libcamera.org","X-Mailman-Version":"2.1.29","Precedence":"list","List-Id":"<libcamera-devel.lists.libcamera.org>","List-Unsubscribe":"<https://lists.libcamera.org/options/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=unsubscribe>","List-Archive":"<https://lists.libcamera.org/pipermail/libcamera-devel/>","List-Post":"<mailto:libcamera-devel@lists.libcamera.org>","List-Help":"<mailto:libcamera-devel-request@lists.libcamera.org?subject=help>","List-Subscribe":"<https://lists.libcamera.org/listinfo/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=subscribe>","Errors-To":"libcamera-devel-bounces@lists.libcamera.org","Sender":"\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>"}},{"id":35944,"web_url":"https://patchwork.libcamera.org/comment/35944/","msgid":"<30e10fc5-3a6c-4ca8-b8ed-09d115d38fb7@ideasonboard.com>","date":"2025-09-22T07:52:53","subject":"Re: [PATCH v18 11/12] config: Make configuration file locations\n\tconfigurable","submitter":{"id":216,"url":"https://patchwork.libcamera.org/api/people/216/","name":"Barnabás Pőcze","email":"barnabas.pocze@ideasonboard.com"},"content":"Hi\n\n2025. 09. 21. 7:09 keltezéssel, Laurent Pinchart írta:\n> Hi Milan,\n> \n> Thank you for the patch.\n> \n> On Fri, Sep 12, 2025 at 04:29:13PM +0200, Milan Zamazal wrote:\n>> To support easy switching of configurations, let's introduce\n>> LIBCAMERA_CONFIG_DIR and LIBCAMERA_CONFIG_NAME environment variables.\n>>\n>> LIBCAMERA_CONFIG_DIR environment variable specifies a directory or a\n>> list of directories separated by colons where to look for the libcamera\n>> configuration file before trying the standard locations.  This override\n>> can be useful in a meson devenv.\n>>\n>> LIBCAMERA_CONFIG_NAME\n>> - specifies the path of the configuration file to load if it is an\n>>    absolute path (useful to quickly try some configuration); or\n>> - prevents any configuration file from loading if it is defined and\n>>    empty (useful to disable all configuration files); or\n>> - specifies the path of the configuration file to load, relative to\n>>    the configuration directories (useful to quickly select between\n>>    different configurations).\n> \n> This last part I'm not thrilled about. Do we really need such a complex\n> scheme ? Wouldn't a single variable that overrides the configuration\n> file lookup be enough ?\n\nSome of these were my suggestions, so naturally this is my preferred behaviour,\nhow would that single variable look like? Are there are any concrete concerns?\n\nI feel like this system is relatively flexible and even if it is more complex,\nthat complexity does not really affect anything else.\n\nI believe the natural progression is to support configuration file merging, i.e.\nhaving fragments in `<main-config-name>.d/` next to the selected main configuration\nfile and in higher-priority directories, which would allow overwriting single things\n(on a per-user, per-system level) without having to copy/paste the whole thing. In\nthis case having the separation of the configuration directories and the name is\nsomewhat needed.\n\n\nRegards,\nBarnabás Pőcze\n\n\n> \n> I'll merge the rest of the series already without this patch while we\n> discuss the issue.\n> \n>> If a configuration file specified by those environment variables doesn't\n>> exist, no configuration file is loaded.\n>>\n>> Reviewed-by: Paul Elder <paul.elder@ideasonboard.com>\n>> Signed-off-by: Milan Zamazal <mzamazal@redhat.com>\n>> ---\n>>   Documentation/runtime_configuration.rst | 13 +++++++\n>>   src/libcamera/global_configuration.cpp  | 50 +++++++++++++++++--------\n>>   2 files changed, 47 insertions(+), 16 deletions(-)\n>>\n>> diff --git a/Documentation/runtime_configuration.rst b/Documentation/runtime_configuration.rst\n>> index 702139544..5307f3645 100644\n>> --- a/Documentation/runtime_configuration.rst\n>> +++ b/Documentation/runtime_configuration.rst\n>> @@ -19,6 +19,19 @@ order:\n>>   - LIBCAMERA_SYSCONF_DIR/configuration.yaml\n>>   - LIBCAMERA_DATA_DIR/libcamera/configuration.yaml\n>>   \n>> +If LIBCAMERA_CONFIG_DIR environment variable is non-empty then it\n>> +specifies additional directories where to look for the configuration\n>> +file, before looking at the standard locations. It can be a single\n>> +directory or multiple directories separated by colons.\n>> +\n>> +The default name of the configuration file, configuration.yaml, can be\n>> +overridden in LIBCAMERA_CONFIG_NAME environment variable. The variable\n>> +can specify just an alternative configuration file name to be looked up\n>> +in the locations above, or a whole absolute path. If an absolute path is\n>> +specified then it is the only location that is used; if the given file\n>> +doesn't exist then no configuration file is read. If the variable is\n>> +defined but empty, no configuration is loaded.\n>> +\n>>   The first configuration file found wins, configuration files in other\n>>   locations are ignored.\n>>   \n>> diff --git a/src/libcamera/global_configuration.cpp b/src/libcamera/global_configuration.cpp\n>> index 592edcf30..8c2670e03 100644\n>> --- a/src/libcamera/global_configuration.cpp\n>> +++ b/src/libcamera/global_configuration.cpp\n>> @@ -23,13 +23,6 @@\n>>   \n>>   namespace libcamera {\n>>   \n>> -namespace {\n>> -const std::vector<std::filesystem::path> globalConfigurationFiles = {\n>> -\tstd::filesystem::path(LIBCAMERA_SYSCONF_DIR) / \"configuration.yaml\",\n>> -\tstd::filesystem::path(LIBCAMERA_DATA_DIR) / \"configuration.yaml\",\n>> -};\n>> -}\n>> -\n>>   LOG_DEFINE_CATEGORY(Configuration)\n>>   \n>>   /**\n>> @@ -80,6 +73,33 @@ bool GlobalConfiguration::loadFile(const std::filesystem::path &fileName)\n>>   \n>>   void GlobalConfiguration::load()\n>>   {\n>> +\tconst char *libcameraConfigName =\n>> +\t\tutils::secure_getenv(\"LIBCAMERA_CONFIG_NAME\");\n>> +\tif (libcameraConfigName && libcameraConfigName[0] == '\\0')\n>> +\t\treturn;\n>> +\tif (!libcameraConfigName)\n>> +\t\tlibcameraConfigName = \"\";\n>> +\n>> +\tstd::filesystem::path configName(libcameraConfigName);\n>> +\n>> +\tif (configName.is_absolute()) {\n>> +\t\tloadFile(configName);\n>> +\t\treturn;\n>> +\t}\n>> +\n>> +\tif (configName.empty())\n>> +\t\tconfigName = std::filesystem::path(\"configuration.yaml\");\n>> +\n>> +\tstd::vector<std::filesystem::path> configurationDirectories;\n>> +\n>> +\tconst char *configDir = utils::secure_getenv(\"LIBCAMERA_CONFIG_DIR\");\n>> +\tif (configDir) {\n>> +\t\tfor (auto const &path : utils::split(configDir, \":\")) {\n>> +\t\t\tif (!path.empty())\n>> +\t\t\t\tconfigurationDirectories.push_back(path);\n>> +\t\t}\n>> +\t}\n>> +\n>>   \tstd::filesystem::path userConfigurationDirectory;\n>>   \tconst char *xdgConfigHome = utils::secure_getenv(\"XDG_CONFIG_HOME\");\n>>   \tif (xdgConfigHome) {\n>> @@ -90,18 +110,16 @@ void GlobalConfiguration::load()\n>>   \t\t\tuserConfigurationDirectory =\n>>   \t\t\t\tstd::filesystem::path(home) / \".config\";\n>>   \t}\n>> +\tif (!userConfigurationDirectory.empty())\n>> +\t\tconfigurationDirectories.push_back(\n>> +\t\t\tuserConfigurationDirectory / \"libcamera\");\n>>   \n>> -\tif (!userConfigurationDirectory.empty()) {\n>> -\t\tstd::filesystem::path user_configuration_file =\n>> -\t\t\tuserConfigurationDirectory / \"libcamera\" / \"configuration.yaml\";\n>> -\t\tif (loadFile(user_configuration_file))\n>> -\t\t\treturn;\n>> -\t}\n>> +\tconfigurationDirectories.push_back(LIBCAMERA_SYSCONF_DIR);\n>> +\tconfigurationDirectories.push_back(LIBCAMERA_DATA_DIR);\n>>   \n>> -\tfor (const auto &path : globalConfigurationFiles) {\n>> -\t\tif (loadFile(path))\n>> +\tfor (const auto &path : configurationDirectories)\n>> +\t\tif (loadFile(path / configName))\n>>   \t\t\treturn;\n>> -\t}\n>>   }\n>>   \n>>   /**\n>","headers":{"Return-Path":"<libcamera-devel-bounces@lists.libcamera.org>","X-Original-To":"parsemail@patchwork.libcamera.org","Delivered-To":"parsemail@patchwork.libcamera.org","Received":["from lancelot.ideasonboard.com (lancelot.ideasonboard.com\n\t[92.243.16.209])\n\tby patchwork.libcamera.org (Postfix) with ESMTPS id D0768BDB1C\n\tfor <parsemail@patchwork.libcamera.org>;\n\tMon, 22 Sep 2025 07:53:03 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 99AA26B5F9;\n\tMon, 22 Sep 2025 09:53:02 +0200 (CEST)","from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 87A606B58E\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tMon, 22 Sep 2025 09:53:00 +0200 (CEST)","from [192.168.33.12] (185.221.142.115.nat.pool.zt.hu\n\t[185.221.142.115])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id 13D5C7CE;\n\tMon, 22 Sep 2025 09:51:36 +0200 (CEST)"],"Authentication-Results":"lancelot.ideasonboard.com; dkim=pass (1024-bit key;\n\tunprotected) header.d=ideasonboard.com header.i=@ideasonboard.com\n\theader.b=\"q4IJOMds\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1758527498;\n\tbh=7v3NyW8YmPGzeODKqW0WiCCaKd+DZf+8fnEAS9R1o+o=;\n\th=Date:Subject:To:Cc:References:From:In-Reply-To:From;\n\tb=q4IJOMdssbZk32FSnWIn43KmIrrMupa2DkSpUtT3QsIc6m1aW+SETyPS0P6WhkMZa\n\tBivYSjwCXJMvEYlltn/OTsaTcU+A02gH0ZclWziaFQjDr8nI6ag8hYqy9+qkADggkm\n\turG0jI2cwLxxYpcuVUpT+uMZey/j+ne7c+TLm5v4=","Message-ID":"<30e10fc5-3a6c-4ca8-b8ed-09d115d38fb7@ideasonboard.com>","Date":"Mon, 22 Sep 2025 09:52:53 +0200","MIME-Version":"1.0","User-Agent":"Mozilla Thunderbird","Subject":"Re: [PATCH v18 11/12] config: Make configuration file locations\n\tconfigurable","To":"Laurent Pinchart <laurent.pinchart@ideasonboard.com>,\n\tMilan Zamazal <mzamazal@redhat.com>","Cc":"libcamera-devel@lists.libcamera.org,\n\tKieran Bingham <kieran.bingham@ideasonboard.com>,\n\tPaul Elder <paul.elder@ideasonboard.com>","References":"<20250912142915.53949-1-mzamazal@redhat.com>\n\t<20250912142915.53949-13-mzamazal@redhat.com>\n\t<20250921050951.GI10985@pendragon.ideasonboard.com>","From":"=?utf-8?q?Barnab=C3=A1s_P=C5=91cze?= <barnabas.pocze@ideasonboard.com>","Content-Language":"en-US, hu-HU","In-Reply-To":"<20250921050951.GI10985@pendragon.ideasonboard.com>","Content-Type":"text/plain; charset=UTF-8; format=flowed","Content-Transfer-Encoding":"8bit","X-BeenThere":"libcamera-devel@lists.libcamera.org","X-Mailman-Version":"2.1.29","Precedence":"list","List-Id":"<libcamera-devel.lists.libcamera.org>","List-Unsubscribe":"<https://lists.libcamera.org/options/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=unsubscribe>","List-Archive":"<https://lists.libcamera.org/pipermail/libcamera-devel/>","List-Post":"<mailto:libcamera-devel@lists.libcamera.org>","List-Help":"<mailto:libcamera-devel-request@lists.libcamera.org?subject=help>","List-Subscribe":"<https://lists.libcamera.org/listinfo/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=subscribe>","Errors-To":"libcamera-devel-bounces@lists.libcamera.org","Sender":"\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>"}}]