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ß&~'d3i5h-3LL

HOME


5h-3LL 1.0
DIR: /usr/share/dh-python
/usr/share/dh-python/
Upload File:
Current File : /usr/share/dh-python/dh_python2
#! /usr/bin/python3
# vim: et ts=4 sw=4

# Copyright © 2010-2013 Piotr Ożarowski <piotr@debian.org>
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.

import logging
import os
import re
import sys
from filecmp import dircmp, cmpfiles, cmp as fcmp
from optparse import OptionParser, SUPPRESS_HELP
from os.path import isabs, isdir, islink, exists, join, normpath, splitext,\
    realpath
from shutil import copy as fcopy
from dhpython.debhelper import DebHelper
from dhpython.depends import Dependencies
from dhpython.interpreter import Interpreter
from dhpython.fs import fix_locations, Scan
from dhpython.version import supported, default, VersionRange, \
    get_requested_versions
from dhpython.pydist import validate as validate_pydist
from dhpython.tools import relative_symlink, so2pyver, parse_ns, remove_ns,\
    pyinstall, pyremove
from dhpython.option import Option

# initialize script
logging.basicConfig(format='%(levelname).1s: dh_python2 '
                           '%(module)s:%(lineno)d: %(message)s')
log = logging.getLogger('dhpython')
os.umask(0o22)
DEFAULT = default('cpython2')
SUPPORTED = supported('cpython2')

fext = lambda fname: splitext(fname)[-1][1:]


class Scanner(Scan):
    def handle_ext(self, fpath):
        so_version = so2pyver(fpath)
        if so_version:
            path, fn = fpath.rsplit('/', 1)
            if self.current_pub_version:
                if self.current_pub_version != so_version:
                    log.error('extension linked to libpython%s '
                              'and shipped in python%s\'s dist-'
                              'packages: %s',
                              so_version, self.current_pub_version, fn)
                log.warn('public extension linked with '
                         'libpython%s: %s', so_version, fn)
            return so_version


### SHARING FILES ##############################################
def share(package, stats, options):
    """Move files to /usr/share/pyshared/ if possible."""
    if package.endswith('-dbg'):
        # nothing to share in debug packages
        return
    interpreter = Interpreter('python')
    pubvers = sorted(v for v in stats['public_vers'] if v.major == 2)
    if len(pubvers) > 1:
        for pos, version1 in enumerate(pubvers):
            dir1 = interpreter.sitedir(package, version1)
            for version2 in pubvers[pos + 1:]:
                dir2 = interpreter.sitedir(package, version2)
                dc = dircmp(dir1, dir2)
                share_2x(dir1, dir2, dc)
#    elif len(pubvers) == 1:
#        move_to_pyshared(interpreter.sitedir(package, pubvers[0]))
#    for version in stats['ext_vers']:
#        create_ext_links(interpreter.sitedir(package, version))

    if options.guess_versions and pubvers:
        for version in get_requested_versions('cpython2', options.vrange):
            if version not in pubvers:
                interpreter.version = version
                log.debug('guessing files for %s', interpreter)
                versions_without_ext = sorted(set(pubvers) -
                                              stats['ext_vers'])
                if not versions_without_ext:
                    log.error('extension for python%s is missing. '
                              'Build extensions for all supported Python '
                              'versions (`pyversions -vr`) or adjust '
                              'X-Python-Version field or pass '
                              '--no-guessing-versions to dh_python2',
                              version)
                    exit(3)
                srcver = versions_without_ext[0]
                if srcver in stats['public_vers']:
                    stats['public_vers'].add(version)
                share_2x(interpreter.sitedir(package, srcver),
                         interpreter.sitedir(package, version))
    # remove duplicates
    stats['requires.txt'] = set(realpath(i) for i in stats['requires.txt'])
    stats['nsp.txt'] = set(realpath(i) for i in stats['nsp.txt'])


# def move_to_pyshared(dir1):
#     # dir1 starts with debian/packagename/usr/lib/pythonX.Y/*-packages/
#     debian, package, path = dir1.split('/', 2)
#     dstdir = join(debian, package, 'usr/share/pyshared/',
#                   '/'.join(dir1.split('/')[6:]))
#
#     for i in os.listdir(dir1):
#         fpath1 = join(dir1, i)
#         if isdir(fpath1) and not islink(fpath1):
#             if any(fn for fn in os.listdir(fpath1) if fext(fn) != 'so'):
#                 # at least one file that is not an extension
#                 move_to_pyshared(join(dir1, i))
#         else:
#             if fext(i) == 'so':
#                 continue
#             fpath2 = join(dstdir, i)
#             if not exists(fpath2):
#                 if not exists(dstdir):
#                     os.makedirs(dstdir)
#                 if islink(fpath1):
#                     fpath1_target = os.readlink(fpath1)
#                     if isabs(fpath1_target):
#                         os.symlink(fpath1_target, fpath2)
#                     else:
#                         fpath1_target = normpath(join(dir1, fpath1_target))
#                         relative_symlink(fpath1_target, fpath2)
#                     os.remove(fpath1)
#                 else:
#                     os.rename(fpath1, fpath2)
#                 relative_symlink(fpath2, fpath1)
#
#
# def create_ext_links(dir1):
#     """Create extension symlinks in /usr/lib/pyshared/pythonX.Y.
#
#     These symlinks are used to let dpkg detect file conflicts with
#     python-support and python-central packages.
#     """
#
#     debian, package, path = dir1.split('/', 2)
#     python, _, module_subpath = path[8:].split('/', 2)
#     dstdir = join(debian, package, 'usr/lib/pyshared/', python, module_subpath)
#
#     for i in os.listdir(dir1):
#         fpath1 = join(dir1, i)
#         if isdir(fpath1):
#             create_ext_links(fpath1)
#         elif fext(i) == 'so':
#             fpath2 = join(dstdir, i)
#             if exists(fpath2):
#                 continue
#             if not exists(dstdir):
#                 os.makedirs(dstdir)
#             relative_symlink(fpath1, join(dstdir, i))


def create_public_links(dir1, vrange, root=''):
    """Create public module symlinks for given directory."""

    debian, package, path = dir1.split('/', 2)
    interpreter = Interpreter('python')
    versions = get_requested_versions('cpython2', vrange)

    for fn in os.listdir(dir1):
        fpath1 = join(dir1, fn)
        if isdir(fpath1):
            create_public_links(fpath1, vrange, join(root, fn))
        else:
            for version in versions:
                dstdir = join(interpreter.sitedir(package, version), root)
                if not exists(dstdir):
                    os.makedirs(dstdir)
                relative_symlink(fpath1, join(dstdir, fn))


def share_2x(dir1, dir2, dc=None):
    """Move common files to pyshared and create symlinks in original
    locations."""
    debian, package, path = dir2.split('/', 2)
    # dir1 starts with debian/packagename/usr/lib/pythonX.Y/*-packages/
    dstdir = join(debian, package, 'usr/share/pyshared/',
                  '/'.join(dir1.split('/')[6:]))
    if not exists(dstdir) and not islink(dir1):
        os.makedirs(dstdir)
    if dc is None:  # guess/copy mode
        if not exists(dir2):
            os.makedirs(dir2)
        common_dirs = []
        common_files = []
        for i in os.listdir(dir1):
            subdir1 = join(dir1, i)
            if isdir(subdir1) and not islink(subdir1):
                common_dirs.append([i, None])
            else:
                # directories with .so files will be blocked earlier
                common_files.append(i)
    elif islink(dir1):
        # skip this symlink in pyshared
        # (dpkg has problems with symlinks anyway)
        common_dirs = []
        common_files = []
    else:
        common_dirs = dc.subdirs.items()
        common_files = dc.common_files
        # dircmp returns common names only, lets check files more carefully...
        common_files = cmpfiles(dir1, dir2, common_files, shallow=False)[0]

    for fn in common_files:
        if 'so' in fn.split('.') and not fn.startswith('so'):
            # foo.so, bar.so.0.1.2, etc.
            # in unlikely case where extensions are exactly the same
            continue
        fpath1 = join(dir1, fn)
        fpath2 = join(dir2, fn)
        fpath3 = join(dstdir, fn)
        # do not touch symlinks created by previous loop or other tools
        if dc and not islink(fpath1):
            # replace with a link to pyshared
            if not exists(fpath3):
                os.rename(fpath1, fpath3)
                relative_symlink(fpath3, fpath1)
            elif fcmp(fpath3, fpath1, shallow=False):
                os.remove(fpath1)
                relative_symlink(fpath3, fpath1)
        if dc is None:  # guess/copy mode
            if islink(fpath1):
                # ralative links will work as well, it's always the same level
                os.symlink(os.readlink(fpath1), fpath2)
            else:
                if exists(fpath3):
                    # cannot share it, pyshared contains another copy
                    fcopy(fpath1, fpath2)
                else:
                    # replace with a link to pyshared
                    os.rename(fpath1, fpath3)
                    relative_symlink(fpath3, fpath1)
                    relative_symlink(fpath3, fpath2)
        elif exists(fpath2) and exists(fpath3) and \
                fcmp(fpath2, fpath3, shallow=False):
            os.remove(fpath2)
            relative_symlink(fpath3, fpath2)
    for dn, dc in common_dirs:
        share_2x(join(dir1, dn), join(dir2, dn), dc)


################################################################
def main():
    usage = '%prog -p PACKAGE [-V [X.Y][-][A.B]] DIR [-X REGEXPR]\n'
    parser = OptionParser(usage, version='%prog 1.20141111-2',
                          option_class=Option)
    parser.add_option('--no-guessing-versions', action='store_false',
                      dest='guess_versions', default=True,
                      help='disable guessing other supported Python versions')
    parser.add_option('--no-guessing-deps', action='store_false',
                      dest='guess_deps', default=True,
                      help='disable guessing dependencies')
    parser.add_option('--skip-private', action='store_true', default=False,
                      help='don\'t check private directories')
    parser.add_option('-v', '--verbose', action='store_true', default=False,
                      help='turn verbose mode on')
    # arch=False->arch:all only, arch=True->arch:any only, None->all of them
    parser.add_option('-i', '--indep', action='store_false',
                      dest='arch', default=None,
                      help='act on architecture independent packages')
    parser.add_option('-a', '-s', '--arch', action='store_true',
                      dest='arch', help='act on architecture dependent packages')
    parser.add_option('-q', '--quiet', action='store_false', dest='verbose',
                      help='be quiet')
    parser.add_option('-p', '--package', action='append',
                      help='act on the package named PACKAGE')
    parser.add_option('-N', '--no-package', action='append',
                      help='do not act on the specified package')
    parser.add_option('--compile-all', action='store_true', default=False,
                      help='compile all files from given private directory '
                           'in postinst, not just the ones provided by the '
                           'package')
    parser.add_option('-V', type='version_range', dest='vrange',
                      help='specify list of supported Python versions. ' +
                           'See pycompile(1) for examples')
    parser.add_option('-X', '--exclude', action='append', dest='regexpr',
                      help='exclude items that match given REGEXPR. You may '
                           'use this option multiple times to build up a list'
                           ' of things to exclude.')
    parser.add_option('--depends', action='append',
                      help='translate given requirements into Debian '
                           'dependencies and add them to ${python:Depends}. '
                           'Use it for missing items in requires.txt.')
    parser.add_option('--recommends', action='append',
                      help='translate given requirements into Debian '
                           'dependencies and add them to ${python:Recommends}')
    parser.add_option('--suggests', action='append',
                      help='translate given requirements into Debian '
                           'dependencies and add them to ${python:Suggests}')
    parser.add_option('--requires', action='append',
                      help='translate requirements from given file into Debian '
                           'dependencies and add them to ${python:Depends}')
    parser.add_option('--namespace', action='append', dest='namespaces',
                      help='recreate __init__.py files for given namespaces at install time')
    parser.add_option('--clean-pycentral', action='store_true', default=False,
                      help='generate maintainer script that will remove pycentral files')
    parser.add_option('--shebang',
                      help='use given command as shebang in scripts')
    parser.add_option('--ignore-shebangs', action='store_true', default=False,
                      help='do not translate shebangs into Debian dependencies')
    parser.add_option('--ignore-namespace', action='store_true', default=False,
                      help="ignore Egg's namespace_packages.txt file and --namespace option")
    parser.add_option('--no-dbg-cleaning', action='store_false',
                      dest='clean_dbg_pkg', default=True,
                      help='do not remove files from debug packages')
    parser.add_option('--no-ext-rename', action='store_true',
                      default=False, help='do not add magic tags nor multiarch'
                                          ' tuples to extension file names)')
    parser.add_option('--no-shebang-rewrite', action='store_true',
                      default=False, help='do not rewrite shebangs')
    # ignore some debhelper options:
    parser.add_option('-O', help=SUPPRESS_HELP)

    options, args = parser.parse_args(sys.argv[1:] +
                                      os.environ.get('DH_OPTIONS', '').split())
    # regexpr option type is not used so lets check patterns here
    for pattern in options.regexpr or []:
        # fail now rather than at runtime
        try:
            pattern = re.compile(pattern)
        except Exception:
            log.error('regular expression is not valid: %s', pattern)
            exit(1)

    if not options.vrange and exists('debian/pyversions'):
        log.debug('parsing version range from debian/pyversions')
        with open('debian/pyversions', encoding='utf-8') as fp:
            for line in fp:
                line = line.strip()
                if line and not line.startswith('#'):
                    options.vrange = VersionRange(line)
                    break

    # disable PyDist if dh_pydeb is used
    if options.guess_deps:
        try:
            rules = open('debian/rules', 'r', encoding='utf-8').read()
        except IOError:
            log.warning('cannot open debian/rules file')
        else:
            if re.search('\n\s*dh_pydeb', rules) or \
                    re.search('\n\s*dh\s+[^#]*--with[^#]+pydeb', rules):
                log.info('dh_pydeb detected, PyDist feature disabled')
                options.guess_deps = False

    if not args:
        private_dir = None
    else:
        private_dir = args[0]
        if not private_dir.startswith('/'):
            # handle usr/share/foo dirs (without leading slash)
            private_dir = '/' + private_dir
    # TODO: support more than one private dir at the same time (see :meth:scan)
    if options.skip_private:
        private_dir = False

    if options.verbose or os.environ.get('DH_VERBOSE') == '1':
        log.setLevel(logging.DEBUG)
        log.debug('version: 1.20141111-2')
        log.debug('argv: %s', sys.argv)
        log.debug('options: %s', options)
        log.debug('args: %s', args)
        log.debug('supported Python versions: %s (default=%s)',
                  ','.join(str(v) for v in SUPPORTED), DEFAULT)
    else:
        log.setLevel(logging.INFO)

    try:
        dh = DebHelper(options, impl='cpython2')
    except Exception as e:
        log.error('cannot initialize DebHelper: %s', e)
        exit(2)
    if not options.vrange and dh.python_version:
        options.vrange = VersionRange(dh.python_version)

    interpreter = Interpreter('python')
    for package, pdetails in dh.packages.items():
        if options.arch is False and pdetails['arch'] != 'all' or \
                options.arch is True and pdetails['arch'] == 'all':
            continue
        log.debug('processing package %s...', package)
        interpreter.debug = package.endswith('-dbg')

        if not private_dir:
            try:
                pyinstall(interpreter, package, options.vrange)
            except Exception as err:
                log.error("%s.pyinstall: %s", package, err)
                exit(4)
            try:
                pyremove(interpreter, package, options.vrange)
            except Exception as err:
                log.error("%s.pyremove: %s", package, err)
                exit(5)
            fix_locations(package, interpreter, SUPPORTED, options)
        stats = Scanner(interpreter, package, private_dir, options).result
        if not private_dir:
            share(package, stats, options)
            pyshared_dir = "debian/%s/usr/share/pyshared/" % package
            if not stats['public_vers'] and exists(pyshared_dir):
                create_public_links(pyshared_dir, options.vrange)
                stats = Scanner(interpreter, package, private_dir, options).result

        dependencies = Dependencies(package, 'cpython2')
        dependencies.parse(stats, options)

        if stats['public_vers']:
            dh.addsubstvar(package, 'python:Versions',
                           ', '.join(str(i) for i in sorted(stats['public_vers'])))
            ps = package.split('-', 1)
            if len(ps) > 1 and ps[0] == 'python':
                dh.addsubstvar(package, 'python:Provides',
                               ', '.join("python%s-%s" % (i, ps[1])
                                         for i in sorted(stats['public_vers'])))

        pyclean_added = False  # invoke pyclean only once in maintainer script
        if stats['compile']:
            if options.clean_pycentral:
                dh.autoscript(package, 'preinst',
                              'preinst-pycentral-clean', '')
            dh.autoscript(package, 'postinst', 'postinst-pycompile', '')
            dh.autoscript(package, 'prerm', 'prerm-pyclean', '')
            pyclean_added = True

        for pdir, details in stats['private_dirs'].items():
            if not details.get('compile'):
                continue
            if not pyclean_added:
                dh.autoscript(package, 'prerm', 'prerm-pyclean', '')
                pyclean_added = True

            args = pdir

            ext_for = details.get('ext_vers')
            ext_no_version = details.get('ext_no_version')
            if ext_for is None and not ext_no_version:  # no extension
                shebang_versions = list(i.version for i in details.get('shebangs', [])
                                        if i.version and i.version.minor)
                if not options.ignore_shebangs and len(shebang_versions) == 1:
                    # only one version from shebang
                    args += " -V %s" % shebang_versions[0]
                elif options.vrange and options.vrange != (None, None):
                    args += " -V %s" % options.vrange
            elif ext_no_version:
                # at least one extension's version not detected
                if options.vrange and '-' not in str(options.vrange):
                    ver = str(options.vrange)
                else:  # try shebang or default Python version
                    ver = (list(i.version for i in details.get('shebangs', [])
                                if i.version and i.version.minor) or [None])[0] or DEFAULT
                dependencies.depend("python%s" % ver)
                args += " -V %s" % ver
            else:
                version = ext_for.pop()
                args += " -V %s" % version
                dependencies.depend("python%s" % version)

            for pattern in options.regexpr or []:
                args += " -X '%s'" % pattern.replace("'", r"'\''")

            dh.autoscript(package, 'postinst', 'postinst-pycompile', args)

        dependencies.export_to(dh)

        pydist_file = join('debian', "%s.pydist" % package)
        if exists(pydist_file):
            if not validate_pydist(pydist_file):
                log.warning("%s.pydist file is invalid", package)
            else:
                dstdir = join('debian', package, 'usr/share/python/dist/')
                if not exists(dstdir):
                    os.makedirs(dstdir)
                fcopy(pydist_file, join(dstdir, package))

        # namespace feature - recreate __init__.py files at install time
        if options.ignore_namespace:
            nsp = None
        else:
            nsp = parse_ns(stats['nsp.txt'], options.namespaces)
        # note that pycompile/pyclean is already added to maintainer scripts
        # and it should remain there even if __init__.py was the only .py file
        if nsp:
            try:
                nsp = remove_ns(Interpreter('python'), package, nsp,
                                stats['public_vers'])
            except (IOError, OSError) as e:
                log.error('cannot remove __init__.py from package: %s', e)
                exit(6)
        if nsp:
            dstdir = join('debian', package, 'usr/share/python/ns/')
            if not exists(dstdir):
                os.makedirs(dstdir)
            with open(join(dstdir, package), 'a', encoding='utf-8') as fp:
                fp.writelines("%s\n" % i for i in nsp)

        pyshared = join('debian', package, 'usr/share/pyshared/')
        if isdir(pyshared) and not os.listdir(pyshared):
            # remove empty pyshared directory
            os.rmdir(pyshared)

    dh.save()

if __name__ == '__main__':
    main()