Change in osmo-gsm-tester[master]: contrib: Add scripts to build srsLTE software

This is merely a historical archive of years 2008-2021, before the migration to mailman3.

A maintained and still updated list archive can be found at https://lists.osmocom.org/hyperkitty/list/gerrit-log@lists.osmocom.org/.

pespin gerrit-no-reply at lists.osmocom.org
Wed Jan 29 18:24:33 UTC 2020


pespin has uploaded this change for review. ( https://gerrit.osmocom.org/c/osmo-gsm-tester/+/17067 )


Change subject: contrib: Add scripts to build srsLTE software
......................................................................

contrib: Add scripts to build srsLTE software

Change-Id: Id9d63920a44a80af187e649c9be5fd7498fa5f44
---
M contrib/jenkins-build-common.sh
A contrib/jenkins-build-srslte.sh
A src/osmo_gsm_tester/templates/srsue.cfg.tmpl
D src/osmo_gsm_tester/test.py
A suites/4g/mo_mt_sms.py
A suites/4g/suite.conf
D update_version.sh
7 files changed, 403 insertions(+), 136 deletions(-)



  git pull ssh://gerrit.osmocom.org:29418/osmo-gsm-tester refs/changes/67/17067/1

diff --git a/contrib/jenkins-build-common.sh b/contrib/jenkins-build-common.sh
index a9eaf7a..f263784 100644
--- a/contrib/jenkins-build-common.sh
+++ b/contrib/jenkins-build-common.sh
@@ -142,10 +142,18 @@
 
   cd "$dep/${dir}"
 
-  set +x; echo; echo; set -x
-  autoreconf -fi
-  set +x; echo; echo; set -x
-  ./configure --prefix="$prefix" --with-systemdsystemunitdir=no $CONFIGURE_FLAGS $configure_opts
+  if [ -f configure.ac ]; then
+    set +x; echo; echo; set -x
+    autoreconf -fi
+    set +x; echo; echo; set -x
+    ./configure --prefix="$prefix" --with-systemdsystemunitdir=no $CONFIGURE_FLAGS $configure_opts
+  elif [ -f CMakeLists.txt ]; then
+    rm -rf build && mkdir build && cd build || exit 1
+    set +x; echo; echo; set -x
+    cmake ../ -DCMAKE_INSTALL_PREFIX=$prefix $CONFIGURE_FLAGS $configure_opts
+  else
+    echo "Unknwown build system" && exit 1
+  fi
   set +x; echo; echo; set -x
   make -j8 || make  # libsmpp34 can't build in parallel
   set +x; echo; echo; set -x
@@ -213,6 +221,9 @@
 
   prune_files bin "$wanted_binaries_bin"
   prune_files sbin "$wanted_binaries_sbin"
+  # Drop all static libraries if exist:
+  rm -f $prefix_real/lib/*.a
+  rm -f $prefix_real/lib/*.la
 
   cd "$prefix_real"
   add_rpath
diff --git a/contrib/jenkins-build-srslte.sh b/contrib/jenkins-build-srslte.sh
new file mode 100755
index 0000000..705e4ab
--- /dev/null
+++ b/contrib/jenkins-build-srslte.sh
@@ -0,0 +1,13 @@
+#!/bin/sh
+set -e -x
+
+base="$PWD"
+name="srslte"
+SANITIZE_FLAGS=""
+git_url="https://github.com/srsLTE/"
+. "$(dirname "$0")/jenkins-build-common.sh"
+
+#TODO: make sure libconfig, zeroMQ is installed
+build_repo srsLTE ${SANITIZE_FLAGS}
+
+create_bin_tgz "srsue srsenb srsepc"
diff --git a/src/osmo_gsm_tester/templates/srsue.cfg.tmpl b/src/osmo_gsm_tester/templates/srsue.cfg.tmpl
new file mode 100644
index 0000000..0afa78b
--- /dev/null
+++ b/src/osmo_gsm_tester/templates/srsue.cfg.tmpl
@@ -0,0 +1,347 @@
+#####################################################################
+#                   srsUE configuration file
+#####################################################################
+
+#####################################################################
+# RF configuration
+#
+# dl_earfcn: Downlink EARFCN code.
+# freq_offset: Uplink and Downlink optional frequency offset (in Hz)
+# tx_gain: Transmit gain (dB). 
+# rx_gain: Optional receive gain (dB). If disabled, AGC if enabled
+#
+# Optional parameters: 
+# dl_freq:            Override DL frequency corresponding to dl_earfcn
+# ul_freq:            Override UL frequency corresponding to dl_earfcn
+# nof_radios:         Number of available RF devices
+# nof_rf_channels:    Number of RF channels per radio
+# nof_rx_ant:         Number of RX antennas per channel
+# device_name:        Device driver family. Supported options: "auto" (uses first found), "UHD" or "bladeRF" 
+# device_args:        Arguments for the device driver. Options are "auto" or any string. 
+#                     Default for UHD: "recv_frame_size=9232,send_frame_size=9232"
+#                     Default for bladeRF: ""
+# device_args_2:      Arguments for the RF device driver 2.
+# device_args_3:      Arguments for the RF device driver 3.
+# time_adv_nsamples:  Transmission time advance (in number of samples) to compensate for RF delay
+#                     from antenna to timestamp insertion. 
+#                     Default "auto". B210 USRP: 100 samples, bladeRF: 27.
+# burst_preamble_us:  Preamble length to transmit before start of burst. 
+#                     Default "auto". B210 USRP: 400 us, bladeRF: 0 us.
+# continuous_tx:      Transmit samples continuously to the radio or on bursts (auto/yes/no).
+#                     Default is auto (yes for UHD, no for rest)
+#####################################################################
+[rf]
+dl_earfcn = 3400
+freq_offset = 0
+tx_gain = 80
+#rx_gain = 40
+
+#nof_radios = 1
+#nof_rx_ant = 1
+
+# For best performance in 2x2 MIMO and >= 15 MHz use the following device_args settings:
+#     USRP B210: num_recv_frames=64,num_send_frames=64
+
+# For best performance when BW<5 MHz (25 PRB), use the following device_args settings:
+#     USRP B210: send_frame_size=512,recv_frame_size=512
+
+#device_args = auto
+#time_adv_nsamples = auto
+#burst_preamble_us = auto
+#continuous_tx     = auto
+
+
+#####################################################################
+# Packet capture configuration
+#
+# Packet capture is supported at both MAC and NAS layers.
+# MAC-layer packets are captured to file in the compact format
+# decoded by the Wireshark mac-lte-framed dissector.
+# To use this dissector, edit the preferences for DLT_USER to
+# add an entry with DLT=147, Payload Protocol=mac-lte-framed.
+# For more information see: https://wiki.wireshark.org/MAC-LTE
+# NAS-layer packets are dissected with DLT=148, and
+# Payload Protocol = nas-eps.
+#
+# enable:       Enable MAC layer packet captures (true/false)
+# filename:     File path to use for MAC packet captures
+# nas_enable:   Enable NAS layer packet captures (true/false)
+# nas_filename: File path to use for NAS packet captures
+#####################################################################
+[pcap]
+enable = false
+filename = /tmp/ue.pcap
+nas_enable = false
+nas_filename = /tmp/nas.pcap
+
+#####################################################################
+# Log configuration
+#
+# Log levels can be set for individual layers. "all_level" sets log
+# level for all layers unless otherwise configured.
+# Format: e.g. phy_level = info
+#
+# In the same way, packet hex dumps can be limited for each level.
+# "all_hex_limit" sets the hex limit for all layers unless otherwise
+# configured.
+# Format: e.g. phy_hex_limit = 32
+#
+# Logging layers: rf, phy, mac, rlc, pdcp, rrc, nas, gw, usim, all
+# Logging levels: debug, info, warning, error, none
+#
+# filename: File path to use for log output. Can be set to stdout
+#           to print logs to standard output
+# file_max_size: Maximum file size (in kilobytes). When passed, multiple files are created.
+#                If set to negative, a single log file will be created.
+#####################################################################
+[log]
+all_level = warning
+phy_lib_level = none
+all_hex_limit = 32
+filename = /tmp/ue.log
+file_max_size = -1
+
+#####################################################################
+# USIM configuration
+#
+# mode:   USIM mode (soft/pcsc)
+# algo:   Authentication algorithm (xor/milenage)
+# op/opc: 128-bit Operator Variant Algorithm Configuration Field (hex)
+#         - Specify either op or opc (only used in milenage)
+# k:      128-bit subscriber key (hex)
+# imsi:   15 digit International Mobile Subscriber Identity
+# imei:   15 digit International Mobile Station Equipment Identity
+# pin:    PIN in case real SIM card is used
+# reader: Specify card reader by it's name as listed by 'pcsc_scan'. If empty, try all available readers.
+#####################################################################
+[usim]
+mode = soft
+algo = xor
+#opc  = 63BFA50EE6523365FF14C1F45F88737D
+k    = 00112233445566778899aabbccddeeff
+imsi = 001010123456789
+imei = 353490069873319
+#reader = 
+#pin  = 1234
+
+#####################################################################
+# RRC configuration
+#
+# ue_category:       Sets UE category (range 1-5). Default: 4
+# release:           UE Release (8 to 10)
+# feature_group:     Hex value of the featureGroupIndicators field in the
+#                    UECapabilityInformation message. Default 0xe6041000
+# mbms_service_id:   MBMS service id for autostarting MBMS reception
+#                    (default -1 means disabled)
+# mbms_service_port: Port of the MBMS service
+#####################################################################
+[rrc]
+#ue_category       = 4
+#release           = 8
+#feature_group     = 0xe6041000
+#mbms_service_id   = -1
+#mbms_service_port = 4321
+
+#####################################################################
+# NAS configuration
+#
+# apn:               Set Access Point Name (APN)
+# apn_protocol:      Set APN protocol (IPv4, IPv6 or IPv4v6.)
+# user:              Username for CHAP authentication
+# pass:              Password for CHAP authentication
+# force_imsi_attach: Whether to always perform an IMSI attach
+# eia:               List of integrity algorithms included in UE capabilities
+#                      Supported: 1 - Snow3G, 2 - AES
+# eea:               List of ciphering algorithms included in UE capabilities
+#                      Supported: 0 - NULL, 1 - Snow3G, 2 - AES
+#####################################################################
+[nas]
+#apn = internetinternet
+#apn_protocol = ipv4
+#user = srsuser
+#pass = srspass
+#force_imsi_attach = false
+#eia = 1,2
+#eea = 0,1,2
+
+#####################################################################
+# GW configuration
+#
+# netns:                Network namespace to create TUN device. Default: empty
+# ip_devname:           Name of the tun_srsue device. Default: tun_srsue
+# ip_netmask:           Netmask of the tun_srsue device. Default: 255.255.255.0
+#####################################################################
+[gw]
+#netns =
+#ip_devname = tun_srsue
+#ip_netmask = 255.255.255.0
+
+#####################################################################
+# GUI configuration
+#
+# Simple GUI displaying PDSCH constellation and channel freq response.
+# (Requires building with srsGUI)
+# enable:               Enable the graphical interface (true/false)
+#####################################################################
+[gui]
+enable = false
+
+#####################################################################
+# Channel emulator options:
+# enable:            Enable/Disable internal Downlink/Uplink channel emulator
+#
+# -- Fading emulator
+# fading.enable:     Enable/disable fading simulator
+# fading.model:      Fading model + maximum doppler (E.g. none, epa5, eva70, etu300, etc)
+#
+# -- Delay Emulator     delay(t) = delay_min + (delay_max - delay_min) * (1 + sin(2pi*t/period)) / 2
+#                       Maximum speed [m/s]: (delay_max - delay_min) * pi * 300 / period
+# delay.enable:      Enable/disable delay simulator
+# delay.period_s:    Delay period in seconds.
+# delay.init_time_s: Delay initial time in seconds.
+# delay.maximum_us:  Maximum delay in microseconds
+# delay.minumum_us:  Minimum delay in microseconds
+#
+# -- Radio-Link Failure (RLF) Emulator
+# rlf.enable:        Enable/disable RLF simulator
+# rlf.t_on_ms:       Time for On state of the channel (ms)
+# rlf.t_off_ms:      Time for Off state of the channel (ms)
+#
+# -- High Speed Train Doppler model simulator
+# hst.enable:        Enable/Disable HST simulator
+# hst.period_s:      HST simulation period in seconds
+# hst.fd_hz:         Doppler frequency in Hz
+# hst.init_time_s:   Initial time in seconds
+#####################################################################
+[channel.dl]
+#enable        = false
+
+[channel.dl.fading]
+#enable        = false
+#model         = none
+
+[channel.dl.delay]
+#enable        = false
+#period_s      = 3600
+#init_time_s   = 0
+#maximum_us    = 100
+#minimum_us    = 10
+
+[channel.dl.rlf]
+#enable        = false
+#t_on_ms       = 10000
+#t_off_ms      = 2000
+
+[channel.dl.hst]
+#enable        = false
+#period_s      = 7.2
+#fd_hz         = 750.0
+#init_time_s   = 0.0
+
+[channel.ul]
+#enable        = false
+
+[channel.ul.fading]
+#enable        = false
+#model         = none
+
+[channel.ul.delay]
+#enable        = false
+#period_s      = 3600
+#init_time_s   = 0
+#maximum_us    = 100
+#minimum_us    = 10
+
+[channel.ul.rlf]
+#enable        = false
+#t_on_ms       = 10000
+#t_off_ms      = 2000
+
+[channel.ul.hst]
+#enable        = false
+#period_s      = 7.2
+#fd_hz         = -750.0
+#init_time_s   = 0.0
+
+#####################################################################
+# PHY configuration options
+#
+# rx_gain_offset:       RX Gain offset to add to rx_gain to calibrate RSRP readings
+# prach_gain:           PRACH gain (dB). If defined, forces a gain for the tranmsission of PRACH only.,
+#                       Default is to use tx_gain in [rf] section. 
+# cqi_max:              Upper bound on the maximum CQI to be reported. Default 15. 
+# cqi_fixed:            Fixes the reported CQI to a constant value. Default disabled.
+# snr_ema_coeff:        Sets the SNR exponential moving average coefficient (Default 0.1)
+# snr_estim_alg:        Sets the noise estimation algorithm. (Default refs)
+#                          Options: pss:   use difference between received and known pss signal, 
+#                                   refs:  use difference between noise references and noiseless (after filtering)
+#                                   empty: use empty subcarriers in the boarder of pss/sss signal
+# pdsch_max_its:        Maximum number of turbo decoder iterations (Default 4)
+# nof_phy_threads:      Selects the number of PHY threads (maximum 4, minimum 1, default 2)
+# equalizer_mode:       Selects equalizer mode. Valid modes are: "mmse", "zf" or any 
+#                       non-negative real number to indicate a regularized zf coefficient.
+#                       Default is MMSE.
+# sfo_ema:              EMA coefficient to average sample offsets used to compute SFO
+# sfo_correct_period:   Period in ms to correct sample time to adjust for SFO
+# sss_algorithm:        Selects the SSS estimation algorithm. Can choose between
+#                       {full, partial, diff}. 
+# estimator_fil_auto:   The channel estimator smooths the channel estimate with an adaptative filter.
+# estimator_fil_stddev: Sets the channel estimator smooth gaussian filter standard deviation.
+# estimator_fil_order:  Sets the channel estimator smooth gaussian filter order (even values perform better).
+#                       The taps are [w, 1-2w, w]
+#
+# snr_to_cqi_offset:    Sets an offset in the SNR to CQI table. This is used to adjust the reported CQI.
+#
+# pregenerate_signals:  Pregenerate uplink signals after attach. Improves CPU performance.
+#
+# interpolate_subframe_enabled: Interpolates in the time domain the channel estimates within 1 subframe. Default is to average.
+#
+# sic_pss_enabled:      Applies Successive Interference Cancellation to PSS signals when searching for neighbour cells.
+#                       Must be disabled if cells have identical channel and timing, for instance if generated from
+#                       the same source.
+#
+# pdsch_csi_enabled:     Stores the Channel State Information and uses it for weightening the softbits. It is only
+#                        used in TM1. It is True by default.
+#
+# pdsch_8bit_decoder:    Use 8-bit for LLR representation and turbo decoder trellis computation (Experimental)
+# force_ul_amplitude:    Forces the peak amplitude in the PUCCH, PUSCH and SRS (set 0.0 to 1.0, set to 0 or negative for disabling)
+#
+#####################################################################
+[phy]
+#rx_gain_offset      = 62
+#prach_gain          = 30
+#cqi_max             = 15
+#cqi_fixed           = 10
+#snr_ema_coeff       = 0.1
+#snr_estim_alg       = refs
+#pdsch_max_its       = 8    # These are half iterations
+#nof_phy_threads     = 3
+#equalizer_mode      = mmse
+#sfo_ema             = 0.1
+#sfo_correct_period  = 10
+#sss_algorithm       = full
+#estimator_fil_auto  = false
+#estimator_fil_stddev  = 1.0
+#estimator_fil_order  = 4
+#snr_to_cqi_offset   = 0.0
+#interpolate_subframe_enabled = false
+#sic_pss_enabled     = true
+#pregenerate_signals = false
+#pdsch_csi_enabled  = true
+#pdsch_8bit_decoder = false
+#force_ul_amplitude = 0
+
+#####################################################################
+# General configuration options
+#
+# metrics_csv_enable:   Write UE metrics to CSV file.
+#
+# metrics_period_secs:  Sets the period at which metrics are requested from the UE.
+#
+# metrics_csv_filename: File path to use for CSV metrics.
+#
+#####################################################################
+[general]
+#metrics_csv_enable  = false
+#metrics_period_secs = 1
+#metrics_csv_filename = /tmp/ue_metrics.csv
diff --git a/src/osmo_gsm_tester/test.py b/src/osmo_gsm_tester/test.py
deleted file mode 100644
index 4d4353a..0000000
--- a/src/osmo_gsm_tester/test.py
+++ /dev/null
@@ -1,122 +0,0 @@
-# osmo_gsm_tester: test class
-#
-# Copyright (C) 2017 by sysmocom - s.f.m.c. GmbH
-#
-# Author: Pau Espin Pedrol <pespin at sysmocom.de>
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as
-# published by the Free Software Foundation, either version 3 of the
-# License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program.  If not, see <http://www.gnu.org/licenses/>.
-
-import os
-import sys
-import time
-import traceback
-from . import testenv
-
-from . import log, util, resource
-
-class Test(log.Origin):
-    UNKNOWN = 'UNKNOWN'
-    SKIP = 'skip'
-    PASS = 'pass'
-    FAIL = 'FAIL'
-
-    def __init__(self, suite_run, test_basename):
-        self.basename = test_basename
-        super().__init__(log.C_TST, self.basename)
-        self._run_dir = None
-        self.suite_run = suite_run
-        self.path = os.path.join(self.suite_run.definition.suite_dir, self.basename)
-        self.status = Test.UNKNOWN
-        self.start_timestamp = 0
-        self.duration = 0
-        self.fail_type = None
-        self.fail_message = None
-        self.log_target = None
-
-    def get_run_dir(self):
-        if self._run_dir is None:
-            self._run_dir = util.Dir(self.suite_run.get_run_dir().new_dir(self._name))
-        return self._run_dir
-
-    def run(self):
-        try:
-            self.log_target = log.FileLogTarget(self.get_run_dir().new_child('log')).set_all_levels(log.L_DBG).style_change(trace=True)
-            log.large_separator(self.suite_run.trial.name(), self.suite_run.name(), self.name(), sublevel=3)
-            self.status = Test.UNKNOWN
-            self.start_timestamp = time.time()
-            from . import suite, sms, process
-            from .event_loop import MainLoop
-            testenv.setup(self.suite_run, self, suite, MainLoop, sms, process)
-            with self.redirect_stdout():
-                util.run_python_file('%s.%s' % (self.suite_run.definition.name(), self.basename),
-                                     self.path)
-            if self.status == Test.UNKNOWN:
-                 self.set_pass()
-        except Exception as e:
-            if hasattr(e, 'msg'):
-                msg = e.msg
-            else:
-                msg = str(e)
-            if isinstance(e, AssertionError):
-                # AssertionError lacks further information on what was
-                # asserted. Find the line where the code asserted:
-                msg += log.get_src_from_exc_info(sys.exc_info())
-            # add source file information to failure report
-            if hasattr(e, 'origins'):
-                msg += ' [%s]' % e.origins
-            tb_str = traceback.format_exc()
-            if isinstance(e, resource.NoResourceExn):
-                tb_str += self.suite_run.resource_status_str()
-            self.set_fail(type(e).__name__, msg, tb_str, log.get_src_from_exc_info())
-        except BaseException as e:
-            # when the program is aborted by a signal (like Ctrl-C), escalate to abort all.
-            self.err('TEST RUN ABORTED: %s' % type(e).__name__)
-            raise
-        finally:
-            if self.log_target:
-                self.log_target.remove()
-                self.log_target = None
-
-    def name(self):
-        l = log.get_line_for_src(self.path)
-        if l is not None:
-            return '%s:%s' % (self._name, l)
-        return super().name()
-
-    def set_fail(self, fail_type, fail_message, tb_str=None, src=4):
-        self.status = Test.FAIL
-        self.duration = time.time() - self.start_timestamp
-        self.fail_type = fail_type
-        self.fail_message = fail_message
-
-        if tb_str is None:
-            # populate an exception-less call to set_fail() with traceback info
-            tb_str = ''.join(traceback.format_stack()[:-1])
-
-        self.fail_tb = tb_str
-        self.err('%s: %s' % (self.fail_type, self.fail_message), _src=src)
-        if self.fail_tb:
-            self.log(self.fail_tb, _level=log.L_TRACEBACK)
-        self.log('Test FAILED (%.1f sec)' % self.duration)
-
-    def set_pass(self):
-        self.status = Test.PASS
-        self.duration = time.time() - self.start_timestamp
-        self.log('Test passed (%.1f sec)' % self.duration)
-
-    def set_skip(self):
-        self.status = Test.SKIP
-        self.duration = 0
-
-# vim: expandtab tabstop=4 shiftwidth=4
diff --git a/suites/4g/mo_mt_sms.py b/suites/4g/mo_mt_sms.py
new file mode 100755
index 0000000..8aa4357
--- /dev/null
+++ b/suites/4g/mo_mt_sms.py
@@ -0,0 +1,22 @@
+#!/usr/bin/env python3
+from osmo_gsm_tester.testenv import *
+
+#epc = suite.epc()
+#enb = suite.enb()
+ue = suite.modem()
+
+#enb.start()
+#epc.enb_add(enb)
+#epc.start()
+
+#wait(epc.enb_is_connected, enb)
+
+#hss/epc.subscriber_add(ue)
+
+#ue.connect(epc.mcc_mnc())
+ue.connect()
+
+
+print('waiting for modem to attach...')
+#wait(ue.is_connected, msc.mcc_mnc())
+sleep(10)
diff --git a/suites/4g/suite.conf b/suites/4g/suite.conf
new file mode 100644
index 0000000..c55b610
--- /dev/null
+++ b/suites/4g/suite.conf
@@ -0,0 +1,6 @@
+resources:
+  ip_address:
+  - times: 1
+  modem:
+  - times: 1
+    type: srsue
diff --git a/update_version.sh b/update_version.sh
deleted file mode 100755
index 3d5fe42..0000000
--- a/update_version.sh
+++ /dev/null
@@ -1,10 +0,0 @@
-#!/bin/sh
-set -e
-git describe --abbrev=8 --dirty | sed 's/v\([^-]*\)-\([^-]*\)-\(.*\)/\1.dev\2.\3/' > version
-cat version
-echo "# osmo-gsm-tester version.
-# Automatically generated by update_version.sh.
-# Gets imported by __init__.py.
-
-_version = '$(cat version)'" \
-  > src/osmo_gsm_tester/_version.py

-- 
To view, visit https://gerrit.osmocom.org/c/osmo-gsm-tester/+/17067
To unsubscribe, or for help writing mail filters, visit https://gerrit.osmocom.org/settings

Gerrit-Project: osmo-gsm-tester
Gerrit-Branch: master
Gerrit-Change-Id: Id9d63920a44a80af187e649c9be5fd7498fa5f44
Gerrit-Change-Number: 17067
Gerrit-PatchSet: 1
Gerrit-Owner: pespin <pespin at sysmocom.de>
Gerrit-MessageType: newchange
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.osmocom.org/pipermail/gerrit-log/attachments/20200129/04c4b605/attachment.htm>


More information about the gerrit-log mailing list