Message ID | 20220428122848.3941460-1-sumit.garg@linaro.org |
---|---|
State | New |
Headers | show |
Series | [1/2] external-arm-toolchain-versions: Use ldd to get libc version | expand |
On Thu, Apr 28, 2022 at 05:58:47PM +0530, Sumit Garg wrote: > Arm GCC 11.2 binary release has moved away from keeping libc library > versioning info as libc-{EAT_VER_LIBC}.so. So rather switch to > retrieving libc version by parsing output from "$ ldd --version". > > Signed-off-by: Sumit Garg <sumit.garg@linaro.org> > --- > .../external-arm-toolchain-versions.inc | 43 ++++++++----------- > 1 file changed, 17 insertions(+), 26 deletions(-) > > diff --git a/meta-arm-toolchain/conf/distro/include/external-arm-toolchain-versions.inc b/meta-arm-toolchain/conf/distro/include/external-arm-toolchain-versions.inc > index a89f2f0..388987a 100644 > --- a/meta-arm-toolchain/conf/distro/include/external-arm-toolchain-versions.inc > +++ b/meta-arm-toolchain/conf/distro/include/external-arm-toolchain-versions.inc > @@ -50,37 +50,28 @@ def eat_get_gcc_version(d): > > def eat_get_libc_version(d): > import os,bb > + import subprocess > + > syspath = bb.data.expand('${EXTERNAL_TOOLCHAIN}/${EAT_TARGET_SYS}', d) > if not syspath: > return 'UNKNOWN' > > - libpath = syspath + '/libc/' + bb.data.expand('${EAT_LIBDIR}/${EAT_TARGET_SYS}/', d) > - > - if os.path.exists(libpath): > - for file in os.listdir(libpath): > - if file.find('libc-') == 0: > - return file[5:-3] > - > - libpath = syspath + '/libc/' + bb.data.expand('${EAT_LIBDIR}/', d) > - > - if os.path.exists(libpath): > - for file in os.listdir(libpath): > - if file.find('libc-') == 0: > - return file[5:-3] > - > - libpath = syspath + '/libc/usr/' + bb.data.expand('${EAT_LIBDIR}/${EAT_TARGET_SYS}/', d) > - > - if os.path.exists(libpath): > - for file in os.listdir(libpath): > - if file.find('libc-') == 0: > - return file[5:-3] > - > - libpath = syspath + '/libc/usr/' + bb.data.expand('${EAT_LIBDIR}/', d) > + topdir = d.getVar('TOPDIR', True) > + lddpath = syspath + '/libc/usr/bin/ldd' > + > + if os.path.exists(lddpath): > + cmd1 = 'sed -i -e \'s#/usr/bin/bash#/bin/bash#\' ' + lddpath Are you trying to sed-in-place ldd executable, which is relative to ${EXTERNAL_TOOLCHAIN} that can be installed system-wide w/o necessary permissions? > + cmd2 = lddpath + ' --version' > + try: > + stdout, stderr = bb.process.run(cmd1, cwd=topdir, stderr=subprocess.PIPE) > + stdout, stderr = bb.process.run(cmd2, cwd=topdir, stderr=subprocess.PIPE) > + except bb.process.CmdError as exc: > + bb.error('Failed to obtain external Arm libc version: %s' % exc) > + return 'UNKNOWN' > + else: > + first_line = stdout.splitlines()[0] > + return first_line.split()[2] > > - if os.path.exists(libpath): > - for file in os.listdir(libpath): > - if file.find('libc-') == 0: > - return file[5:-3] > return 'UNKNOWN' > > def eat_get_kernel_version(d): > -- > 2.17.1 >
Sumit, It passes my CI. Can you answer Denys's question below? WE're going to cut the branch tomorrow, and I'd really like to get this in. However, if it's not ready, we'll push it to the next release. Thanks, Jon On Thu, Apr 28, 2022 at 10:00:01AM -0400, Denys Dmytriyenko wrote: > On Thu, Apr 28, 2022 at 05:58:47PM +0530, Sumit Garg wrote: > > Arm GCC 11.2 binary release has moved away from keeping libc library > > versioning info as libc-{EAT_VER_LIBC}.so. So rather switch to > > retrieving libc version by parsing output from "$ ldd --version". > > > > Signed-off-by: Sumit Garg <sumit.garg@linaro.org> > > --- > > .../external-arm-toolchain-versions.inc | 43 ++++++++----------- > > 1 file changed, 17 insertions(+), 26 deletions(-) > > > > diff --git a/meta-arm-toolchain/conf/distro/include/external-arm-toolchain-versions.inc b/meta-arm-toolchain/conf/distro/include/external-arm-toolchain-versions.inc > > index a89f2f0..388987a 100644 > > --- a/meta-arm-toolchain/conf/distro/include/external-arm-toolchain-versions.inc > > +++ b/meta-arm-toolchain/conf/distro/include/external-arm-toolchain-versions.inc > > @@ -50,37 +50,28 @@ def eat_get_gcc_version(d): > > > > def eat_get_libc_version(d): > > import os,bb > > + import subprocess > > + > > syspath = bb.data.expand('${EXTERNAL_TOOLCHAIN}/${EAT_TARGET_SYS}', d) > > if not syspath: > > return 'UNKNOWN' > > > > - libpath = syspath + '/libc/' + bb.data.expand('${EAT_LIBDIR}/${EAT_TARGET_SYS}/', d) > > - > > - if os.path.exists(libpath): > > - for file in os.listdir(libpath): > > - if file.find('libc-') == 0: > > - return file[5:-3] > > - > > - libpath = syspath + '/libc/' + bb.data.expand('${EAT_LIBDIR}/', d) > > - > > - if os.path.exists(libpath): > > - for file in os.listdir(libpath): > > - if file.find('libc-') == 0: > > - return file[5:-3] > > - > > - libpath = syspath + '/libc/usr/' + bb.data.expand('${EAT_LIBDIR}/${EAT_TARGET_SYS}/', d) > > - > > - if os.path.exists(libpath): > > - for file in os.listdir(libpath): > > - if file.find('libc-') == 0: > > - return file[5:-3] > > - > > - libpath = syspath + '/libc/usr/' + bb.data.expand('${EAT_LIBDIR}/', d) > > + topdir = d.getVar('TOPDIR', True) > > + lddpath = syspath + '/libc/usr/bin/ldd' > > + > > + if os.path.exists(lddpath): > > + cmd1 = 'sed -i -e \'s#/usr/bin/bash#/bin/bash#\' ' + lddpath > > Are you trying to sed-in-place ldd executable, which is relative to > ${EXTERNAL_TOOLCHAIN} that can be installed system-wide w/o necessary > permissions? > > > > + cmd2 = lddpath + ' --version' > > + try: > > + stdout, stderr = bb.process.run(cmd1, cwd=topdir, stderr=subprocess.PIPE) > > + stdout, stderr = bb.process.run(cmd2, cwd=topdir, stderr=subprocess.PIPE) > > + except bb.process.CmdError as exc: > > + bb.error('Failed to obtain external Arm libc version: %s' % exc) > > + return 'UNKNOWN' > > + else: > > + first_line = stdout.splitlines()[0] > > + return first_line.split()[2] > > > > - if os.path.exists(libpath): > > - for file in os.listdir(libpath): > > - if file.find('libc-') == 0: > > - return file[5:-3] > > return 'UNKNOWN' > > > > def eat_get_kernel_version(d): > > -- > > 2.17.1 > > > > -- > Regards, > Denys Dmytriyenko <denis@denix.org> > PGP: 0x420902729A92C964 - https://denix.org/0x420902729A92C964 > Fingerprint: 25FC E4A5 8A72 2F69 1186 6D76 4209 0272 9A92 C964 >
On Thu, Apr 28, 2022 at 03:03:16PM -0400, Jon Mason wrote: > Sumit, > It passes my CI. Can you answer Denys's question below? > > WE're going to cut the branch tomorrow, and I'd really like to get > this in. However, if it's not ready, we'll push it to the next > release. > > Thanks, > Jon > > On Thu, Apr 28, 2022 at 10:00:01AM -0400, Denys Dmytriyenko wrote: > > On Thu, Apr 28, 2022 at 05:58:47PM +0530, Sumit Garg wrote: > > > Arm GCC 11.2 binary release has moved away from keeping libc library > > > versioning info as libc-{EAT_VER_LIBC}.so. So rather switch to > > > retrieving libc version by parsing output from "$ ldd --version". > > > > > > Signed-off-by: Sumit Garg <sumit.garg@linaro.org> > > > --- > > > .../external-arm-toolchain-versions.inc | 43 ++++++++----------- > > > 1 file changed, 17 insertions(+), 26 deletions(-) > > > > > > diff --git a/meta-arm-toolchain/conf/distro/include/external-arm-toolchain-versions.inc b/meta-arm-toolchain/conf/distro/include/external-arm-toolchain-versions.inc > > > index a89f2f0..388987a 100644 > > > --- a/meta-arm-toolchain/conf/distro/include/external-arm-toolchain-versions.inc > > > +++ b/meta-arm-toolchain/conf/distro/include/external-arm-toolchain-versions.inc > > > @@ -50,37 +50,28 @@ def eat_get_gcc_version(d): > > > > > > def eat_get_libc_version(d): > > > import os,bb > > > + import subprocess > > > + > > > syspath = bb.data.expand('${EXTERNAL_TOOLCHAIN}/${EAT_TARGET_SYS}', d) > > > if not syspath: > > > return 'UNKNOWN' > > > > > > - libpath = syspath + '/libc/' + bb.data.expand('${EAT_LIBDIR}/${EAT_TARGET_SYS}/', d) > > > - > > > - if os.path.exists(libpath): > > > - for file in os.listdir(libpath): > > > - if file.find('libc-') == 0: > > > - return file[5:-3] > > > - > > > - libpath = syspath + '/libc/' + bb.data.expand('${EAT_LIBDIR}/', d) > > > - > > > - if os.path.exists(libpath): > > > - for file in os.listdir(libpath): > > > - if file.find('libc-') == 0: > > > - return file[5:-3] > > > - > > > - libpath = syspath + '/libc/usr/' + bb.data.expand('${EAT_LIBDIR}/${EAT_TARGET_SYS}/', d) > > > - > > > - if os.path.exists(libpath): > > > - for file in os.listdir(libpath): > > > - if file.find('libc-') == 0: > > > - return file[5:-3] > > > - > > > - libpath = syspath + '/libc/usr/' + bb.data.expand('${EAT_LIBDIR}/', d) > > > + topdir = d.getVar('TOPDIR', True) > > > + lddpath = syspath + '/libc/usr/bin/ldd' > > > + > > > + if os.path.exists(lddpath): > > > + cmd1 = 'sed -i -e \'s#/usr/bin/bash#/bin/bash#\' ' + lddpath Running an executable from a target sysroot is also questionable, but since it's a shell script and only used to print the version, is probably Ok. > > Are you trying to sed-in-place ldd executable, which is relative to > > ${EXTERNAL_TOOLCHAIN} that can be installed system-wide w/o necessary > > permissions? The way to bypass the bad shebang is to call the interpreter directly (and it's not bash specific, so /bin/sh should work): $ /bin/sh $syspath/libc/usr/bin/ldd --version In previous releases, ldd came with even more weird shebang, e.g.: #! /arm/tools/gnu/bash/4.2/rhe6-x86_64/bin/bash All that gets corrected in do_install() of external-arm-toolchain.bb anyway. > > > + cmd2 = lddpath + ' --version' > > > + try: > > > + stdout, stderr = bb.process.run(cmd1, cwd=topdir, stderr=subprocess.PIPE) > > > + stdout, stderr = bb.process.run(cmd2, cwd=topdir, stderr=subprocess.PIPE) > > > + except bb.process.CmdError as exc: > > > + bb.error('Failed to obtain external Arm libc version: %s' % exc) > > > + return 'UNKNOWN' > > > + else: > > > + first_line = stdout.splitlines()[0] > > > + return first_line.split()[2] > > > > > > - if os.path.exists(libpath): > > > - for file in os.listdir(libpath): > > > - if file.find('libc-') == 0: > > > - return file[5:-3] > > > return 'UNKNOWN' > > > > > > def eat_get_kernel_version(d): > > > -- > > > 2.17.1
On Fri, 29 Apr 2022 at 00:46, Denys Dmytriyenko <denis@denix.org> wrote: > > On Thu, Apr 28, 2022 at 03:03:16PM -0400, Jon Mason wrote: > > Sumit, > > It passes my CI. Can you answer Denys's question below? > > > > WE're going to cut the branch tomorrow, and I'd really like to get > > this in. However, if it's not ready, we'll push it to the next > > release. > > > > Thanks, > > Jon > > > > On Thu, Apr 28, 2022 at 10:00:01AM -0400, Denys Dmytriyenko wrote: > > > On Thu, Apr 28, 2022 at 05:58:47PM +0530, Sumit Garg wrote: > > > > Arm GCC 11.2 binary release has moved away from keeping libc library > > > > versioning info as libc-{EAT_VER_LIBC}.so. So rather switch to > > > > retrieving libc version by parsing output from "$ ldd --version". > > > > > > > > Signed-off-by: Sumit Garg <sumit.garg@linaro.org> > > > > --- > > > > .../external-arm-toolchain-versions.inc | 43 ++++++++----------- > > > > 1 file changed, 17 insertions(+), 26 deletions(-) > > > > > > > > diff --git a/meta-arm-toolchain/conf/distro/include/external-arm-toolchain-versions.inc b/meta-arm-toolchain/conf/distro/include/external-arm-toolchain-versions.inc > > > > index a89f2f0..388987a 100644 > > > > --- a/meta-arm-toolchain/conf/distro/include/external-arm-toolchain-versions.inc > > > > +++ b/meta-arm-toolchain/conf/distro/include/external-arm-toolchain-versions.inc > > > > @@ -50,37 +50,28 @@ def eat_get_gcc_version(d): > > > > > > > > def eat_get_libc_version(d): > > > > import os,bb > > > > + import subprocess > > > > + > > > > syspath = bb.data.expand('${EXTERNAL_TOOLCHAIN}/${EAT_TARGET_SYS}', d) > > > > if not syspath: > > > > return 'UNKNOWN' > > > > > > > > - libpath = syspath + '/libc/' + bb.data.expand('${EAT_LIBDIR}/${EAT_TARGET_SYS}/', d) > > > > - > > > > - if os.path.exists(libpath): > > > > - for file in os.listdir(libpath): > > > > - if file.find('libc-') == 0: > > > > - return file[5:-3] > > > > - > > > > - libpath = syspath + '/libc/' + bb.data.expand('${EAT_LIBDIR}/', d) > > > > - > > > > - if os.path.exists(libpath): > > > > - for file in os.listdir(libpath): > > > > - if file.find('libc-') == 0: > > > > - return file[5:-3] > > > > - > > > > - libpath = syspath + '/libc/usr/' + bb.data.expand('${EAT_LIBDIR}/${EAT_TARGET_SYS}/', d) > > > > - > > > > - if os.path.exists(libpath): > > > > - for file in os.listdir(libpath): > > > > - if file.find('libc-') == 0: > > > > - return file[5:-3] > > > > - > > > > - libpath = syspath + '/libc/usr/' + bb.data.expand('${EAT_LIBDIR}/', d) > > > > + topdir = d.getVar('TOPDIR', True) > > > > + lddpath = syspath + '/libc/usr/bin/ldd' > > > > + > > > > + if os.path.exists(lddpath): > > > > + cmd1 = 'sed -i -e \'s#/usr/bin/bash#/bin/bash#\' ' + lddpath > > Running an executable from a target sysroot is also questionable, but since > it's a shell script and only used to print the version, is probably Ok. > Yeah this was the sanest way I could find to retrieve libc version that will work for all binary toolchain releases. > > > > Are you trying to sed-in-place ldd executable, which is relative to > > > ${EXTERNAL_TOOLCHAIN} that can be installed system-wide w/o necessary > > > permissions? > Ah, you are right there could be a permissions issue. > The way to bypass the bad shebang is to call the interpreter directly (and > it's not bash specific, so /bin/sh should work): > > $ /bin/sh $syspath/libc/usr/bin/ldd --version > Will use this instead in v2. > In previous releases, ldd came with even more weird shebang, e.g.: > > #! /arm/tools/gnu/bash/4.2/rhe6-x86_64/bin/bash > > All that gets corrected in do_install() of external-arm-toolchain.bb anyway. > Yeah. -Sumit > > > > > + cmd2 = lddpath + ' --version' > > > > + try: > > > > + stdout, stderr = bb.process.run(cmd1, cwd=topdir, stderr=subprocess.PIPE) > > > > + stdout, stderr = bb.process.run(cmd2, cwd=topdir, stderr=subprocess.PIPE) > > > > + except bb.process.CmdError as exc: > > > > + bb.error('Failed to obtain external Arm libc version: %s' % exc) > > > > + return 'UNKNOWN' > > > > + else: > > > > + first_line = stdout.splitlines()[0] > > > > + return first_line.split()[2] > > > > > > > > - if os.path.exists(libpath): > > > > - for file in os.listdir(libpath): > > > > - if file.find('libc-') == 0: > > > > - return file[5:-3] > > > > return 'UNKNOWN' > > > > > > > > def eat_get_kernel_version(d): > > > > -- > > > > 2.17.1 > > -- > Regards, > Denys Dmytriyenko <denis@denix.org> > PGP: 0x420902729A92C964 - https://denix.org/0x420902729A92C964 > Fingerprint: 25FC E4A5 8A72 2F69 1186 6D76 4209 0272 9A92 C964
Hi Jon, On Fri, 29 Apr 2022 at 00:33, Jon Mason <jdmason@kudzu.us> wrote: > > Sumit, > It passes my CI. Can you answer Denys's question below? > I have incorporated Denys's suggestion in v2. > WE're going to cut the branch tomorrow, and I'd really like to get > this in. However, if it's not ready, we'll push it to the next > release. I think v2 should be ready to go in. I have tested different poky build combinations using gcc11 and gcc10 binary releases for Arm 32bit and 64bit Qemu targets. -Sumit > > Thanks, > Jon > > On Thu, Apr 28, 2022 at 10:00:01AM -0400, Denys Dmytriyenko wrote: > > On Thu, Apr 28, 2022 at 05:58:47PM +0530, Sumit Garg wrote: > > > Arm GCC 11.2 binary release has moved away from keeping libc library > > > versioning info as libc-{EAT_VER_LIBC}.so. So rather switch to > > > retrieving libc version by parsing output from "$ ldd --version". > > > > > > Signed-off-by: Sumit Garg <sumit.garg@linaro.org> > > > --- > > > .../external-arm-toolchain-versions.inc | 43 ++++++++----------- > > > 1 file changed, 17 insertions(+), 26 deletions(-) > > > > > > diff --git a/meta-arm-toolchain/conf/distro/include/external-arm-toolchain-versions.inc b/meta-arm-toolchain/conf/distro/include/external-arm-toolchain-versions.inc > > > index a89f2f0..388987a 100644 > > > --- a/meta-arm-toolchain/conf/distro/include/external-arm-toolchain-versions.inc > > > +++ b/meta-arm-toolchain/conf/distro/include/external-arm-toolchain-versions.inc > > > @@ -50,37 +50,28 @@ def eat_get_gcc_version(d): > > > > > > def eat_get_libc_version(d): > > > import os,bb > > > + import subprocess > > > + > > > syspath = bb.data.expand('${EXTERNAL_TOOLCHAIN}/${EAT_TARGET_SYS}', d) > > > if not syspath: > > > return 'UNKNOWN' > > > > > > - libpath = syspath + '/libc/' + bb.data.expand('${EAT_LIBDIR}/${EAT_TARGET_SYS}/', d) > > > - > > > - if os.path.exists(libpath): > > > - for file in os.listdir(libpath): > > > - if file.find('libc-') == 0: > > > - return file[5:-3] > > > - > > > - libpath = syspath + '/libc/' + bb.data.expand('${EAT_LIBDIR}/', d) > > > - > > > - if os.path.exists(libpath): > > > - for file in os.listdir(libpath): > > > - if file.find('libc-') == 0: > > > - return file[5:-3] > > > - > > > - libpath = syspath + '/libc/usr/' + bb.data.expand('${EAT_LIBDIR}/${EAT_TARGET_SYS}/', d) > > > - > > > - if os.path.exists(libpath): > > > - for file in os.listdir(libpath): > > > - if file.find('libc-') == 0: > > > - return file[5:-3] > > > - > > > - libpath = syspath + '/libc/usr/' + bb.data.expand('${EAT_LIBDIR}/', d) > > > + topdir = d.getVar('TOPDIR', True) > > > + lddpath = syspath + '/libc/usr/bin/ldd' > > > + > > > + if os.path.exists(lddpath): > > > + cmd1 = 'sed -i -e \'s#/usr/bin/bash#/bin/bash#\' ' + lddpath > > > > Are you trying to sed-in-place ldd executable, which is relative to > > ${EXTERNAL_TOOLCHAIN} that can be installed system-wide w/o necessary > > permissions? > > > > > > > + cmd2 = lddpath + ' --version' > > > + try: > > > + stdout, stderr = bb.process.run(cmd1, cwd=topdir, stderr=subprocess.PIPE) > > > + stdout, stderr = bb.process.run(cmd2, cwd=topdir, stderr=subprocess.PIPE) > > > + except bb.process.CmdError as exc: > > > + bb.error('Failed to obtain external Arm libc version: %s' % exc) > > > + return 'UNKNOWN' > > > + else: > > > + first_line = stdout.splitlines()[0] > > > + return first_line.split()[2] > > > > > > - if os.path.exists(libpath): > > > - for file in os.listdir(libpath): > > > - if file.find('libc-') == 0: > > > - return file[5:-3] > > > return 'UNKNOWN' > > > > > > def eat_get_kernel_version(d): > > > -- > > > 2.17.1 > > > > > > > -- > > Regards, > > Denys Dmytriyenko <denis@denix.org> > > PGP: 0x420902729A92C964 - https://denix.org/0x420902729A92C964 > > Fingerprint: 25FC E4A5 8A72 2F69 1186 6D76 4209 0272 9A92 C964 > >
diff --git a/meta-arm-toolchain/conf/distro/include/external-arm-toolchain-versions.inc b/meta-arm-toolchain/conf/distro/include/external-arm-toolchain-versions.inc index a89f2f0..388987a 100644 --- a/meta-arm-toolchain/conf/distro/include/external-arm-toolchain-versions.inc +++ b/meta-arm-toolchain/conf/distro/include/external-arm-toolchain-versions.inc @@ -50,37 +50,28 @@ def eat_get_gcc_version(d): def eat_get_libc_version(d): import os,bb + import subprocess + syspath = bb.data.expand('${EXTERNAL_TOOLCHAIN}/${EAT_TARGET_SYS}', d) if not syspath: return 'UNKNOWN' - libpath = syspath + '/libc/' + bb.data.expand('${EAT_LIBDIR}/${EAT_TARGET_SYS}/', d) - - if os.path.exists(libpath): - for file in os.listdir(libpath): - if file.find('libc-') == 0: - return file[5:-3] - - libpath = syspath + '/libc/' + bb.data.expand('${EAT_LIBDIR}/', d) - - if os.path.exists(libpath): - for file in os.listdir(libpath): - if file.find('libc-') == 0: - return file[5:-3] - - libpath = syspath + '/libc/usr/' + bb.data.expand('${EAT_LIBDIR}/${EAT_TARGET_SYS}/', d) - - if os.path.exists(libpath): - for file in os.listdir(libpath): - if file.find('libc-') == 0: - return file[5:-3] - - libpath = syspath + '/libc/usr/' + bb.data.expand('${EAT_LIBDIR}/', d) + topdir = d.getVar('TOPDIR', True) + lddpath = syspath + '/libc/usr/bin/ldd' + + if os.path.exists(lddpath): + cmd1 = 'sed -i -e \'s#/usr/bin/bash#/bin/bash#\' ' + lddpath + cmd2 = lddpath + ' --version' + try: + stdout, stderr = bb.process.run(cmd1, cwd=topdir, stderr=subprocess.PIPE) + stdout, stderr = bb.process.run(cmd2, cwd=topdir, stderr=subprocess.PIPE) + except bb.process.CmdError as exc: + bb.error('Failed to obtain external Arm libc version: %s' % exc) + return 'UNKNOWN' + else: + first_line = stdout.splitlines()[0] + return first_line.split()[2] - if os.path.exists(libpath): - for file in os.listdir(libpath): - if file.find('libc-') == 0: - return file[5:-3] return 'UNKNOWN' def eat_get_kernel_version(d):
Arm GCC 11.2 binary release has moved away from keeping libc library versioning info as libc-{EAT_VER_LIBC}.so. So rather switch to retrieving libc version by parsing output from "$ ldd --version". Signed-off-by: Sumit Garg <sumit.garg@linaro.org> --- .../external-arm-toolchain-versions.inc | 43 ++++++++----------- 1 file changed, 17 insertions(+), 26 deletions(-)