From bc32a618d3edec90b53c46c11d57e9c2b2ff5a36 Mon Sep 17 00:00:00 2001 From: Ken Odegard Date: Tue, 17 Oct 2023 16:30:06 -0500 Subject: [PATCH 01/11] Deprecate is_string --- conda_build/os_utils/liefldd.py | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/conda_build/os_utils/liefldd.py b/conda_build/os_utils/liefldd.py index 2cf6ce92ad..a4962628a8 100644 --- a/conda_build/os_utils/liefldd.py +++ b/conda_build/os_utils/liefldd.py @@ -15,6 +15,7 @@ from functools import partial from subprocess import PIPE, Popen +from ..deprecations import deprecated from .external import find_executable # lief cannot handle files it doesn't know about gracefully @@ -34,11 +35,9 @@ pass +@deprecated("3.28.0", "4.0.0", addendum="Use `isinstance(value, str)` instead.") def is_string(s): - try: - return isinstance(s, basestring) - except NameError: - return isinstance(s, str) + return isinstance(s, str) # Some functions can operate on either file names @@ -47,7 +46,7 @@ def is_string(s): # should be passed a binary when possible as that # will prevent having to parse it multiple times. def ensure_binary(file): - if not is_string(file): + if not isinstance(file, str): return file else: try: @@ -111,7 +110,9 @@ def get_libraries(file): if binary.format == lief.EXE_FORMATS.PE: result = binary.libraries else: - result = [lib if is_string(lib) else lib.name for lib in binary.libraries] + result = [ + lib if isinstance(lib, str) else lib.name for lib in binary.libraries + ] # LIEF returns LC_ID_DYLIB name @rpath/libbz2.dylib in binary.libraries. Strip that. binary_name = None if binary.format == lief.EXE_FORMATS.MACHO: From bc25d263a96657f656d46aabc942907955cd8dca Mon Sep 17 00:00:00 2001 From: Ken Odegard Date: Tue, 17 Oct 2023 16:31:25 -0500 Subject: [PATCH 02/11] Cleanup is_codefile --- conda_build/os_utils/pyldd.py | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/conda_build/os_utils/pyldd.py b/conda_build/os_utils/pyldd.py index 1e1cd4e4cc..7db73abd95 100644 --- a/conda_build/os_utils/pyldd.py +++ b/conda_build/os_utils/pyldd.py @@ -1,5 +1,7 @@ # Copyright (C) 2014 Anaconda, Inc # SPDX-License-Identifier: BSD-3-Clause +from __future__ import annotations + import argparse import glob import logging @@ -7,9 +9,12 @@ import re import struct import sys +from pathlib import Path from conda_build.utils import ensure_list, get_logger +from ..deprecations import deprecated + logging.basicConfig(level=logging.INFO) @@ -1055,11 +1060,9 @@ def codefile_class(filename, skip_symlinks=False): return None -def is_codefile(filename, skip_symlinks=True): - klass = codefile_class(filename, skip_symlinks=skip_symlinks) - if not klass: - return False - return True +@deprecated.argument("3.28.0", "4.0.0", "filename", rename="path") +def is_codefile(path: str | os.PathLike | Path, skip_symlinks: bool = True) -> bool: + return bool(codefile_class(path, skip_symlinks=skip_symlinks)) def codefile_type(filename, skip_symlinks=True): From 7dbb33f63e45ef3a537b6f78bcd9c63e0d3245ef Mon Sep 17 00:00:00 2001 From: Ken Odegard Date: Tue, 17 Oct 2023 17:16:43 -0500 Subject: [PATCH 03/11] Add codefile_class unittest --- conda_build/utils.py | 3 +- tests/os_utils/test_liefldd.py | 53 ++++++++++++++++++++++++++++++++++ tests/os_utils/test_pyldd.py | 53 ++++++++++++++++++++++++++++++++++ 3 files changed, 108 insertions(+), 1 deletion(-) create mode 100644 tests/os_utils/test_liefldd.py create mode 100644 tests/os_utils/test_pyldd.py diff --git a/conda_build/utils.py b/conda_build/utils.py index 06a5c79c6d..f8606ffe9d 100644 --- a/conda_build/utils.py +++ b/conda_build/utils.py @@ -97,9 +97,10 @@ FileNotFoundError = FileNotFoundError on_win = sys.platform == "win32" +on_mac = sys.platform == "darwin" +on_linux = sys.platform == "linux" codec = getpreferredencoding() or "utf-8" -on_win = sys.platform == "win32" root_script_dir = os.path.join(root_dir, "Scripts" if on_win else "bin") mmap_MAP_PRIVATE = 0 if on_win else mmap.MAP_PRIVATE mmap_PROT_READ = 0 if on_win else mmap.PROT_READ diff --git a/tests/os_utils/test_liefldd.py b/tests/os_utils/test_liefldd.py new file mode 100644 index 0000000000..2d88b8b0d6 --- /dev/null +++ b/tests/os_utils/test_liefldd.py @@ -0,0 +1,53 @@ +# Copyright (C) 2014 Anaconda, Inc +# SPDX-License-Identifier: BSD-3-Clause +from __future__ import annotations + +from pathlib import Path + +import pytest + +from conda_build.os_utils.liefldd import ( + DLLfile, + EXEfile, + codefile_class, + elffile, + machofile, +) + + +@pytest.mark.parametrize( + "path,expect", + [ + pytest.param(__file__, None, id="None"), + pytest.param( + Path(__file__).parent.parent / "test-recipes" / "dll-package" / "jansi.dll", + DLLfile, + id="DLL[.dll]", + ), + pytest.param( + Path(__file__).parent.parent / "data" / "ldd" / "uuid.pyd", + DLLfile, + id="DLL[.pyd]", + ), + pytest.param( + Path(__file__).parent.parent / "data" / "ldd" / "clear.exe", + EXEfile, + id="EXE", + ), + pytest.param( + Path(__file__).parent.parent / "data" / "ldd" / "clear-mach-o", + machofile, + id="Mach-O", + ), + pytest.param( + Path(__file__).parent.parent / "data" / "ldd" / "clear-elf", + elffile, + id="ELF", + ), + ], +) +def test_codefile_class( + path: str | Path, + expect: type[DLLfile | EXEfile | machofile | elffile] | None, +): + assert codefile_class(path) == expect diff --git a/tests/os_utils/test_pyldd.py b/tests/os_utils/test_pyldd.py new file mode 100644 index 0000000000..4f9eba602e --- /dev/null +++ b/tests/os_utils/test_pyldd.py @@ -0,0 +1,53 @@ +# Copyright (C) 2014 Anaconda, Inc +# SPDX-License-Identifier: BSD-3-Clause +from __future__ import annotations + +from pathlib import Path + +import pytest + +from conda_build.os_utils.pyldd import ( + DLLfile, + EXEfile, + codefile_class, + elffile, + machofile, +) + + +@pytest.mark.parametrize( + "path,expect", + [ + pytest.param(__file__, None, id="None"), + pytest.param( + Path(__file__).parent.parent / "test-recipes" / "dll-package" / "jansi.dll", + DLLfile, + id="DLL[.dll]", + ), + pytest.param( + Path(__file__).parent.parent / "data" / "ldd" / "uuid.pyd", + DLLfile, + id="DLL[.pyd]", + ), + pytest.param( + Path(__file__).parent.parent / "data" / "ldd" / "clear.exe", + EXEfile, + id="EXE", + ), + pytest.param( + Path(__file__).parent.parent / "data" / "ldd" / "clear-mach-o", + machofile, + id="Mach-O", + ), + pytest.param( + Path(__file__).parent.parent / "data" / "ldd" / "clear-elf", + elffile, + id="ELF", + ), + ], +) +def test_codefile_class( + path: str | Path, + expect: type[DLLfile | EXEfile | machofile | elffile] | None, +): + assert codefile_class(path) == expect From bb4668de43dcbb0c0f05b4b92e76a2a1b12be58b Mon Sep 17 00:00:00 2001 From: Ken Odegard Date: Tue, 17 Oct 2023 20:17:30 -0500 Subject: [PATCH 04/11] Add unittest for codefile_class --- tests/data/ldd/clear.elf | Bin 0 -> 10168 bytes tests/data/ldd/clear.exe | Bin 0 -> 9839 bytes tests/data/ldd/clear.macho | Bin 0 -> 68448 bytes tests/data/ldd/jansi.dll | Bin 0 -> 20480 bytes tests/data/ldd/uuid.pyd | Bin 0 -> 12800 bytes tests/os_utils/test_codefile.py | 40 ++++++++++++++++++++++++ tests/os_utils/test_liefldd.py | 53 -------------------------------- tests/os_utils/test_pyldd.py | 53 -------------------------------- 8 files changed, 40 insertions(+), 106 deletions(-) create mode 100755 tests/data/ldd/clear.elf create mode 100644 tests/data/ldd/clear.exe create mode 100755 tests/data/ldd/clear.macho create mode 100755 tests/data/ldd/jansi.dll create mode 100644 tests/data/ldd/uuid.pyd create mode 100644 tests/os_utils/test_codefile.py delete mode 100644 tests/os_utils/test_liefldd.py delete mode 100644 tests/os_utils/test_pyldd.py diff --git a/tests/data/ldd/clear.elf b/tests/data/ldd/clear.elf new file mode 100755 index 0000000000000000000000000000000000000000..52013aa3ee2ca775bba0418b389cfc1f392825de GIT binary patch literal 10168 zcmeHNZ){xEmA~_zlb9p~C$XJ`g!l~ssib6Lhcs~@i05%&k_w7z3`By}csw(DWPNr;lUHDRkQ_p~peXB+d!#q0^ahn4(|YAUQ|=$dgmRmzZ!>Ig z#M?xK?hgA=2&Q|qyywpW;<5*Ci4toL>3k)NM6RVl$%)n2){WK}$v@;I#R zNp!63iLL2LB>M-}L?Y>E_lEU>Oe)YI`%U&qHuSZJy_U$#9IqrF%^yU5Icq%T|_<5?#!|7N2^`HwiIV#e8szF{vj7pZGb3x~;@=T-} z;7V1&W6%BMv0*)q-6{af7*tdZcM1B}?B^Ndzt)}^p{Y&ljK=Kd5)q0YVdT5lb{2&S z+v^J9)R*Jm{f`A7pZs@ycz}L7y#!W|FV_y1!Knd@g*5sNlxMOtQ3kJqq0;dtb34n( zUspzcHSn3*T~Y@BDeTYG?yY6y?=FL1E@P)q#{X}X!Pl3uPwUD;E=>?ni(whVr>4F0Dw_Zc>iHGCKog&(w4#Q%v2zMru3E}khI~fs1(V?nLJQLm- zPiGRTq^IE|QcI1O}4AiNZj{fmUz4H`?1LU;`Qu?CeV?l1^th+Py<$oLH*g5uKhvNRYRXiln=! z3MNHoq9>kAiOwg}2`7%aIGKi|XBtjHCY6R&oLW&8pWa9!2?W84?x0q}UHy@COh5t- zccz}C!)ybwQB|7punXP4E!Z4h7iichZh5eETWH(Y)&>G}IEw9Gr2jDjG?@+I^ZpF4 zL{I(C=b@&C5%Osr(x*i9DHQ1pvyczu_T#uR#h|SA>ibkZs#U!)RX@J6iD2Qwp{-Or zUerzF`dy_`!}W8%O2hSg>QW8Y&u~k_`QAVc*K0W6D+q7YaJmC=vNfFUES$D#INyn= zu0_N3`^|O@*AMh|4cG5o-5O4@=hUa+`hGj0;rhOs)o}eDcTmIWj>hSThU<5yqZ-cl zN75P7aK2v>eoVvlJ6T@C=}yY&gog9G3Dv!$;p$bvQ#q^Qd{3l`f`-%mmeU0dw-^K+ z*KogvpH=hLz$B!*EvJHp>v6uI;dFQ9G`aiNBa^1cJuk%Y?|KUVh9N`NR~f_oMD=)Eqeg>h7o*!B~vFfc%%ttdZp++iD5hZ9+cxsBnEE`|dNS z^S>W*EpgB3^QIUj9&L>YyEf-P5pr>7bv>C+q|9Z=T>ZC@d-`V~_wi_LuJM(Sd){0z zdd^%tS}?0u3-g}Sbrqrk?>}vI+kH=9`)R8y_@2n(Rj#f@(hOpD7kv58Vi8j=+gdR0 zIc;J9zPgz1^n~;cw71*{mi!d_ekE8dzs|y<8`8X$Hx=JHi{Ga z*jjkWmkW-ETpKpdAx7T>ZlLc4vt~4!4Y}>gcEMb}+CMDqQ6H#{!jd1{$ZgOV-UPjs z$bUc_&Y8A*ewE1m5o3`TV*BrrD|}-6-xZ4oo<|l)S#?jzSKGu2yGGJ1UXjHw$tUsZ z)97d3414ng_?T!HIj^sv_XzQE9-skxr?+Ux>GEo_P9X)BI=t z-apYa^g86R4-W>91>Fu$*O=0!{!H%vl{b$s%@ghr+HUW#H^JstK7{`?ChZ+!)1`T~ zJGuJ}Z;pQiUwJOGKI8|VMW#6^FlYSGd-iO|rFKn>qq031EY##O&m-Q3?Pd{k(t+%| zQSgFn6fl1I+FY$vP}9ie$ATkQqs=3eyWjL;L%vZzL}6*pKOyJQk!!_Q zsV%bYpKrUXVBZh>rMAo2L~O^5EaIBAH`y2$8uM?W4SS1yoZ=j`M6T~6#7)Iua`!Lf zc%rYvkh_F=I(#_fQapHXIJ;Nm9)_;FO1M|en$?>S8>|bg-nzgKLsD#TCP=jQLWDzkUDzwyRqE5CPh!CdmGc(|)*zWk#X6Vj)>;VNP$ z*!E;`17QMnOOWdno}DOeaA%42G`{EHix*3=EEhZ~*DmRkox-f~4T#GijitCK_l9b$ zdx}5JFWQG_@9Ia~H(-7c?ms5SgVyc0!T;W@9i{lu9`H|?t2hn@X}&&dqrD@`u%5lW zXi&Ta zr+#i?ti41x)|t}7nMhasPV3f;^%%V&rIMMy@vd!c_qIMj@@;oMGC(xi6OW{+pwiq2 zrSzS1Eo)7iMdB7Eyu?{fcOqjYl6WnQ#H>`Obqm#!+#{Zd_we4TEcrgSM!nCG$iTEn zEM+BAj^(6xSx(CG9I!IcbgHMP1FuTza(V9^(xJ7n_|CPCvy1(sSHVOw(qqw^SE8fe ziD$g3TQk&I%5#Npxp`L~P`aTJ7^2&1SrN)+&)n(9tC}WvRM2G^!{tbVl_hlHt7AJRnVp6d#Y7b46O7m zpI_%;OMyL(w(GrGDR(={1Hd*b%mTHMUuLE*!tlIC%tPj_FfS~9)k?l z-c%y{dytO;?;%v_ZW}TLwRsSE;!3f&2R@^2%y+2vaLtyX>fy!B`xfnA7(7sQ@P^5KOeHHu7<^#q-UvOyl@T^DX ze)z$ev+tcgd1`@Zn%6eXkP6wo1wOPR&eVTOjg*1yp|OzuwH%sz_`2Xw`)2Q- z6+BRJ&}@Fecoe38J8c_!WW#~ZMU2nmD09E>9Wp`?M$nq(-N(U0^?Kx&AzzPi%%aSF zXuAHUrr}xpDz@%7sU!Cd&Hn1iEgybx_Vk%k?_mf%zu$-60QB^@lZh|V7ZLa(0{_n= zu+a7#e5XoM+GZ$4RDpT=c0-AI`qo2dAMfqL- zIrTf=ijsQXV+IV{tGRrwn4*GJA$k7hGd4%^{H>=&)vM!EyoED~5`UB7y}U-kQ%_Ts z^8DVe_^pc4xkHJ+9W9Zp$X{=JCB`e~NuIwY9aHV|HzaPKsWKz5eS7`mxZ^nW_!D!b zy`tikIdM_(dsIE!`M;*t0_k5V<=<^TuRllBJpH_SpH;qZk@UC9YWl1y|0}s8s-1Gm zN7Va#sJZ!0>r43c_BLx{;Eq6pwXVLQv3_I2I_pcV@tCzW;z)c=L;Y<+3O6Mq(Nr=P zvAUws+pLC$z`8)a5P?iLzP~$>4iUij{CK)g1aP~I2bzN0);N(a5$H zN@jNTN{U|uyc+(=L1)6KOUHX6q@YTDJr3E&4-Ww+K7gn96GkANibb4=2*kU?ooW2m z5$=vbmpQ2sj-=C(T~dR~FdXSkMBzdTwxo@YOhyEvsovgr(kU0c&yLf&r!~dvrqQs$ z;l8B+-j_TO4_<%FFGhjZHtV+;HaNUDD8TZ#=?CvyjNFO>?NzKlVA$Yrk5T~L#VGN9 z#`^}_@uLpc))edW{)hKzFYz6+RA1H#@nsY!2CUEfV~f&nR~sMgpX3U+&->FIz(|Dk zdA}V~8y@ek5b;uJ{O$rudl&2Teziw!&|8%r`_FPrsh;*i=6OFnq4aH~PyUk(`>$Z} zC<@e7)}Pv+)q%kKGq=zB-2aHu4=RJa-{;kVr~6N5N~!)1U=$NRpZNF3O7+p7&lP3f z^Oeg)JCSw$>3vp8wMa7ctePsx!V@66epc<*S=IiV?3mKC6lL-x3c5a@?_1OXTG}4Z zTh{+urO)wiSNmSO(yu1tS}L{oE!2?+>refEPOVfb-6BfcA1cwmP-}aN7nJ_RlJk;E?3f41`vCHjKTO$!xByiO!HJ^z{iXB5a5x4%^BFSVpZ pizHJ|ZkK_7L4jPXXFyTb-&%rmcXY~a>!R(JgH-(A@bxopWl#5j$j)IB+FSh=6pxzT2}8?u*-X z;;3nB^=z8Mvg%T(Q2PUD5$YdA5EV-EgF1xP3Lho74gCPrs4CT2pcWx$Lqu_(cV_Qy z*FY!~sYUWgbMN~+^UlmWA3OWr&i0#TSRG@m9(i$*vBQv*qWt&lKjSDqf9;X;+0V{> z?vlff{^u?k7)j|;zK|O(s2M4)X0tg%8q%b~XjV#PrM~NTNSRzh^ENd#US>8O+r(Jn zjs|wr38IxT3E~ZQx$``y^CH#=@I_=QYc?}Hb3o-7Jo!z@#f_lMAcMSM3!`z3ix$CA zeV$CEiY-M{o@eX;O~^Q7WokUi*k2(2+thqJW3y*z#A|3{2FiCg;D>ypu~Yw+G{|Cu z-h^tX;0_WmA=BKPk8DX%mY?+&gyC)~_aReTmNAogl*OXnys+bAjDjTlRmheUWxl9) zOxR5jA44X)&l9L6Za1Xs#GIl<8YJ!gX`K8^iT3zh=V3$st+v~uJ&Z#y#6k157>9BW z@)~4IB0CFQRzJoJ$i>&&<>{u;&tZxOv1Xh6v;KMi@v>pj$1M7Rnl2ZgYF{8cV@W&Z z(yM!pCB5#oe5WwN=tGi=J1;MPsN%` zf1p}7FC>7;YO$?#khI0N3r*?dvf_V*ue7+>*2v3iSlHLFXs?Dh*z9S({qyCWjAr0@ z#XfncWO1E0@p19aT{|i>Uiyt(`t{H0JSqPbPnSITl6#^DkF8wNqw;k4E=)S6^2>Oj zur!7Wb)WJ>cQ#&S(UcQu)GMCbG<80Vyn#c@}mT1bPmBx<7PWn!!!od zhqi;A+DYxq2!jC_%oX1NpaioB%oMmaS9}Y^mqe%cQrUF)Msl~b5?0uoEh$3NO&4-f zmry>;)oo*P>HDjBMcwC~c$Ml-&72}JIq#l031!N)4xUWTx+mv|F81^{LAoa%qG>4h zTr1E)fuaK4D$oXj`UMIJiZ?3iO61_QYe1lOf&TUyt#;7|RK5$NI}8Pb!UOZQJ;&T@`>0CO zJJk7fOCw)|d=%@k`Cq7p%@Z{@k1WfjSWKQe7^P;XTK;|uMCs5tcQqe~LUS9TeLq?}NW%?uj42hd#|MR60hxXz~a;Ubqvydo8(-(QJ&!C0EaR zj4iC;<{MGj)kgR|a(QZFJ8%=>QvyrCZ{u~o@T9;(J)!EJyu{Zp>gR&4B++wdz-HKidIeh0@Y{uN)36wf$};X=50#%Zi9o~avMa|A0! z%NSXB7|IdMf0y%RTz>|}gS5s7KFS(9E%(;%@m-bM}^%H32C#ad?X)LVkN5JlTX5Ej^ zl4Iz60%aJ>SI}1F@Py>dLeux)9t-@m4T}$vsmEXC<{@Z88{Cy&qo{>v0 zVBqh`7*y#DmVLVAP3Usv_2R-%O#d2}w6~Sx#kLJx^7hJ)zq7bVZ{FiaXtK)t0I_pt z5D%5(q~k3)b@2m$2F`?)cn`J_JGFH+w@()L*R!Pi`mfgG-Rb_teED)-TE`1veEKvQ z%Q$4BlErpPZYSe2DD@x5qPXuqTJAy3+GIlG@AHLD*a(_dpOUoNjKgWskOWKrAePhe z3@p#UXJrO5`hMLr9KY4$@AM|pX{K!5tK6Usr*uOr^rlr^*ZAML>Tos%t14FxE%^`F ze7pTz*xcK@L2BQ8-OekdkhjYlu-9g6x%{&|Kb7^Q_ZEHQi23Nd!gBh|%m4!LK4ki) z6NB7^+yH$L@>j^s&`&_Vh`a{+Dadz`FN2=HfU$2QhoH|ueh;}D`u&g(AV;Aef_xOY z5BeZg#WDjf11Td3krg_49;bzt{J0w4hl{qHLMvr&D(ybksmd5*2EMg zKBg)v?jBMG&P-s~6f`Xh#8^9UMonc&-@z1whf2I)_}Ffyq%!%@f~Ms8GCacKYC4^x z&-ARp5#K+&FO^kNS@fG#)8H<0P*r4Jo3ZO1qQA!-N%Y0o3(icn{)#$^NR@qLy5YJ_{lP$mN74UT za_}n{yf(+}jyd=l@B09r?C{}(?H*_ByZ9nlN!?eEWzy1Kt)QoJ*`8Lv*Vig(*?2CI z$`1Fm?i{$*6KR!n1IwhQb6KsYb-$*!UVT+#H~rTLnf+%RWkD?1L5i6wjrqbH5rdP_WrJKf3(ZGoNwY^$eO4DyotEz9w?#p!a}{$%I+&iMLHPsFGBJ)uCb%hMGe8uCPf316}^;Y+CNxhE2T zGOzw1@{Q750Q8$wb(v`on4$UmM{`cZX$H@<*e? zw%Ku%bX3lgtMK`JIeq91(6ODy6#*{x__aPo0=SU3F=8pq&Y;T9|I0tMy;ZiW|)pqDgO;OURq0SKf;w6{W z(!qeDA^=n~8spJiHMZh0q$p4*hE!@nrNCw&sf=i9Lg94-ijRkZX8DrfQm{+HLqYP` zQc`Kik3|%3PwQ=StC`!)M99}Gm1NfgC8(#vl;HXC5RPOt0B06 zOCnQ2T0-!ul|81d*zwR@05g6zODw^;U@9T9Ks@*ss%2(qBJdV37}cq;{W-9#h;22^ S@m3qMu9>+7L|5W3$G-tkOT@1L literal 0 HcmV?d00001 diff --git a/tests/data/ldd/clear.macho b/tests/data/ldd/clear.macho new file mode 100755 index 0000000000000000000000000000000000000000..8de24d5608beff97f78360325b58e7641533f648 GIT binary patch literal 68448 zcmeI5e{>Yp702JqCLu)BB>YGKF#`k*HYBM0F0>nBYEWw;MA%d7nQS%#*|OQ)?9O5$ zhK?09GvpYg?pZBSa)>Ouu(#Hkl08e_DU^ zocj)U-}k=v?w$8OZ|3n|-fN$n_-=AM%xtZ@etDk&(>6aTFs_F{`qkRCK^UJ!`%y*lWg#0fn zsu~O4Ez8<9!>JbWqd0rXjhR$JUW>%nQCz+-8-W z7u8f$HQ-gFP4zXQfEv~#|1n>?Ib4WD|9K5S`vu89)T&zR)xCWU&iS<``k2rt@{@BR z-&s_(CffHkoW0&e!pv7`3$*96UhCf8zVqXnIoDoYcEucXH_F7&GZ?!qp_^pHQK|n&11hJ!cEEg7+C2=9@f>g=aKT4mRd-54n(|9{q zxcy3XiX<-U*J3*7p;BP<{TIigk>Y^Arnt5#Pz#^RNEppy#eEBU8t$ET!-`Fn72c|i z&rvP~M$Z-!W(6Z{vdoq*fzG5ps}x`hYFO z{HcI#9BVN0y8|I_trk&@nG_Wn$c#bw83m*G>NLdB!Ow*WFaajO1egF5U;<2l2`~XB zzyz286JP>NfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XB zzyz286JP>NfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XB zzyz286JP>NfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XB zzyz286JP>N;ASuvosdue)Ww@Y5r>5|$`xkQ^H++BYaVlD2g zY!^3*E-^t=<|(cNr_lBh`g25lF8ODs2+#aN5hi`imDBdIE4}TAYjE39*O0b%T*KOq z8#yrch}59;^i<_lN)1PazzwMJxwuYrt%4fYlCB-M&n7-bMCxcc+w^Jjy!4b;;S(BT(lnwls?S!Cx> zEalGGFyayDo@d3r&I$?ZmRq}T6Kg2%{$k;&mfc;X3nt5+V=mEk|2UCJ{zHiIqEES4 zOeB8`e46`4)TbBh1jD{uop?TtIWR$ZS`d@|KuN1I6!pMFQ(mfQke=T#Vz+GOO(33l zZYh?*-{}Q1 z+Fe**3ieg%-Pdx=c{292Ww+SjhCYfM_aawZIy0pJKDE=jsJ$8O32|o1GiW3J)V7Mo z%4eq1Sln;gUXbOQUM(kP6%@+Gyo3~=<&{e|`^UJuYSI$3296e8k|b@GQ{%HX?so6! zUU~)QRf_q}ZpA#;(44DM#3W^;xvmoA_2C&C@yxh5GnJkhgs*(wGi4^~!2>(c27?VES>9lwB?$WsGd^z{0`R1BOW6tH^PHX9`cpA*{E|iKj zr|>PA@8aM#d0>1l?z3HsYh))G@nhs%ihBoh?p|5~Cc9gvB1ckFE*dv+r0fxLo}n{s zx?@CN`(B%Fx9Mh^4%>94O;5DxOq=c)Zp&}e?Ka(P(_x#gwCRa9ooUk@xwiZ^-EPy( zmR^%F2tffyu@3AzUE7_7c<^+wg^l|7* zE&UH@oHukYa_+m(2sQLkXuKnaJ`7!E>9?TgS^5oVx;&U-4?xo$;G|!NUS{dnpzpTy ztI+E#{Sx$pmVN;m-?b6@Ec7l*C!h~odMES;mVN@7E==|XG;c&ymCgO3sG2dqQCuJO zF4ATwbO_ECZ=mqF)m6GWEmo( z!VH^{p(qoo6w0hniA6O2d%hEJcR~uVFFBm2`~XB zzyz286JP>NfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XB zzyz286JP>NfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1io1UgO&^9uLL}P zi&;Ns)wx!CzEw}O>X}wuZq-#*U2W9?t8TRF6;|DB)qAb{_gQ|6Rd2KEx2^tTR^4gU z!s<`bN;v#vJJ(Er2`~XBzyz286JP>NfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)Aj zFaajO1egF5U;<2l2`~XBzyz286JP>NfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)Aj zFaajO1pXfhWQ`To!%D6bS#H%Ai>SI5sTbEpGMlsAs;WlyS}hU@i}9MfE3vrF; zjOvlz<;5j5=srButLsMion{N7k}b^=vgm${K_oqVozZ|t8qe5BUM#Aq*0fuazU~kC z^Z){kBB^S99RO**n69aHnwNOz$lum?vGYSIE?;wxl(JVYq&be2gqVqXc9}Po{1n*v zQYJ~`?^5KNb?-gwR7*E{?r4j+G>qTlmZIQ)AY z{#u8BpTqyH!*6r=TOIzB4u6;F_pbj{NB=>Gf7Ic>?}$I`@Vgy;8lGhSLkCK>>Gbj> zK^r>&mJS;T%YdB&8w5KSb{_0}814FC*bvxI*f3ZQjNXCauo1A4unS-=7`-cLuq;?M zY!vLPdLB}XFZ$AON}3kZ~Sa=g(P(e8gKDnNeIk zdCH}eCQrJIfT4VHcu)d6)d5LcMkODHZIa$JcU+#2G30L-GVPvGYVbP=Mh#g)N~<0s z8Lx}cNk6`ThGY4&OFCa3l|TE*<>L!?oG$6Us%_fS4ZTBb;=)fK41ShBU#{GF&|g$g z|L0A!uKd9T$3LFcdEUHHr=HomxZ<%rzx;G*XZCA&xh8tHOyx0Bk9a}b^9CzT| zJ?m%uub=zJ%NjDLrM7IEG&SolwL=cc+w(Sk^4~n;!^KUHs&%KzPQNy9{8ihk#ymcH z-4^T`zICw-Mm6p35VWBZbuen9kCS#V)!Z#8vyDD>>Z3z|N=7tR^ApXd7nNRX_!LWp z4hGU0m)u@{`^Uc8G}-Dg-x&GVwm0TxjO+KtDDoG*F^7VWzVzmbM;iaNa>gI#d^GT) z?`G$3e(%E<_H=wNZ*}22SuZ2YmzH<$-am5vtKp=qN5Qi382qD1=3YZ}?;SId}aWV;@kzta&BqNiVIP(TW z>p2@6u+6@vrL}d{ZdYt~d-}(9skJJ$NUT<*fmoc-}wPdwD;>uq@>8Dlb(L# zi8rsE^)GvkQoWh&ZAZU)^OC*md7ZyEh&rH@?A^%W?%ewsK3=8I+jV%GUKjA%AMWfW znrB);vzM{1o5!(tUv;iCU{0_K=LPvij8$Od6Jpd+iQ2*2gLza@JD)K-{lH_?Y$rNU z;uCS2t_7$-GOFCZ7-^Ony9z9KtY&OE5gcUfZuD6{XmN%#h-U|5#i(lCj9tVB&hbYr zaIAE)&?;4BK*iX*PW&K|Y3<|;mdDB1rpkC%NDVP|*Hlc@qLib248`))Vy04nu?NRt zViO9fX(fu~sby@mvR?r5HDawC4inY~-P+1{BHoEXu9HDDNC~S@EKeex+vkd_tAH7Ep7>_jE?kbdqRhMI(H1wuZ(x%HJ zC6_H`Odhc>MI~wPOWND1TL$4X-kSZA_PnG$C2OOpTTWp_(q;p^P=HV8;50A5-Mcwk z?RkLnK@;P-D$d|NRDz;`LEeOsT#R1}jNfEq{2(t4E@?wYxJ>P?DoImaOQoU5oIxpd z)L1LkZtV#vHTUEq#>D7PjfM{7tWAY2W$kBzhCB6@a%^W>OtYj#TNaCl1a07hsC5*DQ0exwWodBGd}HL zs;u(dMU{wCv#@F{w<`Hv+Ux!{^4&l0oK<Wo{XuHh^v-_swbf+g3|6=w`}3hkoKnql1dGM9>#E%mVPLPx`(&%$ZMr8 zjoi)0XzmW84Ica~0gonR7lT$NLl+oKw&pU48caN{YJ-D=at|aJRV06vM{8g_TtA1j z!HDy72?9xhPrIhdr)^&9(_Rs&Kyahs;JSYs`D4wfPkX^fnb038gsxp?|M6Pm$aha9 z3CBaz4`7TR`8c}tBmZtOM6$qR$MZ9Rrf6V|G=fphfxJk>PV6`%xtrSpA=A;5^1H+0 zNUjm%B3?w(KuC;qfY)7wn7u!Z$c7d0V_?)c1`yLzJLcI*aDEKH+n!F9%>rR@223Z* zPm!UZ#Xl#%jJO7BPBv&FyF`lcs`lILv*`)W;{=^eb^HXD zwbFEM02wII>1n_v5)Sx5xDrni8#F9mrn3ZkeJ)kzfJSIB{187zX`(p9ameb2IHien zJkO$FS`It8cT>hLYmfUlNNPtR9n!jE)yqg1Va~=ZwaJb9EmP0duSCINEqa|921FT z0;gL{B-`1MmI)-n<@^4rJ%wjSvI(TCOeCD)XA|$~OSpIoOeE*ok?s&kr6y8s1`=1D zxY3!4Pz2KJsPr`rW*~{dEbUbZq=P0BT}scQ@;_DZHSMw>!BA&GdR!oV-GXF0E7F$* z(#;km80svX+6B_}X(abg=oO2=!jS0%N1(Q)Q8QTOdhFYCxF+h;@O#)` zDwTnh>#_X;X?_|>mkit9+!f}f+%3RoWP!VPp9H7VVw4IDmV@!`nJ|9i>JqC60SH zayFBR^*zoP1jbDqgNMaDfS$(5uyPR&GWC6$*DVKXThe!#>sNrU z=-%lhM5{e1uBPp2RmG(O<7SQ_0wBEsbMGD$7{(4YcTa)9=*q#s0P)DhI6R9>wJHar z_DmRe3Jhls2F23T^5_#7AHcF=oyLC4KNF8D1jex(3_7?@%VUDT_<0TndCzGvp2r(* z*ke}?hVK8ly81VPacd5SZb5-@4m&a{Ulsd(wV*yo4wvB{`kF;(JqPLs;O~^146S&j zmM{K=(`vuAvn4;Y~KrDye&8ZqexoW575Kly;R|DHB#~u z;aa;n3hq}NZrFZ107~yUwa>1i!F7!dD0YDvfed+WxsnmN7fQFk%o`ap#RP-ftTJr| zf+^Fr=s~89RB@S>3zWVLnY6M?0RV|t&E(*h8Q}J};3NDRrmwL?z^x?oVf(Z+Tquj) z?^bepPZ9dC{XO(Jd%HISZrDz6To>O#!>Ws{{E^4Up%vQ!#eDQ)0MX!ur2Y7_AJ7p; z7unBXifmNhobo0nN>%xqQqW zvdrB=bAr?KGjh5)gVO|)lMU29ZJ}o6MDLcnEprAZlA;iE_pUG(rVEJCe@&0N5&vkt zxJH!9Biv4r}tmzarX9`vf%z*z)ckN z_NC#J47g$Yk1)e+){n;NY?foMH2}=8*Y`wd@|50B_F9fapNu}tsDOEBoIu0*h9>Q?GIDM{oyFGSolK;M=|~3YXE>h{FL5H4%`390Jpz} zU1;^2J^^=!fV&|Lw?6}J*sfrP+ph|ZbFyC%05k0OzF|MU-~POm1VKg#nJqS=W8$^+ zRHpsNw$Gknj%@o#dM?)x#KIaL4j?<3H}rlUj=WWn^Fe({^D<)Wfdk#$r5A6*JY>D1 zWH-L+CNGp8dBoBE-Xp10GXD>cN{{S!y!InZ^ZQM?e(SJ*iM{|2;guqj_EvxMrG>YD zk_hZmi>3Dt!5jmaeq)O?BD<a~&mUcOT0D7r0nYs|x z1eCpbVx7u7m z^lp--s^~3cEw$!JBX$q*MB6C?zgfojh4qpKay9#p9|qbR6%uYfT!3M_gLsbU-Jwx@ zZn1xZ&^7x>PQ~6+MLpw_oV^#L`|K+*IKjq7_t}@C#SN+1O9&Eddx1PbZ}+FlzU^Ra z*!~?1@Ne?R>mfqT{#4nm7>5QfyO1>SWpsvCd=@|~StQ_Qqn#=n#Kc3yO46Q4m3@1mmKzWKDtJm;*hjDhb9$D1#1gWx(iCx;?n!w1w%(qNVmxaPslYt_i6j- zGJnl$;r~sgxF0uYZhTn4#Np$^@C4JDA<##U(161y>MFfnqu0H9{aL;Ks$PFvuOHOw zXY~4*Ucax`MffmD&pf?es@Jk!U#HiDdi_GBb6A&KB-R2GYTHJxa z28Q2)VD(LY?`nTjYojN)N^bR9`>Xw4FTSIR#{%c~dNS~QjR9|Ciw^|xta8__wbHZn zGw4~yIXz21gI--zLqk(zP;Ofll)Y}Od3A8rhJcq@#shx0Pfkzh@>=Fs`+c6E)a3VF z-P9Ox>-Nf?m)pGlfUnM&w$kVL{xi?}y_jq92HSidFSiAWV4)A)V!jTF#yIrY;0^>E zye%#6)!tyezo{YEvY{p5#TP(&V7H*Ju^Fb6+>IWYQ20aRFmTQUjl-53z$S)IGNMQ*BF8*CCLZ)|O_c3DfEze$$OA#Won z*Lgib5F!$?w>}Vb%Yk6CA4?+-5f2})3;5-%3BPZ(bUFkvo{P{T`M|&=9#YkKxFe}5 z3FsQElF@J{el@hNH$*!K^2Fjji@K8uB@s);JC#M(g`$b@qHt7I;?YoK(OOhWq^8tCvXX2tNOl_9gC1g0H6DwsRkpUMAyr`!rJK`KWBn{1?&+mYM@&^? zeT?~AJS}@4yFE~H`!wI@UY&V&`_~q8G92kL#s)sMWMN#1D4~SX9tn2{H2mUc2WS)hydoPbT2jc0 zs>k)`73Z_!ybD>LEsxoddghJGXXC2#tMaB4vMF6Cf$?n0l5uQGwWB|;yoi-|p#&zd za^RO&PdPMc6yr0B*bH?7n*sP4fS&>Q8P!uq=YUr~KKkE=QoNe6ImGv!Qf5CkF=IT> zQOF!i9Ly0fK2$VX*gt;LxaPdlajdj!JSzpQ(&`KPr%$u7!nm!!U{ik8kt)V0$IF{q z#HI!=WK)4V^(&K(Iu1=7E$+Wy)AX6+Sn-k)RvZ_!((tp3*=)6h&F(@SxPZ-GQp9Ha zXB;g*Gv_IBf3>1ECi^;+cvE*> zESiW#6koJIsq$T!U;$f;f^Eph1NhZxw-LwKd|OK=c3ecCL`PAgtCHQ_N*upo-kw(< zNhW%&6vZ67HxC^3@dnz`tShfR7VitG4N4*r>QR8b*1}c5Txl7p%Zhn5_I2^Fs^~P= zvHL9?nvyCOQ`gMcW?E^B+9hFAN5Hi*uRffXUI#-w33Vdmu49D+Er$}SHy)26M1QfM zSy47ym$MGHMRO(A<@=)DF~*uL5}Q)ASw;h4HA1UhkSmF)X7=L(zY^-ox4luJjgY_HK8hffpDMVPC)Srwb)a(fD-QuBbX{WIAf3J(qJ#!TBE(( zZe8AiPNkpDIuIej*bhmgXPnM2@FhG-N3y3!i8sfU1RXUWv-#CXTR5&JLy^`foqmj6 zOk;8^wmI2fpNw`A120Y#9DC(7Qy1!2lW}q}{r?YGcb$_Vx+o3>h% zLnud42B(2mIbdgi1`54Pbf7pm4p{t@Ldlv614+ZekVWdwyZn9mBBjoI-ltm9cBo4|_L1^90eC2S%qg&Hqplh|Z7 zg_W_XY#J+P)7cCx_98Zm&1M%fC!2%+(s2oMF@9)sw_ele3pPdNSg4Dw32g}lk!l6a zR4d2SOU{wb?n$kqbP?OJNB5_>D&4o)@P)WVtsXz z+aFx)YpicNXCbo)G&Qy~$=={%WZbxa1sAVst*`ffSenQX&r=?88Cfi{%)bf^BY2Kk zx0LfP=9iY>hm%Jn>qH|k_7z!Aim@yq=X5mBqz^@gt~~l7J0?13NGHZbBQwny3#xh2 z^L*s|P}6C^`Jw0J7-J-3rZZzi{0sTv7%7?g*H{p9Q?IdL=cZ3%!9HV>doHIzI#ilT zbXM{@CQ&l;=JP{6FCR3;&%6Vip9nnf9h3Sp^ZT)I4K5aG?pSbm{yY|hb3Luo?x1Jp z!5}j4V3(er278fyQU>(V^S9H0@fq&mwa#C3KSQ6(K6?J1G~jgLTLtb_PP})b`;|Ni zcOA6pp4C2Cw5{*X=p9<$6x@UG4w~xxGRBUfO?R<7Q4XL@_pv#+gS8V))K8<(INi$z za4)+LZMvV8<92(%b#0{|DtZz|;S0{{V%zKaP9Z zJVECWYX5vOz6tfqdiwgN4 zKVm+Q<)PPnn(=&$<_+qpr_)i zU6@5#52%G%gejmLW!)?W&^N~uOch&#vW(Xq_z7RK73b&S%SDX!;hzF{l_fAPgF+|o zC-Acix=doO3+*`CDs-fvcH_@Gga9XcnK%nD-^Sq+pcMnQlU1`yaCNeIX$lotoGRFS zb_F1|0wamK5A?U9j-s!kPC`23OcI3Ac4B>Etxk*&aGCo#Bx%BlKCP@D+6aSEl+Qca z4d@XCb0wLwS7K&EmIN`@0h|ypiEc=z-Or_qL5efcB3Kn~If{7cMO%eDm$OCqcLV=d z2?$e_LNc;?g6k!Y*7eX=7}SIXJGiXG zOX#B$d^g&D%i;8*1eSgRR#VU<{sV&46+gJ?j*Ml(dYrr7C^-@E-d2YSaEPC zO&U9obV|6ik7*~+Ecr6ok#tJ)XSWVQIsODnDdLET7v!^1_*5fmiXHU$Q4<%5Q@@An z%Lk}V=zyM4tUE6qpFDt0V2*r>cCC3B)=1W?&SR~7!&e$0E4`ZB7>o~9?*)S z(2U`q=Bi0MUSQjH4kSm>DAB-d4b3T z7~Y{%k|HcX{zq}ey7wm7cG;GP5(%ZRBeK;w&=-j&R#YV8(aRH^y-Hswv9K?UFNBF$ zx4N)1)^~X*(O0=;afK7#mBQUhLT$sRc6?@8QL(tPs$ykHk<+3ffi-))FEBlL4cMJVBm zZi#JH;uX$h*xgBAvQ|`dhaw53V&(EhY1)~{Y5Eq39PY~(WyrdGQF_rpU%trD=gMYx kv)eWRky>994)l<%_v%?&Gh@L|=Ce_&5;S_ly zjBP_0G(3l~e8N!-$l|C_a8YvDMzCr^2DrSgQJhN|^Frn!z%3-)1~?PY!`P^5kccQ7 z8T$~x_#(zSsQw9LJb5yMBpWnIvqHKnqy#BA4mW`vFWX9ITg#LBHf@Y*P_P zAh0=jC^lKe1Fy?8HdZhL4Ng3W6(gUriifduSzKdO`v`){r^no21=&+3Cd2>;YD^Ft zR*2^&JXyt~@(Ga`7%4^+D^(xa&nh0qR%KQHtWbVngT3G$K6To|%jOF=GRC`}~AT`Sy>}`DNS&wh{uunhAGGGELP1hE z)}OXKJ~Y^%fO+W@FUdgrN%C4*atAmKEuoO*#vST7@+*oKq5XVv9zQfx9J(;1DCd(o z=ZE>BvEox-%T-0lX8&=iHubtmT1u~LQ*WE3!u>QoREwEUp_dcpj1R!_owQ18k&hBQ zMf0N-{yjRRRu@7@jVV7M*^BvshwNO#S{OhO&wJ%_uCdI!P_iSPEJY{Le|)5jBiIpQ>S!otH;50Zd>RF7?Vke42z>GABQB4nf1lu}H|8Yp!`%ypc^&LPy36)$wa^boATv^2+PP^=-4FfYw1B{%7rw7D?L zrnC%_k7$y~nS<+07!T(}iNUK_7f<>=k?(quTIFF%)GZhfPs4q_`-Trs<+nP9E%HVA zXS{q4lO}1-{5^u;l}F^~c}k4Q1gF6~_33vN1u^%uYZKz6YfP~|KZ_FVkYYU!M6o`j zR!5)4pwc|!)?;SxA=-c!d6PO_bKnDrS!Oea8(p7qfKu?tGUWTO7lQmv)OZ;w!Vj2# zh7scj2~VYwapwD}E}Mr544BC5;B(loIO zNpd95M3$%Ma?#TZKp*htaR$-E%SB%>h!C8Q$(F$(i&n83TE#r=YxR})q+w>s(&86Vaa^O8i1jxm6_K6F>U={g$8v$ zIDq=81(@Ibp!xg2hbJNQWqt)$_*6k&<~0q;fi3JQWGnMyEX@e?B7v9lmN;q1Wxim- z%&!=gN?hr)yyaU(JD@Omrc&Dj_L(LwP)teoZ#3B%nS3li6Z114LmkWIK8>7LnVy)D z`35TcOsYYW!Ddj8JllcIL(^yI`ZD;iMUc?E%-?F28JW)jnK+##pLrOR%vQW~qCURJ z_6Y4g#v@4(tj9XfRqw9MO@c5~*K%8J11{rtIJKlK6-ZT?%nV_pg2 z{;}`TT(dL{?=+XwLjOZ7gPAXYO^-lHX17+EiFkbm=)~*0pcYGmHiuxrv#tI&n8Qpy zY3bhwn0m`(dE}pgWZuEvfDv8V|67pk=Q4V^DQvhPg#Cv`sS7I&|JL zw@3v1p}7uklRA8!^}`3?34F$jatd4Q(EiqsG8U>ecOqMpeSE;Y69_i(W);jX-d;-| zEJ@$~Sy+xjwGE}o4(}}oE#GY@;Riol%I6*hn$Hi;-sT;g{Ud&$#NM*vm{cm?G26Rh zNGz0B732p@|=PD*(@jwk2fba50S0Am1ZuW1x9Ka*e^PAw6L zdsy9HI{CpT?VjJEx7$yr5f}NSw(@@*lCYR3A3Cz^0C1N1S4?DhKG=G;VgFG&3)n%X zs$yLWL0tLomFNMEQRb| z43-*8b(`h~um1q;B!l(E02A|YYNG&PNp+G)YPf)3@rrm#oB0?+pEeGL>;x?jgY~}z z$d>&Ld2|KYgOtPAh^CgIVi&g7uUw-YHCmJPF(r(d0!m<72U$o&(k0Hq`mA2A=8 zr}cBh{B2-Zq1C4A5}m}cFmV^unU3;9zu@>;M|t#sqq7KS&#%i*R?6lSWKyFABW4i@ z<@kU(4$SlB2q#^W8s$dJA3+tPhK759(U>izv$KTniPW>j_?}X?NQ}QLU2EpSf-Q!o z?qOxgH<5ieMjeoB2mr@kLk-+z}y|AdMc;Jwc@eE8DG1rxO1x5^FJ zHh$D1AIsn{nY~-nnWtGU<>j9>q+Y$~mB$+1WO-ism~>5p>?vpswB=nm;mtk92S&Y% zkF^Ab?~qH1dAYF|+b}@En@y%%i!{sf9l+H1S#R#B*99|U>rYwFt0zn9A(g4`KV{t0 z37-((*LSsgXl=UpR2^28!;|F9N8VDDU9C7KQX4nfhA*?%dD$c*gE9AMjJ$(I$IdB= zS8k5Woj8KEZp;i`RFvJ2bYiYSqblJV+g^jQNn1WQBoBd(5d7(ugCEj->u_lBHXYh@ zSfIo6I^Rn=%+cXjb@*8wenN*Eb=agsrw*^xp%Ia#HyfA+Z@?*(%DX!KwM*K6qPK6; z;a(kf=y0_TZ`I+y=rE*1O*>gTd)-BZT`^In3@BNI1{~_cm zG<|6u_AS;F_V^RNWHKD|bqi5J^h<(I3ik@Wgg+#x44r6e6a_RerZQf^592Nq)0W+j z#{=CS`iw#`+GYc%Yr7}W_T(jPMWA~ioJLz(Zv#myw2b}{N`dpr@pUfJ=ruaL%=910 zpUdp%gf;C=?LEg!Uu}M;?~YGD`drc7y{qmg7aDKf(6zzemGA|swn{xcelgUyAt1(L z(uR1S)Dw$367fh_@>NvVy4|kjwN+I$Zuf@GG4X*7ZH-;Ya3r|F-y5uUZ&1e+m!e&| zJsKl=s9?Wiw>Nfp>2CHY?jh7WTYGPm+K%EVjb(q5W_LQ-FF@NqNyDu&r`-XUh3U@K zUWF!x_^MaEWlm=x)QxdRoj!ic8rR^{ps|5?_~|s9P;osyjn<;_t(#6$`8H0YwW)kP z(`hPSd>XAo<=Zlyrt)nAEp38-`aLw|b{e^=)$LoiZVh&!8|vM#+7D3**jpM@eFZn^ zeN$;4RrM8T(>gT1(rGk}j{~ik>}=8QtBw2mGC`};y?qd7_1IRD3*(@bPSIRMy9gTH z8|i#*qS2aoSMDUOnrL)qPQSMp_vpnHki{-j)|E)8?H=uS0ptFhelOUA2KAoY?gTgL zpq)SvbeifD(XUqK&(C9p?m|{5=EvKRKX8MY@=Ppml_mw3*j#G?vr03WH8_J=-TBN~ zId}XlzH1O3wgV1yD`V9+i;qS@>r33CM&AUZ!_!}a3;mX#+YI6OE?YQynwMgVUM6G z$Ha0Fe}jKgr`G=|8&nrzv!sBPARZ+hGgt{?Qc_tQpOn?(|6kUvW{k(v%xc=t^2v4~ zjb%P7tjv#3!_^od?rt;2YF3=aiDIVu?40tM=v45%r4Z~w?y7vi39dtZ1D=g|(#05O zKz&y#i}wXtTVG2QYu@BGwPhK#YsG_{-^L++S+o z>?qMh(bq0WtHoIFJ>h6DwmAU`^3l-KB!qmFON_l~Xjmg8q?l+ZVcIV1s;E$1D_}lf zqc0H`0^v|N;Op^6gAqYwYzgQIDd>~>;({+64aIyxs1aj*zDPI$?YFUBp*JA_Tidv% z^RAAT*5(SgQ|oOtgG5-81hJPbpTd0tTgiM0p~n{rN6_e_(3CP?AQlaUyOW~ei~2<| zw%O+wyEoy!K$Ao)5i6rfh;9mtv1l)X%$R!`M=UCA!5otOT@jr4Y|JNY5dujZ3#T<) z3wy+e^)?=M^d=me!%;^-lpOdap3aYsNQI-qp>^cn^43U^Mt@v_Zx|T$ci)$Y=8eT3 zNXAzuqX8)#i#A6kv5&D=sby_gl#>2PXB29&$)(MmQ7xpw<}CpsPVB4I&f_-|Gsf{f zo4K6Z1*tJ9is)&Z7z+s4%)V&uKuE(;9BB;_`|I46gkFh>t8v(ExgZUSfC`U9P<)$d+VLwUh&q{hFxleF;hE?LdGU66kxdV6j}vLT&Kcy+|3JGPob!HVIwH?ruReyu7n{&0Wo2SEZIam#;_v zSCk|7a>qk2D2nk5fU&mIdQSUyIXB%iqGy-1aSkum&gHlc`hyDDpt4(+*J@MmOYKdy zOverzeoQAbkNzF8?LEFHE@A)kt74yi1P`5OF$V10c-+9p0Zll&d4T5ucHkKWPOul} zuO{GhC-p9#oxtg1#8rat4&d~^F%RNlAH@F#0Dc{h9XP>0+;|oPe+ckD@RR~S3;225 zx_<~b!5`qM0e%{A2EI2vzzYBy@Wg>P0dB$b6mWurc%B5l8*o3K!@vn1!Se#}qkv8v zydMKja3h{)fD@GPJPVxQ_wj54o(6mj=eOO!30C0z#shZ)uEVnhIKdR2oxnc_`0{m( zy##z5a3OB7PXi~2`vP_m_y)kA;w+knGYXxfd-2$T#{m!FSqL0=3hFtz6gZui>CC$g z@gzv+)--T}bf&xroL~S?5A^@@MkvEV`DUpoF zVx4g2U;o2?~PX3c5nhk7xDiG6k-x z3Rg{6t=~}gTb@{KV!0oRLRn`bDN0qCq*5P)$D;!<^ z+JGZiT^n@!-TrF9RdZDZ6`|_o)q&;JjvA*>;c!>FY8|yzU0seESI`-%4myMWTn6Bq@GtdAUBB$|fgM8C)uFZ*3{Z=vJ5O=XOJ- z?KY&FP**-pqnSwu`M%x;Gpc*0}mbEh<-py_2miWen)IUy zya^Ui{fkfIo35YyAicN)V>7bk*McTO!<2p(I4ba0#;R0%)rgo$?XRTrM&VB+t0&X# zG~s`Dy{eqk^hwBhA=9l&kOy(}nIhSZeoNrGoW`+lpzoDxG%J`x#VYZw$o;qCRR+1M z+i-$o6@0uKz6pqM8DdEzb~VWgR*SzX-8&~@MON-Y=C!;JIqH?6fyTWRvSo-x9sZHm z1V6O+P_|K=jeMh;mN`CTMG`R#LW<%Ugse8EZIF$jo Date: Tue, 17 Oct 2023 20:24:52 -0500 Subject: [PATCH 05/11] Deprecate codefile_type and is_codefile --- conda_build/os_utils/ldd.py | 11 ++--- conda_build/os_utils/liefldd.py | 78 +++++++++++++++++---------------- conda_build/os_utils/pyldd.py | 59 +++++++++++++++---------- conda_build/post.py | 73 ++++++++++++++++-------------- 4 files changed, 120 insertions(+), 101 deletions(-) diff --git a/conda_build/os_utils/ldd.py b/conda_build/os_utils/ldd.py index 77daf4ab10..32eea125a2 100644 --- a/conda_build/os_utils/ldd.py +++ b/conda_build/os_utils/ldd.py @@ -8,12 +8,7 @@ from conda_build.conda_interface import linked_data, untracked from conda_build.os_utils.macho import otool -from conda_build.os_utils.pyldd import ( - codefile_class, - inspect_linkages, - is_codefile, - machofile, -) +from conda_build.os_utils.pyldd import codefile_class, inspect_linkages, machofile LDD_RE = re.compile(r"\s*(.*?)\s*=>\s*(.*?)\s*\(.*\)") LDD_NOT_FOUND_RE = re.compile(r"\s*(.*?)\s*=>\s*not found") @@ -118,7 +113,7 @@ def get_package_obj_files(dist, prefix): files = get_package_files(dist, prefix) for f in files: path = join(prefix, f) - if is_codefile(path): + if codefile_class(path): res.append(f) return res @@ -130,7 +125,7 @@ def get_untracked_obj_files(prefix): files = untracked(prefix) for f in files: path = join(prefix, f) - if is_codefile(path): + if codefile_class(path): res.append(f) return res diff --git a/conda_build/os_utils/liefldd.py b/conda_build/os_utils/liefldd.py index a4962628a8..863ba7ff32 100644 --- a/conda_build/os_utils/liefldd.py +++ b/conda_build/os_utils/liefldd.py @@ -1,9 +1,6 @@ # Copyright (C) 2014 Anaconda, Inc # SPDX-License-Identifier: BSD-3-Clause -try: - from collections.abc import Hashable -except ImportError: - from collections.abc import Hashable +from __future__ import annotations import hashlib import json @@ -11,28 +8,28 @@ import struct import sys import threading +from collections.abc import Hashable from fnmatch import fnmatch from functools import partial +from pathlib import Path from subprocess import PIPE, Popen from ..deprecations import deprecated from .external import find_executable +from .pyldd import DLLfile, EXEfile, elffile, machofile # lief cannot handle files it doesn't know about gracefully # TODO :: Remove all use of pyldd # Currently we verify the output of each against the other -from .pyldd import codefile_type as codefile_type_pyldd from .pyldd import inspect_linkages as inspect_linkages_pyldd -codefile_type = codefile_type_pyldd -have_lief = False try: import lief lief.logging.disable() have_lief = True -except: - pass +except ImportError: + have_lief = False @deprecated("3.28.0", "4.0.0", addendum="Use `isinstance(value, str)` instead.") @@ -45,17 +42,16 @@ def is_string(s): # these are to be avoided, or if not avoided they # should be passed a binary when possible as that # will prevent having to parse it multiple times. -def ensure_binary(file): - if not isinstance(file, str): +def ensure_binary(file: str | os.PathLike | Path | lief.Binary) -> lief.Binary | None: + if isinstance(file, lief.Binary): return file - else: - try: - if not os.path.exists(file): - return [] - return lief.parse(file) - except: - print(f"WARNING: liefldd: failed to ensure_binary({file})") - return None + elif not Path(file).exists(): + return None + try: + return lief.parse(str(file)) + except BaseException: + print(f"WARNING: liefldd: failed to ensure_binary({file})") + return None def nm(filename): @@ -76,25 +72,31 @@ def nm(filename): print("No symbols found") -def codefile_type_liefldd(file, skip_symlinks=True): - binary = ensure_binary(file) - result = None - if binary: - if binary.format == lief.EXE_FORMATS.PE: - if lief.PE.DLL_CHARACTERISTICS: - if binary.header.characteristics & lief.PE.HEADER_CHARACTERISTICS.DLL: - result = "DLLfile" - else: - result = "EXEfile" +if have_lief: + + def codefile_class( + path: str | os.PathLike | Path, + skip_symlinks: bool = False, + ) -> type[DLLfile | EXEfile | machofile | elffile] | None: + # same signature as conda.os_utils.pyldd.codefile_class + if not (binary := ensure_binary(path)): + return None + elif ( + binary.format == lief.EXE_FORMATS.PE + and lief.PE.HEADER_CHARACTERISTICS.DLL in binary.header.characteristics_list + ): + return DLLfile + elif binary.format == lief.EXE_FORMATS.PE: + return EXEfile elif binary.format == lief.EXE_FORMATS.MACHO: - result = "machofile" + return machofile elif binary.format == lief.EXE_FORMATS.ELF: - result = "elffile" - return result - + return elffile + else: + return None -if have_lief: - codefile_type = codefile_type_liefldd +else: + from .pyldd import codefile_class def _trim_sysroot(sysroot): @@ -506,7 +508,7 @@ def inspect_linkages_lief( while tmp_filename: if ( not parent_exe_dirname - and codefile_type(tmp_filename) == "EXEfile" + and codefile_class(tmp_filename) == EXEfile ): parent_exe_dirname = os.path.dirname(tmp_filename) tmp_filename = parents_by_filename[tmp_filename] @@ -596,7 +598,7 @@ def get_linkages( result_pyldd = [] debug = False if not have_lief or debug: - if codefile_type(filename) not in ("DLLfile", "EXEfile"): + if codefile_class(filename) not in (DLLfile, EXEfile): result_pyldd = inspect_linkages_pyldd( filename, resolve_filenames=resolve_filenames, @@ -608,7 +610,7 @@ def get_linkages( return result_pyldd else: print( - f"WARNING: failed to get_linkages, codefile_type('{filename}')={codefile_type(filename)}" + f"WARNING: failed to get_linkages, codefile_class('{filename}')={codefile_class(filename)}" ) return {} result_lief = inspect_linkages_lief( diff --git a/conda_build/os_utils/pyldd.py b/conda_build/os_utils/pyldd.py index 7db73abd95..3b68ad7ebc 100644 --- a/conda_build/os_utils/pyldd.py +++ b/conda_build/os_utils/pyldd.py @@ -1033,40 +1033,55 @@ def codefile(file, arch="any", initial_rpaths_transitive=[]): return inscrutablefile(file, list(initial_rpaths_transitive)) -def codefile_class(filename, skip_symlinks=False): - if os.path.islink(filename): - if skip_symlinks: - return None - else: - filename = os.path.realpath(filename) - if os.path.isdir(filename): +def codefile_class( + path: str | os.PathLike | Path, + skip_symlinks: bool = False, +) -> type[DLLfile | EXEfile | machofile | elffile] | None: + # same signature as conda.os_utils.liefldd.codefile_class + path = Path(path) + if skip_symlinks and path.is_symlink(): return None - if filename.endswith((".dll", ".pyd")): + path = path.resolve() + + def _get_magic_bit(path: Path) -> bytes: + with path.open("rb") as handle: + bit = handle.read(4) + return struct.unpack(BIG_ENDIAN + "L", bit)[0] + + if path.is_dir(): + return None + elif path.suffix.lower() in (".dll", ".pyd"): return DLLfile - if filename.endswith(".exe"): + elif path.suffix.lower() == ".exe": return EXEfile - # Java .class files share 0xCAFEBABE with Mach-O FAT_MAGIC. - if filename.endswith(".class"): + elif path.suffix.lower() == ".class": + # Java .class files share 0xCAFEBABE with Mach-O FAT_MAGIC. return None - if not os.path.exists(filename) or os.path.getsize(filename) < 4: + elif not path.exists() or path.stat().st_size < 4: + return None + elif (magic := _get_magic_bit(path)) == ELF_HDR: + return elffile + elif magic in (FAT_MAGIC, MH_MAGIC, MH_CIGAM, MH_CIGAM_64): + return machofile + else: return None - with open(filename, "rb") as file: - (magic,) = struct.unpack(BIG_ENDIAN + "L", file.read(4)) - file.seek(0) - if magic in (FAT_MAGIC, MH_MAGIC, MH_CIGAM, MH_CIGAM_64): - return machofile - elif magic == ELF_HDR: - return elffile - return None -@deprecated.argument("3.28.0", "4.0.0", "filename", rename="path") +@deprecated( + "3.28.0", + "4.0.0", + addendum="Use `conda_build.os_utils.pyldd.codefile_class` instead.", +) def is_codefile(path: str | os.PathLike | Path, skip_symlinks: bool = True) -> bool: return bool(codefile_class(path, skip_symlinks=skip_symlinks)) +@deprecated( + "3.28.0", + "4.0.0", + addendum="Use `conda_build.os_utils.pyldd.codefile_class` instead.", +) def codefile_type(filename, skip_symlinks=True): - "Returns None, 'machofile' or 'elffile'" klass = codefile_class(filename, skip_symlinks=skip_symlinks) if not klass: return None diff --git a/conda_build/post.py b/conda_build/post.py index 290779385d..1eae47c589 100644 --- a/conda_build/post.py +++ b/conda_build/post.py @@ -53,18 +53,24 @@ have_lief, set_rpath, ) -from conda_build.os_utils.pyldd import codefile_type +from conda_build.os_utils.pyldd import ( + DLLfile, + EXEfile, + codefile_class, + elffile, + machofile, +) filetypes_for_platform = { - "win": ("DLLfile", "EXEfile"), - "osx": ["machofile"], - "linux": ["elffile"], + "win": (DLLfile, EXEfile), + "osx": (machofile,), + "linux": (elffile,), } def fix_shebang(f, prefix, build_python, osx_is_app=False): path = join(prefix, f) - if codefile_type(path): + if codefile_class(path): return elif islink(path): return @@ -405,7 +411,7 @@ def osx_ch_link(path, link_dict, host_prefix, build_prefix, files): ".. seems to be linking to a compiler runtime, replacing build prefix with " "host prefix and" ) - if not codefile_type(link): + if not codefile_class(link): sys.exit( "Error: Compiler runtime library in build prefix not found in host prefix %s" % link @@ -841,7 +847,7 @@ def _collect_needed_dsos( sysroots = list(sysroots_files.keys())[0] for f in files: path = join(run_prefix, f) - if not codefile_type(path): + if not codefile_class(path): continue build_prefix = build_prefix.replace(os.sep, "/") run_prefix = run_prefix.replace(os.sep, "/") @@ -901,10 +907,9 @@ def _map_file_to_package( for subdir2, _, filez in os.walk(prefix): for file in filez: fp = join(subdir2, file) - dynamic_lib = ( - any(fnmatch(fp, ext) for ext in ("*.so*", "*.dylib*", "*.dll")) - and codefile_type(fp, skip_symlinks=False) is not None - ) + dynamic_lib = any( + fnmatch(fp, ext) for ext in ("*.so*", "*.dylib*", "*.dll") + ) and codefile_class(fp, skip_symlinks=False) static_lib = any(fnmatch(fp, ext) for ext in ("*.a", "*.lib")) # Looking at all the files is very slow. if not dynamic_lib and not static_lib: @@ -947,7 +952,7 @@ def _map_file_to_package( ) } all_lib_exports[prefix][rp_po] = exports - # Check codefile_type to filter out linker scripts. + # Check codefile_class to filter out linker scripts. if dynamic_lib: contains_dsos[prefix_owners[prefix][rp_po][0]] = True elif static_lib: @@ -1217,8 +1222,7 @@ def _show_linking_messages( ) for f in files: path = join(run_prefix, f) - filetype = codefile_type(path) - if not filetype or filetype not in filetypes_for_platform[subdir.split("-")[0]]: + if codefile_class(path) not in filetypes_for_platform[subdir.split("-")[0]]: continue warn_prelude = "WARNING ({},{})".format(pkg_name, f.replace(os.sep, "/")) err_prelude = " ERROR ({},{})".format(pkg_name, f.replace(os.sep, "/")) @@ -1316,15 +1320,15 @@ def check_overlinking_impl( files_to_inspect = [] filesu = [] - for f in files: - path = join(run_prefix, f) - filetype = codefile_type(path) - if filetype and filetype in filetypes_for_platform[subdir.split("-")[0]]: - files_to_inspect.append(f) - filesu.append(f.replace("\\", "/")) + for file in files: + path = join(run_prefix, file) + codefile = codefile_class(path) + if codefile in filetypes_for_platform[subdir.split("-")[0]]: + files_to_inspect.append(file) + filesu.append(file.replace("\\", "/")) if not files_to_inspect: - return dict() + return {} sysroot_substitution = "$SYSROOT" build_prefix_substitution = "$PATH" @@ -1630,21 +1634,18 @@ def check_overlinking(m, files, host_prefix=None): def post_process_shared_lib(m, f, files, host_prefix=None): - if not host_prefix: - host_prefix = m.config.host_prefix - path = join(host_prefix, f) - codefile_t = codefile_type(path) - if not codefile_t or path.endswith(".debug"): + if (path := join(host_prefix, f)).endswith(".debug"): + return + elif not (codefile := codefile_class(path)): return - rpaths = m.get_value("build/rpaths", ["lib"]) - if codefile_t == "elffile": + elif codefile == elffile: mk_relative_linux( f, - host_prefix, - rpaths=rpaths, + host_prefix or m.config.host_prefix, + rpaths=m.get_value("build/rpaths", ["lib"]), method=m.get_value("build/rpaths_patcher", None), ) - elif codefile_t == "machofile": + elif codefile == machofile: if m.config.host_platform != "osx": log = utils.get_logger(__name__) log.warn( @@ -1652,7 +1653,13 @@ def post_process_shared_lib(m, f, files, host_prefix=None): path, ) return - mk_relative_osx(path, host_prefix, m, files=files, rpaths=rpaths) + mk_relative_osx( + path, + host_prefix or m.config.host_prefix, + m, + files=files, + rpaths=m.get_value("build/rpaths", ["lib"]), + ) def fix_permissions(files, prefix): @@ -1734,7 +1741,7 @@ def check_symlinks(files, prefix, croot): # symlinks to binaries outside of the same dir don't work. RPATH stuff gets confused # because ld.so follows symlinks in RPATHS # If condition exists, then copy the file rather than symlink it. - if not dirname(link_path) == dirname(real_link_path) and codefile_type(f): + if not dirname(link_path) == dirname(real_link_path) and codefile_class(f): os.remove(path) utils.copy_into(real_link_path, path) elif real_link_path.startswith(real_build_prefix): From 401a19e1fc967d523921d61462a76a1d0e391356 Mon Sep 17 00:00:00 2001 From: Ken Odegard Date: Tue, 17 Oct 2023 21:39:25 -0500 Subject: [PATCH 06/11] List comprehensions --- conda_build/post.py | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/conda_build/post.py b/conda_build/post.py index 1eae47c589..fdb5f8ec19 100644 --- a/conda_build/post.py +++ b/conda_build/post.py @@ -1318,15 +1318,11 @@ def check_overlinking_impl( verbose = True errors = [] - files_to_inspect = [] - filesu = [] - for file in files: - path = join(run_prefix, file) - codefile = codefile_class(path) - if codefile in filetypes_for_platform[subdir.split("-")[0]]: - files_to_inspect.append(file) - filesu.append(file.replace("\\", "/")) - + filetypes = filetypes_for_platform[subdir.split("-")[0]] + files_to_inspect = [ + file for file in files if codefile_class(join(run_prefix, file)) in filetypes + ] + filesu = [file.replace("\\", "/") for file in files] if not files_to_inspect: return {} From b48cb383a127d38ad2217d3742844c95677b93c4 Mon Sep 17 00:00:00 2001 From: Ken Odegard Date: Tue, 17 Oct 2023 21:44:28 -0500 Subject: [PATCH 07/11] Revert --- conda_build/post.py | 40 +++++++++++++++++++++------------------- 1 file changed, 21 insertions(+), 19 deletions(-) diff --git a/conda_build/post.py b/conda_build/post.py index fdb5f8ec19..05af50b24f 100644 --- a/conda_build/post.py +++ b/conda_build/post.py @@ -1222,7 +1222,8 @@ def _show_linking_messages( ) for f in files: path = join(run_prefix, f) - if codefile_class(path) not in filetypes_for_platform[subdir.split("-")[0]]: + codefile = codefile_class(path) + if codefile not in filetypes_for_platform[subdir.split("-")[0]]: continue warn_prelude = "WARNING ({},{})".format(pkg_name, f.replace(os.sep, "/")) err_prelude = " ERROR ({},{})".format(pkg_name, f.replace(os.sep, "/")) @@ -1318,11 +1319,15 @@ def check_overlinking_impl( verbose = True errors = [] - filetypes = filetypes_for_platform[subdir.split("-")[0]] - files_to_inspect = [ - file for file in files if codefile_class(join(run_prefix, file)) in filetypes - ] - filesu = [file.replace("\\", "/") for file in files] + files_to_inspect = [] + filesu = [] + for file in files: + path = join(run_prefix, file) + codefile = codefile_class(path) + if codefile in filetypes_for_platform[subdir.split("-")[0]]: + files_to_inspect.append(file) + filesu.append(file.replace("\\", "/")) + if not files_to_inspect: return {} @@ -1630,15 +1635,18 @@ def check_overlinking(m, files, host_prefix=None): def post_process_shared_lib(m, f, files, host_prefix=None): - if (path := join(host_prefix, f)).endswith(".debug"): - return - elif not (codefile := codefile_class(path)): + if not host_prefix: + host_prefix = m.config.host_prefix + path = join(host_prefix, f) + codefile = codefile_class(path) + if not codefile or path.endswith(".debug"): return - elif codefile == elffile: + rpaths = m.get_value("build/rpaths", ["lib"]) + if codefile == elffile: mk_relative_linux( f, - host_prefix or m.config.host_prefix, - rpaths=m.get_value("build/rpaths", ["lib"]), + host_prefix, + rpaths=rpaths, method=m.get_value("build/rpaths_patcher", None), ) elif codefile == machofile: @@ -1649,13 +1657,7 @@ def post_process_shared_lib(m, f, files, host_prefix=None): path, ) return - mk_relative_osx( - path, - host_prefix or m.config.host_prefix, - m, - files=files, - rpaths=m.get_value("build/rpaths", ["lib"]), - ) + mk_relative_osx(path, host_prefix, m, files=files, rpaths=rpaths) def fix_permissions(files, prefix): From 73bf6d0268f452f67c52bd6527217a7b8170f21d Mon Sep 17 00:00:00 2001 From: Ken Odegard Date: Tue, 17 Oct 2023 21:50:22 -0500 Subject: [PATCH 08/11] Typing --- conda_build/os_utils/pyldd.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/conda_build/os_utils/pyldd.py b/conda_build/os_utils/pyldd.py index 3b68ad7ebc..42b89711ae 100644 --- a/conda_build/os_utils/pyldd.py +++ b/conda_build/os_utils/pyldd.py @@ -1081,11 +1081,12 @@ def is_codefile(path: str | os.PathLike | Path, skip_symlinks: bool = True) -> b "4.0.0", addendum="Use `conda_build.os_utils.pyldd.codefile_class` instead.", ) -def codefile_type(filename, skip_symlinks=True): - klass = codefile_class(filename, skip_symlinks=skip_symlinks) - if not klass: - return None - return klass.__name__ +def codefile_type( + path: str | os.PathLike | Path, + skip_symlinks: bool = True, +) -> str | None: + codefile = codefile_class(path, skip_symlinks=skip_symlinks) + return codefile.__name__ if codefile else None def _trim_sysroot(sysroot): From c03d699087e75aaed27231c0f612c03fe1d4e228 Mon Sep 17 00:00:00 2001 From: Ken Odegard Date: Tue, 17 Oct 2023 21:55:59 -0500 Subject: [PATCH 09/11] Add news --- news/5040-codefile | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 news/5040-codefile diff --git a/news/5040-codefile b/news/5040-codefile new file mode 100644 index 0000000000..c4f85ca7cf --- /dev/null +++ b/news/5040-codefile @@ -0,0 +1,21 @@ +### Enhancements + +* + +### Bug fixes + +* + +### Deprecations + +* Mark `conda_build.os_utils.pyldd.is_string` as pending deprecation. Use `isinstance(value, str)` instead. (#5040) +* Mark `conda_build.os_utils.pyldd.is_codefile` as pending deprecation. Use `conda_build.os_utils.pyldd.codefile_class` instead. (#5040) +* Mark `conda_build.os_utils.pyldd.codefile_type` as pending deprecation. Use `conda_build.os_utils.pyldd.codefile_class` instead. (#5040) + +### Docs + +* + +### Other + +* From f280b42e0706f75ce2b7f3e6c2743be254fe8e5a Mon Sep 17 00:00:00 2001 From: Ken Odegard Date: Tue, 17 Oct 2023 22:31:07 -0500 Subject: [PATCH 10/11] Update inspect_pkg.py --- conda_build/inspect_pkg.py | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/conda_build/inspect_pkg.py b/conda_build/inspect_pkg.py index e38c5aa9e7..cbb60d4f25 100644 --- a/conda_build/inspect_pkg.py +++ b/conda_build/inspect_pkg.py @@ -24,7 +24,7 @@ get_package_obj_files, get_untracked_obj_files, ) -from conda_build.os_utils.liefldd import codefile_type +from conda_build.os_utils.liefldd import codefile_class, machofile from conda_build.os_utils.macho import get_rpaths, human_filetype from conda_build.utils import ( comma_join, @@ -354,14 +354,16 @@ def inspect_objects(packages, prefix=sys.prefix, groupby="package"): info = [] for f in obj_files: - f_info = {} path = join(prefix, f) - filetype = codefile_type(path) - if filetype == "machofile": - f_info["filetype"] = human_filetype(path, None) - f_info["rpath"] = ":".join(get_rpaths(path)) - f_info["filename"] = f - info.append(f_info) + codefile = codefile_class(path) + if codefile == machofile: + info.append( + { + "filetype": human_filetype(path, None), + "rpath": ":".join(get_rpaths(path)), + "filename": f, + } + ) output_string += print_object_info(info, groupby) if hasattr(output_string, "decode"): From 7527a7d2a094935942f30e3db4992f995df1d2df Mon Sep 17 00:00:00 2001 From: Ken Odegard Date: Tue, 17 Oct 2023 22:40:21 -0500 Subject: [PATCH 11/11] Add backports --- conda_build/os_utils/liefldd.py | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/conda_build/os_utils/liefldd.py b/conda_build/os_utils/liefldd.py index 863ba7ff32..26a768a4f6 100644 --- a/conda_build/os_utils/liefldd.py +++ b/conda_build/os_utils/liefldd.py @@ -16,11 +16,12 @@ from ..deprecations import deprecated from .external import find_executable -from .pyldd import DLLfile, EXEfile, elffile, machofile # lief cannot handle files it doesn't know about gracefully # TODO :: Remove all use of pyldd # Currently we verify the output of each against the other +from .pyldd import DLLfile, EXEfile, elffile, machofile +from .pyldd import codefile_type as _codefile_type from .pyldd import inspect_linkages as inspect_linkages_pyldd try: @@ -99,6 +100,32 @@ def codefile_class( from .pyldd import codefile_class +@deprecated( + "3.28.0", + "4.0.0", + addendum="Use `conda_build.os_utils.liefldd.codefile_class` instead.", +) +def codefile_type_liefldd(*args, **kwargs) -> str | None: + codefile = codefile_class(*args, **kwargs) + return codefile.__name__ if codefile else None + + +deprecated.constant( + "3.28.0", + "4.0.0", + "codefile_type_pyldd", + _codefile_type, + addendum="Use `conda_build.os_utils.pyldd.codefile_class` instead.", +) +deprecated.constant( + "3.28.0", + "4.0.0", + "codefile_type", + _codefile_type, + addendum="Use `conda_build.os_utils.liefldd.codefile_class` instead.", +) + + def _trim_sysroot(sysroot): while sysroot.endswith("/") or sysroot.endswith("\\"): sysroot = sysroot[:-1]