PNG  IHDRX cHRMz&u0`:pQ<bKGD pHYsodtIME MeqIDATxw]Wug^Qd˶ 6`!N:!@xI~)%7%@Bh&`lnjVF29gΨ4E$|>cɚ{gk= %,a KX%,a KX%,a KX%,a KX%,a KX%,a KX%, b` ǟzeאfp]<!SJmɤY޲ڿ,%c ~ع9VH.!Ͳz&QynֺTkRR.BLHi٪:l;@(!MԴ=žI,:o&N'Kù\vRmJ雵֫AWic H@" !: Cé||]k-Ha oݜ:y F())u]aG7*JV@J415p=sZH!=!DRʯvɱh~V\}v/GKY$n]"X"}t@ xS76^[bw4dsce)2dU0 CkMa-U5tvLƀ~mlMwfGE/-]7XAƟ`׮g ewxwC4\[~7@O-Q( a*XGƒ{ ՟}$_y3tĐƤatgvێi|K=uVyrŲlLӪuܿzwk$m87k( `múcE)"@rK( z4$D; 2kW=Xb$V[Ru819קR~qloѱDyįݎ*mxw]y5e4K@ЃI0A D@"BDk_)N\8͜9dz"fK0zɿvM /.:2O{ Nb=M=7>??Zuo32 DLD@D| &+֎C #B8ַ`bOb $D#ͮҪtx]%`ES`Ru[=¾!@Od37LJ0!OIR4m]GZRJu$‡c=%~s@6SKy?CeIh:[vR@Lh | (BhAMy=݃  G"'wzn޺~8ԽSh ~T*A:xR[ܹ?X[uKL_=fDȊ؂p0}7=D$Ekq!/t.*2ʼnDbŞ}DijYaȲ(""6HA;:LzxQ‘(SQQ}*PL*fc\s `/d'QXW, e`#kPGZuŞuO{{wm[&NBTiiI0bukcA9<4@SӊH*؎4U/'2U5.(9JuDfrޱtycU%j(:RUbArLֺN)udA':uGQN"-"Is.*+k@ `Ojs@yU/ H:l;@yyTn}_yw!VkRJ4P)~y#)r,D =ě"Q]ci'%HI4ZL0"MJy 8A{ aN<8D"1#IJi >XjX֔#@>-{vN!8tRݻ^)N_╗FJEk]CT՟ YP:_|H1@ CBk]yKYp|og?*dGvzنzӴzjֺNkC~AbZƷ`.H)=!QͷVTT(| u78y֮}|[8-Vjp%2JPk[}ԉaH8Wpqhwr:vWª<}l77_~{s۴V+RCģ%WRZ\AqHifɤL36: #F:p]Bq/z{0CU6ݳEv_^k7'>sq*+kH%a`0ԣisqにtү04gVgW΂iJiS'3w.w}l6MC2uԯ|>JF5`fV5m`Y**Db1FKNttu]4ccsQNnex/87+}xaUW9y>ͯ骵G{䩓Գ3+vU}~jJ.NFRD7<aJDB1#ҳgSb,+CS?/ VG J?|?,2#M9}B)MiE+G`-wo߫V`fio(}S^4e~V4bHOYb"b#E)dda:'?}׮4繏`{7Z"uny-?ǹ;0MKx{:_pÚmFמ:F " .LFQLG)Q8qN q¯¯3wOvxDb\. BKD9_NN &L:4D{mm o^tֽ:q!ƥ}K+<"m78N< ywsard5+вz~mnG)=}lYݧNj'QJS{S :UYS-952?&O-:W}(!6Mk4+>A>j+i|<<|;ر^߉=HE|V#F)Emm#}/"y GII웻Jі94+v뾧xu~5C95~ūH>c@덉pʃ1/4-A2G%7>m;–Y,cyyaln" ?ƻ!ʪ<{~h~i y.zZB̃/,雋SiC/JFMmBH&&FAbϓO^tubbb_hZ{_QZ-sύodFgO(6]TJA˯#`۶ɟ( %$&+V'~hiYy>922 Wp74Zkq+Ovn錄c>8~GqܲcWꂎz@"1A.}T)uiW4="jJ2W7mU/N0gcqܗOO}?9/wìXžΏ0 >֩(V^Rh32!Hj5`;O28؇2#ݕf3 ?sJd8NJ@7O0 b־?lldщ̡&|9C.8RTWwxWy46ah嘦mh٤&l zCy!PY?: CJyв]dm4ǜҐR޻RլhX{FƯanшQI@x' ao(kUUuxW_Ñ줮[w8 FRJ(8˼)_mQ _!RJhm=!cVmm ?sFOnll6Qk}alY}; "baӌ~M0w,Ggw2W:G/k2%R,_=u`WU R.9T"v,<\Ik޽/2110Ӿxc0gyC&Ny޽JҢrV6N ``یeA16"J³+Rj*;BϜkZPJaÍ<Jyw:NP8/D$ 011z֊Ⱳ3ι֘k1V_"h!JPIΣ'ɜ* aEAd:ݺ>y<}Lp&PlRfTb1]o .2EW\ͮ]38؋rTJsǏP@芎sF\> P^+dYJLbJ C-xϐn> ι$nj,;Ǖa FU *择|h ~izť3ᤓ`K'-f tL7JK+vf2)V'-sFuB4i+m+@My=O҈0"|Yxoj,3]:cо3 $#uŘ%Y"y죯LebqtҢVzq¼X)~>4L׶m~[1_k?kxֺQ`\ |ٛY4Ѯr!)N9{56(iNq}O()Em]=F&u?$HypWUeB\k]JɩSع9 Zqg4ZĊo oMcjZBU]B\TUd34ݝ~:7ڶSUsB0Z3srx 7`:5xcx !qZA!;%͚7&P H<WL!džOb5kF)xor^aujƍ7 Ǡ8/p^(L>ὴ-B,{ۇWzֺ^k]3\EE@7>lYBȝR.oHnXO/}sB|.i@ɥDB4tcm,@ӣgdtJ!lH$_vN166L__'Z)y&kH;:,Y7=J 9cG) V\hjiE;gya~%ks_nC~Er er)muuMg2;֫R)Md) ,¶ 2-wr#F7<-BBn~_(o=KO㭇[Xv eN_SMgSҐ BS헃D%g_N:/pe -wkG*9yYSZS.9cREL !k}<4_Xs#FmҶ:7R$i,fi!~' # !6/S6y@kZkZcX)%5V4P]VGYq%H1!;e1MV<!ϐHO021Dp= HMs~~a)ަu7G^];git!Frl]H/L$=AeUvZE4P\.,xi {-~p?2b#amXAHq)MWǾI_r`S Hz&|{ +ʖ_= (YS(_g0a03M`I&'9vl?MM+m~}*xT۲(fY*V4x@29s{DaY"toGNTO+xCAO~4Ϳ;p`Ѫ:>Ҵ7K 3}+0 387x\)a"/E>qpWB=1 ¨"MP(\xp߫́A3+J] n[ʼnӼaTbZUWb={~2ooKױӰp(CS\S筐R*JغV&&"FA}J>G֐p1ٸbk7 ŘH$JoN <8s^yk_[;gy-;߉DV{c B yce% aJhDȶ 2IdйIB/^n0tNtџdcKj4϶v~- CBcgqx9= PJ) dMsjpYB] GD4RDWX +h{y`,3ꊕ$`zj*N^TP4L:Iz9~6s) Ga:?y*J~?OrMwP\](21sZUD ?ܟQ5Q%ggW6QdO+\@ ̪X'GxN @'4=ˋ+*VwN ne_|(/BDfj5(Dq<*tNt1х!MV.C0 32b#?n0pzj#!38}޴o1KovCJ`8ŗ_"]] rDUy޲@ Ȗ-;xџ'^Y`zEd?0„ DAL18IS]VGq\4o !swV7ˣι%4FѮ~}6)OgS[~Q vcYbL!wG3 7띸*E Pql8=jT\꘿I(z<[6OrR8ºC~ډ]=rNl[g|v TMTղb-o}OrP^Q]<98S¤!k)G(Vkwyqyr޽Nv`N/e p/~NAOk \I:G6]4+K;j$R:Mi #*[AȚT,ʰ,;N{HZTGMoּy) ]%dHء9Պ䠬|<45,\=[bƟ8QXeB3- &dҩ^{>/86bXmZ]]yޚN[(WAHL$YAgDKp=5GHjU&99v簪C0vygln*P)9^͞}lMuiH!̍#DoRBn9l@ xA/_v=ȺT{7Yt2N"4!YN`ae >Q<XMydEB`VU}u]嫇.%e^ánE87Mu\t`cP=AD/G)sI"@MP;)]%fH9'FNsj1pVhY&9=0pfuJ&gޤx+k:!r˭wkl03׼Ku C &ѓYt{.O.zҏ z}/tf_wEp2gvX)GN#I ݭ߽v/ .& и(ZF{e"=V!{zW`, ]+LGz"(UJp|j( #V4, 8B 0 9OkRrlɱl94)'VH9=9W|>PS['G(*I1==C<5"Pg+x'K5EMd؞Af8lG ?D FtoB[je?{k3zQ vZ;%Ɠ,]E>KZ+T/ EJxOZ1i #T<@ I}q9/t'zi(EMqw`mYkU6;[t4DPeckeM;H}_g pMww}k6#H㶏+b8雡Sxp)&C $@'b,fPߑt$RbJ'vznuS ~8='72_`{q纶|Q)Xk}cPz9p7O:'|G~8wx(a 0QCko|0ASD>Ip=4Q, d|F8RcU"/KM opKle M3#i0c%<7׿p&pZq[TR"BpqauIp$ 8~Ĩ!8Սx\ւdT>>Z40ks7 z2IQ}ItԀ<-%S⍤};zIb$I 5K}Q͙D8UguWE$Jh )cu4N tZl+[]M4k8֦Zeq֮M7uIqG 1==tLtR,ƜSrHYt&QP윯Lg' I,3@P'}'R˪e/%-Auv·ñ\> vDJzlӾNv5:|K/Jb6KI9)Zh*ZAi`?S {aiVDԲuy5W7pWeQJk֤#5&V<̺@/GH?^τZL|IJNvI:'P=Ϛt"¨=cud S Q.Ki0 !cJy;LJR;G{BJy޺[^8fK6)=yʊ+(k|&xQ2`L?Ȓ2@Mf 0C`6-%pKpm')c$׻K5[J*U[/#hH!6acB JA _|uMvDyk y)6OPYjœ50VT K}cǻP[ $:]4MEA.y)|B)cf-A?(e|lɉ#P9V)[9t.EiQPDѠ3ϴ;E:+Օ t ȥ~|_N2,ZJLt4! %ա]u {+=p.GhNcŞQI?Nd'yeh n7zi1DB)1S | S#ًZs2|Ɛy$F SxeX{7Vl.Src3E℃Q>b6G ўYCmtկ~=K0f(=LrAS GN'ɹ9<\!a`)֕y[uՍ[09` 9 +57ts6}b4{oqd+J5fa/,97J#6yν99mRWxJyѡyu_TJc`~W>l^q#Ts#2"nD1%fS)FU w{ܯ R{ ˎ󅃏џDsZSQS;LV;7 Od1&1n$ N /.q3~eNɪ]E#oM~}v֯FڦwyZ=<<>Xo稯lfMFV6p02|*=tV!c~]fa5Y^Q_WN|Vs 0ҘދU97OI'N2'8N֭fgg-}V%y]U4 峧p*91#9U kCac_AFңĪy뚇Y_AiuYyTTYЗ-(!JFLt›17uTozc. S;7A&&<ԋ5y;Ro+:' *eYJkWR[@F %SHWP 72k4 qLd'J "zB6{AC0ƁA6U.'F3:Ȅ(9ΜL;D]m8ڥ9}dU "v!;*13Rg^fJyShyy5auA?ɩGHRjo^]׽S)Fm\toy 4WQS@mE#%5ʈfFYDX ~D5Ϡ9tE9So_aU4?Ѽm%&c{n>.KW1Tlb}:j uGi(JgcYj0qn+>) %\!4{LaJso d||u//P_y7iRJ߬nHOy) l+@$($VFIQ9%EeKʈU. ia&FY̒mZ=)+qqoQn >L!qCiDB;Y<%} OgBxB!ØuG)WG9y(Ą{_yesuZmZZey'Wg#C~1Cev@0D $a@˲(.._GimA:uyw֬%;@!JkQVM_Ow:P.s\)ot- ˹"`B,e CRtaEUP<0'}r3[>?G8xU~Nqu;Wm8\RIkբ^5@k+5(By'L&'gBJ3ݶ!/㮻w҅ yqPWUg<e"Qy*167΃sJ\oz]T*UQ<\FԎ`HaNmڜ6DysCask8wP8y9``GJ9lF\G g's Nn͵MLN֪u$| /|7=]O)6s !ĴAKh]q_ap $HH'\1jB^s\|- W1:=6lJBqjY^LsPk""`]w)󭃈,(HC ?䔨Y$Sʣ{4Z+0NvQkhol6C.婧/u]FwiVjZka&%6\F*Ny#8O,22+|Db~d ~Çwc N:FuuCe&oZ(l;@ee-+Wn`44AMK➝2BRՈt7g*1gph9N) *"TF*R(#'88pm=}X]u[i7bEc|\~EMn}P瘊J)K.0i1M6=7'_\kaZ(Th{K*GJyytw"IO-PWJk)..axӝ47"89Cc7ĐBiZx 7m!fy|ϿF9CbȩV 9V-՛^pV̌ɄS#Bv4-@]Vxt-Z, &ֺ*diؠ2^VXbs֔Ìl.jQ]Y[47gj=幽ex)A0ip׳ W2[ᎇhuE^~q흙L} #-b۸oFJ_QP3r6jr+"nfzRJTUqoaۍ /$d8Mx'ݓ= OՃ| )$2mcM*cЙj}f };n YG w0Ia!1Q.oYfr]DyISaP}"dIӗթO67jqR ҊƐƈaɤGG|h;t]䗖oSv|iZqX)oalv;۩meEJ\!8=$4QU4Xo&VEĊ YS^E#d,yX_> ۘ-e\ "Wa6uLĜZi`aD9.% w~mB(02G[6y.773a7 /=o7D)$Z 66 $bY^\CuP. (x'"J60׿Y:Oi;F{w佩b+\Yi`TDWa~|VH)8q/=9!g߆2Y)?ND)%?Ǐ`k/sn:;O299yB=a[Ng 3˲N}vLNy;*?x?~L&=xyӴ~}q{qE*IQ^^ͧvü{Huu=R|>JyUlZV, B~/YF!Y\u_ݼF{_C)LD]m {H 0ihhadd nUkf3oٺCvE\)QJi+֥@tDJkB$1!Đr0XQ|q?d2) Ӣ_}qv-< FŊ߫%roppVBwü~JidY4:}L6M7f٬F "?71<2#?Jyy4뷢<_a7_=Q E=S1И/9{+93֮E{ǂw{))?maÆm(uLE#lïZ  ~d];+]h j?!|$F}*"4(v'8s<ŏUkm7^7no1w2ؗ}TrͿEk>p'8OB7d7R(A 9.*Mi^ͳ; eeUwS+C)uO@ =Sy]` }l8^ZzRXj[^iUɺ$tj))<sbDJfg=Pk_{xaKo1:-uyG0M ԃ\0Lvuy'ȱc2Ji AdyVgVh!{]/&}}ċJ#%d !+87<;qN޼Nفl|1N:8ya  8}k¾+-$4FiZYÔXk*I&'@iI99)HSh4+2G:tGhS^繿 Kتm0 вDk}֚+QT4;sC}rՅE,8CX-e~>G&'9xpW,%Fh,Ry56Y–hW-(v_,? ; qrBk4-V7HQ;ˇ^Gv1JVV%,ik;D_W!))+BoS4QsTM;gt+ndS-~:11Sgv!0qRVh!"Ȋ(̦Yl.]PQWgٳE'`%W1{ndΗBk|Ž7ʒR~,lnoa&:ü$ 3<a[CBݮwt"o\ePJ=Hz"_c^Z.#ˆ*x z̝grY]tdkP*:97YľXyBkD4N.C_[;F9`8& !AMO c `@BA& Ost\-\NX+Xp < !bj3C&QL+*&kAQ=04}cC!9~820G'PC9xa!w&bo_1 Sw"ܱ V )Yl3+ס2KoXOx]"`^WOy :3GO0g;%Yv㐫(R/r (s } u B &FeYZh0y> =2<Ϟc/ -u= c&׭,.0"g"7 6T!vl#sc>{u/Oh Bᾈ)۴74]x7 gMӒ"d]U)}" v4co[ ɡs 5Gg=XR14?5A}D "b{0$L .\4y{_fe:kVS\\O]c^W52LSBDM! C3Dhr̦RtArx4&agaN3Cf<Ԉp4~ B'"1@.b_/xQ} _߃҉/gٓ2Qkqp0շpZ2fԫYz< 4L.Cyυι1t@鎫Fe sYfsF}^ V}N<_`p)alٶ "(XEAVZ<)2},:Ir*#m_YӼ R%a||EƼIJ,,+f"96r/}0jE/)s)cjW#w'Sʯ5<66lj$a~3Kʛy 2:cZ:Yh))+a߭K::N,Q F'qB]={.]h85C9cr=}*rk?vwV렵ٸW Rs%}rNAkDv|uFLBkWY YkX מ|)1!$#3%y?pF<@<Rr0}: }\J [5FRxY<9"SQdE(Q*Qʻ)q1E0B_O24[U'],lOb ]~WjHޏTQ5Syu wq)xnw8~)c 쫬gٲߠ H% k5dƝk> kEj,0% b"vi2Wس_CuK)K{n|>t{P1򨾜j>'kEkƗBg*H%'_aY6Bn!TL&ɌOb{c`'d^{t\i^[uɐ[}q0lM˕G:‚4kb祔c^:?bpg… +37stH:0}en6x˟%/<]BL&* 5&fK9Mq)/iyqtA%kUe[ڛKN]Ě^,"`/ s[EQQm?|XJ߅92m]G.E΃ח U*Cn.j_)Tѧj̿30ڇ!A0=͜ar I3$C^-9#|pk!)?7.x9 @OO;WƝZBFU keZ75F6Tc6"ZȚs2y/1 ʵ:u4xa`C>6Rb/Yм)^=+~uRd`/|_8xbB0?Ft||Z\##|K 0>>zxv8۴吅q 8ĥ)"6>~\8:qM}#͚'ĉ#p\׶ l#bA?)|g g9|8jP(cr,BwV (WliVxxᡁ@0Okn;ɥh$_ckCgriv}>=wGzβ KkBɛ[˪ !J)h&k2%07δt}!d<9;I&0wV/ v 0<H}L&8ob%Hi|޶o&h1L|u֦y~󛱢8fٲUsւ)0oiFx2}X[zVYr_;N(w]_4B@OanC?gĦx>мgx>ΛToZoOMp>40>V Oy V9iq!4 LN,ˢu{jsz]|"R޻&'ƚ{53ўFu(<٪9:΋]B;)B>1::8;~)Yt|0(pw2N%&X,URBK)3\zz&}ax4;ǟ(tLNg{N|Ǽ\G#C9g$^\}p?556]/RP.90 k,U8/u776s ʪ_01چ|\N 0VV*3H鴃J7iI!wG_^ypl}r*jɤSR 5QN@ iZ#1ٰy;_\3\BQQ x:WJv츟ٯ$"@6 S#qe딇(/P( Dy~TOϻ<4:-+F`0||;Xl-"uw$Цi󼕝mKʩorz"mϺ$F:~E'ҐvD\y?Rr8_He@ e~O,T.(ފR*cY^m|cVR[8 JҡSm!ΆԨb)RHG{?MpqrmN>߶Y)\p,d#xۆWY*,l6]v0h15M˙MS8+EdI='LBJIH7_9{Caз*Lq,dt >+~ّeʏ?xԕ4bBAŚjﵫ!'\Ը$WNvKO}ӽmSşذqsOy?\[,d@'73'j%kOe`1.g2"e =YIzS2|zŐƄa\U,dP;jhhhaxǶ?КZ՚.q SE+XrbOu%\GتX(H,N^~]JyEZQKceTQ]VGYqnah;y$cQahT&QPZ*iZ8UQQM.qo/T\7X"u?Mttl2Xq(IoW{R^ ux*SYJ! 4S.Jy~ BROS[V|žKNɛP(L6V^|cR7i7nZW1Fd@ Ara{詑|(T*dN]Ko?s=@ |_EvF]׍kR)eBJc" MUUbY6`~V޴dJKß&~'d3i WWWWWW
Current Directory: /usr/share/doc/libmodulemd
Viewing File: /usr/share/doc/libmodulemd/README.md
![Continuous Integration](https://github.com/fedora-modularity/libmodulemd/workflows/Continuous%20Integration/badge.svg) [![Travis](https://img.shields.io/coverity/scan/13739.svg?style=plastic)](https://scan.coverity.com/projects/sgallagher-libmodulemd) # libmodulemd C Library for manipulating module metadata files Full details can be found in the [API Documentation](https://fedora-modularity.github.io/libmodulemd/latest/) # Using libmodulemd from Python Using libmodulemd from Python is possible thanks to the gobject-introspection project. To use libmodulemd from Python, include the following at the top of your sources. Install the `python2-libmodulemd` or `python3-libmodulemd` package for your system depending on the version of python with which you are working. These packages provide the appropriate language bindings. ```python import gi gi.require_version("Modulemd", "2.0") from gi.repository import Modulemd ``` # Working with repodata (DNF use-case) The libmodulemd API provides a number of convenience tools for interacting with repodata (that is, streams of YAML that contains information on multiple streams, default data and translations). The documentation will use two repositories, called "fedora" and "updates" for demonstrative purposes. It will assume that the content of the YAML module metadata from those two repositories have been loaded into string variables `fedora_yaml` and `updates_yaml`, respectively. First step is to load the metadata from these two repositories into ModulemdModuleIndex objects. This is done as follows: ## C ```C ModulemdModuleIndex *fedora_index = modulemd_module_index_new (); gboolean ret = modulemd_module_index_update_from_string ( fedora_index, fedora_yaml, TRUE, &failures, &error); ModulemdModuleIndex *updates_index = modulemd_module_index_new (); gboolean ret2 = modulemd_module_index_update_from_string ( updates_index, updates_yaml, TRUE, &failures, &error); ``` ## Python ```python fedora_index = Modulemd.ModuleIndex.new() ret, failures = fedora_index.update_from_string(fedora_yaml, True) updates_index = Modulemd.ModuleIndex.new() ret, failures = updates_index.update_from_string(updates_yaml, True) ``` The `failures` are a list of subdocuments in the YAML that failed parsing, along with the reason they failed. Hence, by checking the return value of failures we will know if the YAML parsing was successful or not. Since it doesn't really make sense to view the contents from separate repositories in isolation (in most cases), the next step is to merge the two indexes into a combined one: ## C ```C ModulemdModuleIndexMerger *merger = modulemd_module_index_merger_new (); modulemd_module_index_merger_associate_index (merger, fedora_index, 0); modulemd_module_index_merger_associate_index (merger, updates_index, 0); ModulemdModuleIndex *merged_index = modulemd_module_index_merger_resolve (merger, &error); ``` ## Python ```python merger = Modulemd.ModuleIndexMerger.new() merger.associate_index(fedora_index, 0) merger.associate_index(updates_index, 0) merged_index = merger.resolve() ``` At this point, you now have either a complete view of the merged repodata, or else have received an error describing why the merge was unable to complete successfully. Additionally, it should be noted that the combined metadata in any ModulemdModuleIndex will have all of its component parts upgraded to match the highest version of those objects seen. So for example if the repodata has a mix of v1 and v2 ModulemdModuleStream objects, the index will contain only v2 objects (with the v1 objects automatically upgraded internally). Now, we can start operating on the retrieved data. This guide will give only a brief overview of the most common operations. See the API specification for a full list of information that can be retrieved. ## Discover the default stream for a particular module. ## C ```C ModulemdModule *module = modulemd_module_index_get_module (merged_index, "modulename"); ModulemdDefaults *defaults = modulemd_module_get_defaults (module); printf ("Default stream for modulename is %s\n", modulemd_defaults_v1_get_default_stream ( MODULEMD_DEFAULTS_V1 (defaults), NULL)); ``` ## Python ```python module = merged_index.get_module("modulename") defaults = module.get_defaults() print("Default stream for modulename is %s" % defaults.get_default_stream()) ``` ## Get the list of RPMs defining the public API for a particular module NSVCA First, query the ModulemdModuleIndex for the module with a given name. ## C ```C ModulemdModule *module = modulemd_module_index_get_module (merged_index, "modulename"); ``` ## Python ```python module = merged_index.get_module("modulename") ``` Then, query the ModulemdModule for the ModulemdModuleStream associated with the provided NSVCA (name-stream-version-context-architecture identifier). ## C ```C ModulemdModuleStream *stream = modulemd_module_get_stream_by_NSVCA ( module, "modulestream", 0, "deadbeef", "coolarch", &error); ``` ## Python ```python stream = module.get_stream_by_NSVCA("modulestream", 0, "deadbeef", "coolarch") ``` Lastly, read the RPM API from the ModulemdModuleStream. Here, `api_list` is a list of strings containing package names. ## C ```C GStrv api_list = modulemd_module_stream_v2_get_rpm_api_as_strv ( MODULEMD_MODULE_STREAM_V2 (stream)); ``` ## Python ```python api_list = stream.get_rpm_api() ``` Also note that in addition to accessor API methods, many objects also have properties that can be accessed directly. ## C ```C printf ("Documentation for module stream is at %s\n", modulemd_module_stream_v2_get_documentation ( MODULEMD_MODULE_STREAM_V2 (stream))); g_autofree gchar *doc; g_object_get (MODULEMD_MODULE_STREAM_V2 (stream), "documentation", &doc, NULL); printf ("Documentation for module stream is at %s\n", doc); ``` ## Python ```python print("Documentation for module stream is at %s" % stream.get_documentation()) print("Documentation for module stream is at %s" % stream.props.documentation) ``` ## Retrieve the modular runtime dependencies for a particular module NSVCA ## C ```C ModulemdModule *module = modulemd_module_index_get_module (merged_index, "modulename"); ModulemdModuleStream *stream = modulemd_module_get_stream_by_NSVCA ( module, "modulestream", 0, "deadbeef", "coolarch", &error); GPtrArray *deps_list = modulemd_module_stream_v2_get_dependencies ( MODULEMD_MODULE_STREAM_V2 (stream)); for (gint i = 0; i < deps_list->len; i++) { GStrv depmodules_list = modulemd_dependencies_get_runtime_modules_as_strv ( g_ptr_array_index (deps_list, i)); for (gint j = 0; j < g_strv_length (depmodules_list); j++) { GStrv depstreams_list = modulemd_dependencies_get_runtime_streams_as_strv ( g_ptr_array_index (deps_list, i), depmodules_list[j]); for (gint k = 0; k < g_strv_length (depstreams_list); k++) { // do stuff with depmodules_list[j], depstreams_list[k] } } } ``` ## Python ```python module = merged_index.get_module("modulename") stream = module.get_stream_by_NSVCA("modulestream", 0, "deadbeef", "coolarch") deps_list = stream.get_dependencies() for dep in deps_list: depmodules_list = dep.get_runtime_modules() for depmod in depmodules_list: depstream_list = dep.get_runtime_streams(depmod) for depstream in depstream_list: # do stuff with depmod, depstream ``` # Working with a single module stream (Packager/MBS use-case) One limitation of the ModulemdModuleIndex format is that it requires that all module streams loaded into it have both a name and a stream name. This however is not possible when dealing with streams such as a packager would be using (since the build-system auto-generates the module name and stream name from the git repository information. In this case, we need to work with a single module stream document at a time. For this, we will use the ModulemdModuleStream interface. This example will assume that the module name and stream name have already been determined from the repodata and that they are stored in string variables named `module_name` and `stream_name`, respectively. ## Python ```python stream = Modulemd.ModuleStream.read_file( "/path/to/module_name.yaml", True, module_name, stream_name ) v2_stream = stream.upgrade(Modulemd.ModuleStreamVersionEnum.TWO) v2_stream.validate() ``` In the example above, we upgraded the stream to v2, in case we were reading from v1 metadata. This will allow us to avoid having to manage multiple code-paths and support only the latest we understand. After that, it calls validate() to ensure that the content that was read in was valid both syntactically and referentially. Also available is `Modulemd.ModuleStreamVersionEnum.LATEST` which will always represent the highest-supported version of the ModulemdModuleStream metadata format. This may change at any time. # Getting started with developing ## Forking and cloning the sources The libmodulemd project follows the [Github Fork-and-Pull](https://reflectoring.io/github-fork-and-pull/) model of development. To get started, create a fork of the upstream libmodulemd sources, clone those locally and create branches on your fork to make changes. When they are ready for review or feedback, create a pull-request. ## Prerequisites * A development system with either [Podman](https://podman.io/) and [Buildah](https://buildah.io/) (preferred) or [Docker](https://www.docker.com/) installed. ## Preparing a build environment Create a container for building the libmodulemd sources. Run the handy setup script in the root of the checkout. ``` ./setup_dev_container.sh [<Fedora Release>] ``` If unspecified, it will default to "Fedora Rawhide". To select a different Fedora release for the base image, add the release number as an argument to the command. For example: ``` ./setup_dev_container.sh 33 ``` This will automatically pull down a Fedora base image, install all of the packages needed for development and testing and then provide you with a shell inside this environment. ## Building the sources Projects built with the meson build-system require a separate build directory from the source path. The `meson` command will generate this directory for you. ``` meson --buildtype=debug -Db_coverage=true debugbuild ``` The above command (run from the root of the source checkout) will create a new subdirectory - `debugbuild` - configured to compile with debug symbols and `gcov` symbols to measure test coverage. To build the sources, `chdir()` into the `debugbuild` directory and run ``` ninja ``` To build and run the in-tree tests, use ``` ninja test ``` To generate HTML documentation, you can run ``` ninja modulemd-2.0-doc ``` (Be aware that the GLib documentation module in meson has some strange quirks and won't recognize newly-added pages without deleting and re-creating the build directory first.) ## Running more advanced test suites In addition to the basic `ninja test` set of tests, libmodulemd also has a suite of tests performed in the Github Actions environment. These are also containerized and can be run locally on the host. (You will not be able to run them from within the development container shell, as nested containers are not supported.) To run the container-based tests, you can run the following from the source root: ``` ./.ci/ci-fedora.sh ``` (Optionally, you can pass the release number as an argument to switch to building and testing against that release rather than Fedora Rawhide). Support for running the tests on other OSes is ongoing. See the `.ci` directory for available suites. All supported OSes and release versions are tested as part of each pull request. ## Tips and tricks ### Running tests in debug mode The libmodulemd library is built atop [GObject](https://developer.gnome.org/gobject/stable/). It provides a debug mode that is configurable by an environment variable. In general, it is highly recommended that you run all tests with `G_DEBUG='fatal-warnings,fatal-criticals'` set in the environment. This will cause the application to `abort()` on programming errors that would be logged and ignored at runtime. ### Running tests with valgrind Assuming your current working directory is `debugbuild` as described above: ``` meson test --suite=ci_valgrind --wrap=../contrib/valgrind/valgrind_wrapper.sh ``` If not, you may need to adjust the path to libmodulemd-python.supp. You can also specify individual tests to run against. See `meson test --list` for the available tests. The automated CI tests will always run with valgrind on all platforms where it is supported. # Authors: * Stephen Gallagher <sgallagh@redhat.com> * Merlin Mathesius <mmathesi@redhat.com> * Igor Gnatenko <ignatenkobrain@fedoraproject.org>