!13 update ModemManager to 1.20.6

From: @eaglegai 
Reviewed-by: @kircher 
Signed-off-by: @kircher
This commit is contained in:
openeuler-ci-bot 2023-07-28 06:08:11 +00:00 committed by Gitee
commit 7ec9079bf6
No known key found for this signature in database
GPG Key ID: 173E9B9CA92EEF8F
8 changed files with 29 additions and 4783 deletions

Binary file not shown.

BIN
ModemManager-1.20.6.tar.bz2 Normal file

Binary file not shown.

View File

@ -4,23 +4,17 @@
Name: ModemManager Name: ModemManager
Version: 1.18.12 Version: 1.20.6
Release: 1 Release: 1
Summary: Mobile broadband modem manager Summary: Mobile broadband modem manager
License: GPLv2+ License: GPLv2+
URL: https://www.freedesktop.org/wiki/Software/ModemManager/ URL: https://www.freedesktop.org/wiki/Software/ModemManager/
Source: https://www.freedesktop.org/software/ModemManager/%{name}-%{version}.tar.xz Source: https://gitlab.com/linux-mobile-broadband/ModemManager/-/archive/%{version}/%{name}-%{version}.tar.bz2
Patch2: backport-core-port-GRegex-GMatchInfo-to-use-autoptr.patch BuildRequires: meson >= 0.53 dbus-devel gtk-doc vala-tools vala-devel
Patch5: backport-modem-helpers-rework-CGCONTRDP-response-parser.patch
Patch6: backport-modem-helpers-cinterion-rework-CNMI-test-response-parser.patch
Patch7: backport-modem-helpers-ublox-rework-UIPADDR-response-parser.patch
Patch8: backport-modem-helpers-rework-the-CGEV-indication-parser.patch
BuildRequires: automake autoconf dbus gtk-doc libtool vala-tools vala-devel
BuildRequires: gettext-devel glib2-devel gobject-introspection-devel libgudev-devel BuildRequires: gettext-devel glib2-devel gobject-introspection-devel libgudev-devel
BuildRequires: libqmi-devel >= 1.30.8 libmbim-devel >= 1.26.0 systemd-devel BuildRequires: libqmi-devel >= 1.32.0 libmbim-devel >= 1.28.0 systemd-devel systemd
BuildRequires: autoconf-archive python3-gobject python3-dbus BuildRequires: python3-gobject python3-dbus
Requires: libmbim-utils libqmi-utils glib2 >= %{glib2_version} Requires: libmbim-utils libqmi-utils glib2 >= %{glib2_version}
Requires: libmbim >= %{mbim_version} libqmi >= %{qmi_version} Requires: libmbim >= %{mbim_version} libqmi >= %{qmi_version}
@ -73,21 +67,26 @@ Vala bindings for ModemManager
%autosetup -n %{name}-%{version} -p1 %autosetup -n %{name}-%{version} -p1
%build %build
autoreconf -if %meson \
%configure \ -Ddist_version='"%{version}-%{release}"' \
--enable-gtk-doc --enable-more-warnings=no --disable-rpath \ -Dvapi=true \
--disable-silent-rules --with-udev-base-dir=%{_prefix}/lib/udev \ -Dqrtr=false \
--with-qmi=yes --with-mbim=yes --with-polkit=no --with-dist-version=%{version}-%{release} \ -Dgtk_doc=true \
--with-systemd-journal --with-systemd-suspend-resume -Dpolkit=permissive \
%make_build -Dbash_completion=false
%meson_build
%check
make check
%install %install
%make_install %meson_install
find %{buildroot}%{_datadir}/gtk-doc |xargs touch --reference meson.build
%find_lang %{name}
mkdir -p %{buildroot}%{_datadir}/bash-completion/completions/
cp -a cli/mmcli-completion %{buildroot}%{_datadir}/bash-completion/completions/mmcli
%delete_la %delete_la
%check
%meson_test
%post %post
%systemd_post ModemManager.service %systemd_post ModemManager.service
@ -109,6 +108,7 @@ make check
%{_unitdir}/ModemManager.service %{_unitdir}/ModemManager.service
%{_datadir}/dbus-1/system-services/org.freedesktop.ModemManager1.service %{_datadir}/dbus-1/system-services/org.freedesktop.ModemManager1.service
%{_datadir}/bash-completion %{_datadir}/bash-completion
%{_datadir}/polkit-1/actions/org.freedesktop.ModemManager1.policy
%{_sysconfdir}/dbus-1/system.d/org.freedesktop.ModemManager1.conf %{_sysconfdir}/dbus-1/system.d/org.freedesktop.ModemManager1.conf
%{_datadir}/ModemManager %{_datadir}/ModemManager
@ -136,7 +136,7 @@ make check
%files help %files help
%defattr(-,root,root) %defattr(-,root,root)
%doc README TODO NEWS ChangeLog %doc README TODO NEWS
%{_mandir}/man8/* %{_mandir}/man8/*
%{_mandir}/man1/* %{_mandir}/man1/*
%{_datadir}/icons/hicolor/22x22/apps/*.png %{_datadir}/icons/hicolor/22x22/apps/*.png
@ -144,6 +144,12 @@ make check
%{_datadir}/dbus-1/interfaces/*.xml %{_datadir}/dbus-1/interfaces/*.xml
%changelog %changelog
* Mon Jul 24 2023 gaihuiying <eaglegai@163.com> - 1.20.6-1
- Type:requirements
- ID:NA
- SUG:NA
- DESC: update ModemManager to 1.20.6
* Fri Nov 18 2022 gaihuiying <eaglegai@163.com> - 1.18.12-1 * Fri Nov 18 2022 gaihuiying <eaglegai@163.com> - 1.18.12-1
- Type:requirements - Type:requirements
- ID:NA - ID:NA

File diff suppressed because it is too large Load Diff

View File

@ -1,66 +0,0 @@
From e6c40349b81ac2915ce90b7e399eb33719a1fd24 Mon Sep 17 00:00:00 2001
From: Aleksander Morgado <aleksandermj@chromium.org>
Date: Wed, 24 Aug 2022 16:42:45 +0000
Subject: [PATCH] modem-helpers-cinterion: rework CNMI test response parser
We setup all output variables with g_autoptr() and then use
g_steal_pointer() to return the needed ones.
---
.../cinterion/mm-modem-helpers-cinterion.c | 25 ++++++++-----------
1 file changed, 10 insertions(+), 15 deletions(-)
diff --git a/plugins/cinterion/mm-modem-helpers-cinterion.c b/plugins/cinterion/mm-modem-helpers-cinterion.c
index 0bf3a0782..9219bff4d 100644
--- a/plugins/cinterion/mm-modem-helpers-cinterion.c
+++ b/plugins/cinterion/mm-modem-helpers-cinterion.c
@@ -556,12 +556,12 @@ mm_cinterion_parse_cnmi_test (const gchar *response,
{
g_autoptr(GRegex) r = NULL;
g_autoptr(GMatchInfo) match_info = NULL;
+ g_autoptr(GArray) tmp_supported_mode = NULL;
+ g_autoptr(GArray) tmp_supported_mt = NULL;
+ g_autoptr(GArray) tmp_supported_bm = NULL;
+ g_autoptr(GArray) tmp_supported_ds = NULL;
+ g_autoptr(GArray) tmp_supported_bfr = NULL;
GError *inner_error = NULL;
- GArray *tmp_supported_mode = NULL;
- GArray *tmp_supported_mt = NULL;
- GArray *tmp_supported_bm = NULL;
- GArray *tmp_supported_ds = NULL;
- GArray *tmp_supported_bfr = NULL;
if (!response) {
g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_FAILED, "Missing response");
@@ -619,25 +619,20 @@ mm_cinterion_parse_cnmi_test (const gchar *response,
out:
if (inner_error) {
- g_clear_pointer (&tmp_supported_mode, g_array_unref);
- g_clear_pointer (&tmp_supported_mt, g_array_unref);
- g_clear_pointer (&tmp_supported_bm, g_array_unref);
- g_clear_pointer (&tmp_supported_ds, g_array_unref);
- g_clear_pointer (&tmp_supported_bfr, g_array_unref);
g_propagate_error (error, inner_error);
return FALSE;
}
if (supported_mode)
- *supported_mode = tmp_supported_mode;
+ *supported_mode = g_steal_pointer (&tmp_supported_mode);
if (supported_mt)
- *supported_mt = tmp_supported_mt;
+ *supported_mt = g_steal_pointer (&tmp_supported_mt);
if (supported_bm)
- *supported_bm = tmp_supported_bm;
+ *supported_bm = g_steal_pointer (&tmp_supported_bm);
if (supported_ds)
- *supported_ds = tmp_supported_ds;
+ *supported_ds = g_steal_pointer (&tmp_supported_ds);
if (supported_bfr)
- *supported_bfr = tmp_supported_bfr;
+ *supported_bfr = g_steal_pointer (&tmp_supported_bfr);
return TRUE;
}
--
GitLab

View File

@ -1,156 +0,0 @@
From 845667c7b3d36f0e776d5a0e582ad62d48cdeb02 Mon Sep 17 00:00:00 2001
From: Aleksander Morgado <aleksandermj@chromium.org>
Date: Wed, 24 Aug 2022 16:41:36 +0000
Subject: [PATCH] modem-helpers: rework +CGCONTRDP response parser
We setup all output variables with g_autofree and then use
g_steal_pointer() to return the needed ones.
---
src/mm-modem-helpers.c | 87 +++++++++++++++---------------------------
1 file changed, 31 insertions(+), 56 deletions(-)
diff --git a/src/mm-modem-helpers.c b/src/mm-modem-helpers.c
index 58207bb15..9c3b0ccdc 100644
--- a/src/mm-modem-helpers.c
+++ b/src/mm-modem-helpers.c
@@ -2335,13 +2335,13 @@ mm_3gpp_parse_cgcontrdp_response (const gchar *response,
GError *inner_error = NULL;
guint cid = 0;
guint bearer_id = 0;
- gchar *apn = NULL;
- gchar *local_address_and_subnet = NULL;
- gchar *local_address = NULL;
- gchar *subnet = NULL;
- gchar *gateway_address = NULL;
- gchar *dns_primary_address = NULL;
- gchar *dns_secondary_address = NULL;
+ g_autofree gchar *apn = NULL;
+ g_autofree gchar *local_address_and_subnet = NULL;
+ g_autofree gchar *local_address = NULL;
+ g_autofree gchar *subnet = NULL;
+ g_autofree gchar *gateway_address = NULL;
+ g_autofree gchar *dns_primary_address = NULL;
+ g_autofree gchar *dns_secondary_address = NULL;
guint field_format_extra_index = 0;
/* Response may be e.g.:
@@ -2371,28 +2371,28 @@ mm_3gpp_parse_cgcontrdp_response (const gchar *response,
g_assert (r != NULL);
g_regex_match_full (r, response, strlen (response), 0, 0, &match_info, &inner_error);
- if (inner_error)
- goto out;
+ if (inner_error) {
+ g_propagate_error (error, inner_error);
+ return FALSE;
+ }
if (!g_match_info_matches (match_info)) {
- inner_error = g_error_new (MM_CORE_ERROR, MM_CORE_ERROR_INVALID_ARGS, "Couldn't match +CGCONTRDP response");
- goto out;
+ g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_INVALID_ARGS, "Couldn't match +CGCONTRDP response");
+ return FALSE;
}
if (out_cid && !mm_get_uint_from_match_info (match_info, 1, &cid)) {
- inner_error = g_error_new (MM_CORE_ERROR, MM_CORE_ERROR_FAILED, "Error parsing cid");
- goto out;
+ g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_FAILED, "Error parsing cid");
+ return FALSE;
}
if (out_bearer_id && !mm_get_uint_from_match_info (match_info, 2, &bearer_id)) {
- inner_error = g_error_new (MM_CORE_ERROR, MM_CORE_ERROR_FAILED, "Error parsing bearer id");
- goto out;
+ g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_FAILED, "Error parsing bearer id");
+ return FALSE;
}
/* Remaining strings are optional or empty allowed */
-
- if (out_apn)
- apn = mm_get_string_unquoted_from_match_info (match_info, 3);
+ apn = mm_get_string_unquoted_from_match_info (match_info, 3);
/*
* The +CGCONTRDP=[cid] response format before version TS 27.007 v9.4.0 had
@@ -2400,64 +2400,39 @@ mm_3gpp_parse_cgcontrdp_response (const gchar *response,
*/
local_address_and_subnet = mm_get_string_unquoted_from_match_info (match_info, 4);
if (local_address_and_subnet && !split_local_address_and_subnet (local_address_and_subnet, &local_address, &subnet)) {
- inner_error = g_error_new (MM_CORE_ERROR, MM_CORE_ERROR_FAILED, "Error parsing local address and subnet");
- goto out;
+ g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_FAILED, "Error parsing local address and subnet");
+ return FALSE;
}
+
/* If we don't have a subnet in field 4, we're using the old format with subnet in an extra field */
if (!subnet) {
- if (out_subnet)
- subnet = mm_get_string_unquoted_from_match_info (match_info, 5);
+ subnet = mm_get_string_unquoted_from_match_info (match_info, 5);
field_format_extra_index = 1;
}
- if (out_gateway_address)
- gateway_address = mm_get_string_unquoted_from_match_info (match_info, 5 + field_format_extra_index);
-
- if (out_dns_primary_address)
- dns_primary_address = mm_get_string_unquoted_from_match_info (match_info, 6 + field_format_extra_index);
-
- if (out_dns_secondary_address)
- dns_secondary_address = mm_get_string_unquoted_from_match_info (match_info, 7 + field_format_extra_index);
-
-out:
- g_free (local_address_and_subnet);
-
- if (inner_error) {
- g_free (apn);
- g_free (local_address);
- g_free (subnet);
- g_free (gateway_address);
- g_free (dns_primary_address);
- g_free (dns_secondary_address);
- g_propagate_error (error, inner_error);
- return FALSE;
- }
+ gateway_address = mm_get_string_unquoted_from_match_info (match_info, 5 + field_format_extra_index);
+ dns_primary_address = mm_get_string_unquoted_from_match_info (match_info, 6 + field_format_extra_index);
+ dns_secondary_address = mm_get_string_unquoted_from_match_info (match_info, 7 + field_format_extra_index);
if (out_cid)
*out_cid = cid;
if (out_bearer_id)
*out_bearer_id = bearer_id;
if (out_apn)
- *out_apn = apn;
-
+ *out_apn = g_steal_pointer (&apn);
/* Local address and subnet may always be retrieved, even if not requested
* by the caller, as we need them to know which +CGCONTRDP=[cid] response is
* being parsed. So make sure we free them if not needed. */
if (out_local_address)
- *out_local_address = local_address;
- else
- g_free (local_address);
+ *out_local_address = g_steal_pointer (&local_address);
if (out_subnet)
- *out_subnet = subnet;
- else
- g_free (subnet);
-
+ *out_subnet = g_steal_pointer (&subnet);
if (out_gateway_address)
- *out_gateway_address = gateway_address;
+ *out_gateway_address = g_steal_pointer (&gateway_address);
if (out_dns_primary_address)
- *out_dns_primary_address = dns_primary_address;
+ *out_dns_primary_address = g_steal_pointer (&dns_primary_address);
if (out_dns_secondary_address)
- *out_dns_secondary_address = dns_secondary_address;
+ *out_dns_secondary_address = g_steal_pointer (&dns_secondary_address);
return TRUE;
}
--
GitLab

View File

@ -1,86 +0,0 @@
From 9bbc768666e8ca77abdda325c46588cbf8a4df64 Mon Sep 17 00:00:00 2001
From: Aleksander Morgado <aleksandermj@chromium.org>
Date: Wed, 24 Aug 2022 16:50:34 +0000
Subject: [PATCH] modem-helpers: rework the +CGEV indication parser
We setup all output variables with g_autofree and then use
g_steal_pointer() to return the needed ones.
---
src/mm-modem-helpers.c | 36 +++++++++++++++---------------------
1 file changed, 15 insertions(+), 21 deletions(-)
diff --git a/src/mm-modem-helpers.c b/src/mm-modem-helpers.c
index 9c3b0ccdc..d71e1082c 100644
--- a/src/mm-modem-helpers.c
+++ b/src/mm-modem-helpers.c
@@ -3642,8 +3642,8 @@ mm_3gpp_parse_cgev_indication_pdp (const gchar *str,
g_autoptr(GRegex) r = NULL;
g_autoptr(GMatchInfo) match_info = NULL;
GError *inner_error = NULL;
- gchar *pdp_type = NULL;
- gchar *pdp_addr = NULL;
+ g_autofree gchar *pdp_type = NULL;
+ g_autofree gchar *pdp_addr = NULL;
guint cid = 0;
g_assert (type == MM_3GPP_CGEV_REJECT ||
@@ -3660,44 +3660,38 @@ mm_3gpp_parse_cgev_indication_pdp (const gchar *str,
str = mm_strip_tag (str, "+CGEV:");
g_regex_match_full (r, str, strlen (str), 0, 0, &match_info, &inner_error);
- if (inner_error)
- goto out;
+ if (inner_error) {
+ g_propagate_error (error, inner_error);
+ return FALSE;
+ }
if (!g_match_info_matches (match_info)) {
- inner_error = g_error_new (MM_CORE_ERROR, MM_CORE_ERROR_FAILED, "Couldn't match response");
- goto out;
+ g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_FAILED, "Couldn't match response");
+ return FALSE;
}
if (out_pdp_type && !(pdp_type = mm_get_string_unquoted_from_match_info (match_info, 1))) {
- inner_error = g_error_new (MM_CORE_ERROR, MM_CORE_ERROR_FAILED, "Error parsing PDP type");
- goto out;
+ g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_FAILED, "Error parsing PDP type");
+ return FALSE;
}
if (out_pdp_addr && !(pdp_addr = mm_get_string_unquoted_from_match_info (match_info, 2))) {
- inner_error = g_error_new (MM_CORE_ERROR, MM_CORE_ERROR_FAILED, "Error parsing PDP addr");
- goto out;
+ g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_FAILED, "Error parsing PDP addr");
+ return FALSE;
}
/* CID is optional */
if (out_cid &&
(g_match_info_get_match_count (match_info) >= 4) &&
!mm_get_uint_from_match_info (match_info, 3, &cid)) {
- inner_error = g_error_new (MM_CORE_ERROR, MM_CORE_ERROR_FAILED, "Error parsing CID");
- goto out;
- }
-
-out:
- if (inner_error) {
- g_free (pdp_type);
- g_free (pdp_addr);
- g_propagate_error (error, inner_error);
+ g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_FAILED, "Error parsing CID");
return FALSE;
}
if (out_pdp_type)
- *out_pdp_type = pdp_type;
+ *out_pdp_type = g_steal_pointer (&pdp_type);
if (out_pdp_addr)
- *out_pdp_addr = pdp_addr;
+ *out_pdp_addr = g_steal_pointer (&pdp_addr);
if (out_cid)
*out_cid = cid;
return TRUE;
--
GitLab

View File

@ -1,115 +0,0 @@
From 8eeaba188272de496671763bc31f7fd592cb5ce0 Mon Sep 17 00:00:00 2001
From: Aleksander Morgado <aleksandermj@chromium.org>
Date: Wed, 24 Aug 2022 16:55:41 +0000
Subject: [PATCH] modem-helpers-ublox: rework +UIPADDR response parser
We setup all output variables with g_autofree and then use
g_steal_pointer() to return the needed ones.
---
plugins/ublox/mm-modem-helpers-ublox.c | 65 ++++++++++----------------
1 file changed, 24 insertions(+), 41 deletions(-)
diff --git a/plugins/ublox/mm-modem-helpers-ublox.c b/plugins/ublox/mm-modem-helpers-ublox.c
index 5cc035422..84a7cf272 100644
--- a/plugins/ublox/mm-modem-helpers-ublox.c
+++ b/plugins/ublox/mm-modem-helpers-ublox.c
@@ -228,11 +228,11 @@ mm_ublox_parse_uipaddr_response (const gchar *response,
g_autoptr(GMatchInfo) match_info = NULL;
GError *inner_error = NULL;
guint cid = 0;
- gchar *if_name = NULL;
- gchar *ipv4_address = NULL;
- gchar *ipv4_subnet = NULL;
- gchar *ipv6_global_address = NULL;
- gchar *ipv6_link_local_address = NULL;
+ g_autofree gchar *if_name = NULL;
+ g_autofree gchar *ipv4_address = NULL;
+ g_autofree gchar *ipv4_subnet = NULL;
+ g_autofree gchar *ipv6_global_address = NULL;
+ g_autofree gchar *ipv6_link_local_address = NULL;
/* Response may be e.g.:
* +UIPADDR: 1,"ccinet0","5.168.120.13","255.255.255.0","",""
@@ -245,61 +245,44 @@ mm_ublox_parse_uipaddr_response (const gchar *response,
g_assert (r != NULL);
g_regex_match_full (r, response, strlen (response), 0, 0, &match_info, &inner_error);
- if (inner_error)
- goto out;
+ if (inner_error) {
+ g_propagate_error (error, inner_error);
+ return FALSE;
+ }
if (!g_match_info_matches (match_info)) {
- inner_error = g_error_new (MM_CORE_ERROR, MM_CORE_ERROR_INVALID_ARGS, "Couldn't match +UIPADDR response");
- goto out;
+ g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_INVALID_ARGS, "Couldn't match +UIPADDR response");
+ return FALSE;
}
if (out_cid && !mm_get_uint_from_match_info (match_info, 1, &cid)) {
- inner_error = g_error_new (MM_CORE_ERROR, MM_CORE_ERROR_FAILED, "Error parsing cid");
- goto out;
+ g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_FAILED, "Error parsing cid");
+ return FALSE;
}
if (out_if_name && !(if_name = mm_get_string_unquoted_from_match_info (match_info, 2))) {
- inner_error = g_error_new (MM_CORE_ERROR, MM_CORE_ERROR_FAILED, "Error parsing interface name");
- goto out;
+ g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_FAILED, "Error parsing interface name");
+ return FALSE;
}
/* Remaining strings are optional */
-
- if (out_ipv4_address)
- ipv4_address = mm_get_string_unquoted_from_match_info (match_info, 3);
-
- if (out_ipv4_subnet)
- ipv4_subnet = mm_get_string_unquoted_from_match_info (match_info, 4);
-
- if (out_ipv6_global_address)
- ipv6_global_address = mm_get_string_unquoted_from_match_info (match_info, 5);
-
- if (out_ipv6_link_local_address)
- ipv6_link_local_address = mm_get_string_unquoted_from_match_info (match_info, 6);
-
-out:
- if (inner_error) {
- g_free (if_name);
- g_free (ipv4_address);
- g_free (ipv4_subnet);
- g_free (ipv6_global_address);
- g_free (ipv6_link_local_address);
- g_propagate_error (error, inner_error);
- return FALSE;
- }
+ ipv4_address = mm_get_string_unquoted_from_match_info (match_info, 3);
+ ipv4_subnet = mm_get_string_unquoted_from_match_info (match_info, 4);
+ ipv6_global_address = mm_get_string_unquoted_from_match_info (match_info, 5);
+ ipv6_link_local_address = mm_get_string_unquoted_from_match_info (match_info, 6);
if (out_cid)
*out_cid = cid;
if (out_if_name)
- *out_if_name = if_name;
+ *out_if_name = g_steal_pointer (&if_name);
if (out_ipv4_address)
- *out_ipv4_address = ipv4_address;
+ *out_ipv4_address = g_steal_pointer (&ipv4_address);
if (out_ipv4_subnet)
- *out_ipv4_subnet = ipv4_subnet;
+ *out_ipv4_subnet = g_steal_pointer (&ipv4_subnet);
if (out_ipv6_global_address)
- *out_ipv6_global_address = ipv6_global_address;
+ *out_ipv6_global_address = g_steal_pointer (&ipv6_global_address);
if (out_ipv6_link_local_address)
- *out_ipv6_link_local_address = ipv6_link_local_address;
+ *out_ipv6_link_local_address = g_steal_pointer (&ipv6_link_local_address);
return TRUE;
}
--
GitLab