nwdiag-1.0.4/0000755000076600000240000000000012451257704013575 5ustar tkomiyastaff00000000000000nwdiag-1.0.4/bootstrap.py0000644000076600000240000001306112217202643016155 0ustar tkomiyastaff00000000000000############################################################################## # # Copyright (c) 2006 Zope Foundation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. # ############################################################################## """Bootstrap a buildout-based project Simply run this script in a directory containing a buildout.cfg. The script accepts buildout command-line options, so you can use the -c option to specify an alternate configuration file. """ import os import shutil import sys import tempfile from optparse import OptionParser tmpeggs = tempfile.mkdtemp() usage = '''\ [DESIRED PYTHON FOR BUILDOUT] bootstrap.py [options] Bootstraps a buildout-based project. Simply run this script in a directory containing a buildout.cfg, using the Python that you want bin/buildout to use. Note that by using --find-links to point to local resources, you can keep this script from going over the network. ''' parser = OptionParser(usage=usage) parser.add_option("-v", "--version", help="use a specific zc.buildout version") parser.add_option("-t", "--accept-buildout-test-releases", dest='accept_buildout_test_releases', action="store_true", default=False, help=("Normally, if you do not specify a --version, the " "bootstrap script and buildout gets the newest " "*final* versions of zc.buildout and its recipes and " "extensions for you. If you use this flag, " "bootstrap and buildout will get the newest releases " "even if they are alphas or betas.")) parser.add_option("-c", "--config-file", help=("Specify the path to the buildout configuration " "file to be used.")) parser.add_option("-f", "--find-links", help=("Specify a URL to search for buildout releases")) options, args = parser.parse_args() ###################################################################### # load/install setuptools to_reload = False try: import pkg_resources import setuptools except ImportError: ez = {} try: from urllib.request import urlopen except ImportError: from urllib2 import urlopen # XXX use a more permanent ez_setup.py URL when available. exec(urlopen('http://bitbucket.org/pypa/setuptools/raw/0.7.2/ez_setup.py' ).read(), ez) setup_args = dict(to_dir=tmpeggs, download_delay=0) ez['use_setuptools'](**setup_args) if to_reload: reload(pkg_resources) import pkg_resources # This does not (always?) update the default working set. We will # do it. for path in sys.path: if path not in pkg_resources.working_set.entries: pkg_resources.working_set.add_entry(path) ###################################################################### # Install buildout ws = pkg_resources.working_set cmd = [sys.executable, '-c', 'from setuptools.command.easy_install import main; main()', '-mZqNxd', tmpeggs] find_links = os.environ.get( 'bootstrap-testing-find-links', options.find_links or ('http://downloads.buildout.org/' if options.accept_buildout_test_releases else None) ) if find_links: cmd.extend(['-f', find_links]) setuptools_path = ws.find( pkg_resources.Requirement.parse('setuptools')).location requirement = 'zc.buildout' version = options.version if version is None and not options.accept_buildout_test_releases: # Figure out the most recent final version of zc.buildout. import setuptools.package_index _final_parts = '*final-', '*final' def _final_version(parsed_version): for part in parsed_version: if (part[:1] == '*') and (part not in _final_parts): return False return True index = setuptools.package_index.PackageIndex( search_path=[setuptools_path]) if find_links: index.add_find_links((find_links,)) req = pkg_resources.Requirement.parse(requirement) if index.obtain(req) is not None: best = [] bestv = None for dist in index[req.project_name]: distv = dist.parsed_version if _final_version(distv): if bestv is None or distv > bestv: best = [dist] bestv = distv elif distv == bestv: best.append(dist) if best: best.sort() version = best[-1].version if version: requirement = '=='.join((requirement, version)) cmd.append(requirement) import subprocess if subprocess.call(cmd, env=dict(os.environ, PYTHONPATH=setuptools_path)) != 0: raise Exception( "Failed to execute command:\n%s", repr(cmd)[1:-1]) ###################################################################### # Import and run buildout ws.add_entry(tmpeggs) ws.require(requirement) import zc.buildout.buildout if not [a for a in args if '=' not in a]: args.append('bootstrap') # if -c was provided, we push it back into args for buildout' main function if options.config_file is not None: args[0:0] = ['-c', options.config_file] zc.buildout.buildout.main(args) shutil.rmtree(tmpeggs) nwdiag-1.0.4/buildout.cfg0000644000076600000240000000204612355217265016110 0ustar tkomiyastaff00000000000000[buildout] parts = nwdiag test tox static_analysis develop = . [nwdiag] recipe = zc.recipe.egg eggs = nwdiag blockdiag interpreter = py [test] recipe = pbp.recipe.noserunner eggs = nwdiag[rst] nwdiag[testing] coverage unittest-xml-reporting [tox] recipe = zc.recipe.egg eggs = tox detox [static_analysis] recipe = zc.recipe.egg eggs = coverage flake8 pylint [test-extra] recipe = iw.recipe.cmd:py on_install = true cmds = >>> url = "http://sourceforge.jp/frs/redir.php?m=jaist&f=%2Fvlgothic%2F46966%2FVLGothic-20100416.zip" >>> buildout_dir = buildout.get('directory', '.') >>> path = os.path.join(buildout_dir, 'src/nwdiag/tests/truetype') >>> if not os.path.exists(path): ... os.makedirs(path) ... import cStringIO, urllib2, zipfile ... archive = urllib2.urlopen(url).read() ... zip = zipfile.ZipFile(cStringIO.StringIO(archive)) ... ttf = zip.read('VLGothic/VL-PGothic-Regular.ttf') ... open(os.path.join(path, 'VL-PGothic-Regular.ttf'), 'wb').write(ttf) nwdiag-1.0.4/examples/0000755000076600000240000000000012451257704015413 5ustar tkomiyastaff00000000000000nwdiag-1.0.4/examples/nwdiag/0000755000076600000240000000000012451257704016664 5ustar tkomiyastaff00000000000000nwdiag-1.0.4/examples/nwdiag/node_groups1.diag0000644000076600000240000000067011655736343022130 0ustar tkomiyastaff00000000000000diagram { network Sample_front { address = "192.168.10.0/24"; // define group group web { web01 [address = ".1"]; web02 [address = ".2"]; } } network Sample_back { address = "192.168.20.0/24"; web01 [address = ".1"]; web02 [address = ".2"]; db01 [address = ".101"]; db02 [address = ".102"]; // define network using defined nodes group db { db01; db02; } } } nwdiag-1.0.4/examples/nwdiag/node_groups1.png0000644000076600000240000005037112021306063021767 0ustar tkomiyastaff00000000000000PNG  IHDRPIDATx=,Yz='"2i"5 @HZ%ͺZkPɐ#9vI`e C`AEc4Dр;ʌ8gYu+2"kdWU~F<9a1FIpC&L>0!|`B !B&L>0!|`B !B&L>0!|`B !B&L>0!|`B !B&٘Y86pj !B&L>0!|`B !B&L>0!|`B !B&L>0!|`B !B&L>0!|`B !B&LHv 78(4N{E@B0N~>0!|`B8>11E2*F0a !B0Ɔ1)PƄLzG1tQ=ƌ y ` bXCØs`JOA >L-:rgKL71'fXikc84^B73x`&A%ADOazW}{m?tٮ}&io7;$UUՆ,B7yR<,K\.ݶm9YTSUv>VU~m$=^9}B>S0м-l?~S'$}:>\х\\W+Afqm`/5a9W\Nm'8 f\J~ !_UU֜)!ۀiTι཯ek~sFTIO+cxCE)խܧpg<>}coNeee<ϗyynYVs}N$~jj~ɳ45ɶii?f_)IׯOgg{ߝf7j6e,Dm>o7i/rժy\{j]UU^"Bw5?iTtq΅h?L.ChUs-પy0)_}B&m9Y/t5J>|LAD{UUef(nͲlBXy@TNHjC? yryYUwVpd&{؇&st}n u͕tf!M6l6Z.j5+2ߣm;-LQ}KH5i8-Q~OۿO}˲t?e륕(`lW ݪ}5zT ,qO1c'ۮzQa\(BD_EqmenonN{0_~ʑb!ۚ}c. u, Tual6:;;{Zfʢ(nV,}|}_o޼ycousl&^_}vv~6]EqB~:ϋ1m"sH~d?U{zfl*_UU1FޗvQeQUUwZ|qmt1Tc${_eYf׋ׯ^zX\6eӶD \_u?i$o~)%3sl6X.+Pny_mT?;6`_+:FfH*uemw .g^a[\h*{?jڸ~Q2Y4཯<_vUy/UZ^ݾoۀb|=ߦe*lv3ͮfl6KE?jp5fo6]^o0Ko?|^esz/*ocouT׺>,,[y6e[/)s{Ǟ͕tw\.7*ݏ~TeYU:ҩ~~;~Lk^Hjʬ,ygLUO__sݞak;=czPZWL.NOH14m*wH=ۀb|=Gue`OD JVs8XkNgHY .nݥ2{NET" I;~O5|~s:6`_wy=SC?Avv^O-aT#~m 8e WqηlsvtxN_W=@?`LN`{+t/t߅Xtrݽ#C8#C[ߺmh菽 KJT)Tq'ח!|l<}5;VUeR|ۆe?ȑ h[B}X_?ʴ6МCG!O>=ͪ}'ߙbtRt)_QpөI{I1.L$WeQj֨4*ɂ S,FBCCM)!OSvRzs)b,ƐIoS 5_^~ot0I916:b_e.DY\)̕U֝=0"]' bPLqU(bXyPشLD\^|co{Ͼ?~0]_śoieQf sW2V,5-%ꐯH=<HSxWy r\v\Z\1'ԣ߹V_tgy(h悜+b)W\]YTt$GYUT{L s]|MCPuy*^:BrKRILO~0-O߽sgۺo.F*/nϯ]eY-Ȃ??v&i1#!vB{~XX^L\\2W\e M~'o?rq?^|I.ʹ KblqR'_[(U|iѕ5KPp؆GQN^ ⪈BիLo?ohy:>)VB뀟>8o4R=`Z:.>ѿ{1֮zco寮bbل{.1J٭}^t`OTshbB+,*ε|i}&|n~Źʫ2SB&WXy5}͗Z?߸N?׽|{N*>||Yb3Wyzed5>!Y2*T-sU7ʫs>,T_t[]=͗l;uo|{:C~KUJ\MjsceY=ǖOA#5}u/1z)UVﰗ\&uTm X^LW]u/$uaYNz tx*~o['*J1~7x>c_$pBŰV>[Bp{Һ7O;!~k?NoC{kړ׭=K{0a_fR4;]u͍ڶgx- 8U||m7V~Z5'|m{1o;ol+moc}M: +rip|<]F;N=n%mIRvSwX޺oE< ~mնx?v`j87}&^gܹ G{U{D`ml pbl0~ `omƇ > |^ahO x&IѿCSoW?v}-C>,j{h ?sIN'kF/A>*8OmLʶQ"ew=/ pXo~"&Bb[ZV2ɚwѮضZ[λqid%1wY3]˚Eӏq㢭7/ cGܙh{wCؘ}Uz|m$g3t|<ٮ}[VX:m3PٰFW??c~iXBf%_Jck# Ƌ'yp\ZGhB8% Fkŀr'Ao(\i$F;eЌhhrb}4hhdqPmN?coӡ2էۿVLA˚FWS@4H7tW%ҏ~K%@~i `s0Qfe%9uք^Rj@_U/L.8)l!33>>Xնcn*7[lJ5cWW]]q)2UN18eMN6G">W";1\f\PrX04!in5?|ȑ\eʽWQ:*' Vb݋+]>ʚn{ .ns+||Eɚ!=ȱNF=1 53K.6ico(LӝGMyViU y}Y`[L |1JQxwShrULqe Niթg3>@AuCXaBgy/gw>Rox{ShsUE&[yeSLy0h :#i:%n5Db*C]G.*Q7fcZæb\6ϔ^E4 NUɶ"dwZQX}9 eA, NU DԦӮɐDL.n3Y)_yKETs Eǁիb&َ^Eg^z-+bw@J7 (\phW=BjN>}uiR~MqhWU w' %3yö NeeuTV|0l1lʩl*UP]7Cx&|< vQuZrҩK17cP/isyLO8>P2!׆.u֛o.ROM- 6tZ&Ć}խz)n$|*\#)㹵K֫ldঘLf{t}?6Z' s`c n3M=5t!nLx~Q{ } m8 @}:5x ؆s_ݡ[I%ccѵ lqRzG`G9 $>NCUa$ K/mh'~~#t`(m[dWCӶ_8M|~}?嘆_+6B&L>0!|`Bgr !BfLҲco8:4m}ZxeQN $3I2*k7sз5M'!}\hIq3ؐ92rZt_,ʙl gv/qRٗ2/gL*Sy] g?~Uyf>h򮔷~!wQgu/f˫j3uƗzkuぎ?ٝKљwgEJoqc|YUqE͎ܛ؜r294SvlY\~rsR />(A fNKp8hU*Ck̩`qKȫcoGI~U?<4W7eCmHTc 4HKMg^y3D_Ch0b|XJKA4*:|UhZ(bbuM8&ϳJy&>uE/ ͧE,TRE*IwQ,z/!6ڢLtFgTESwp{7mC6&ͦ`fůRgyR_jBuKmxT$eu>}^ `{jƉw?=&<ں UnW_Y7ذ}EdJU<KzA/ ΔeNEi>7rU8QWr_E)y e>¾uvsMx--66T_d?pF B^_], _frΔy< *fŬYQjw@vt6f0 ƊI)@:dAʃB]WVjױ-y> kWIO:[vg&|3)Q,0䛜YP^by Y3ٶ;oO@At5GLR>bJepMHw?eC|=Wrsê'mߥ(|bdG5U|/E[JjMI!%)ZUtLVZEG6Z1(Ue(3TUʲP|TK=cyf`<hj?3Ҋ:.(/)D)DXCH)O6Vq~>J]޾f|FUzj6ZtF46YS$Vd>֧&;)pL՝ UGj9Z dwWOxu-Iٖ۫tS=~,پlǕ}Gr|eQw^=(ٜ}w%#It/Om:Xn~D{v7 ~zim9 R'w%빥NiC~3_LB֐}s5tO*{AFpOz?Mo ۛ?sF4G=ϯD#Yiۋ;|[(`guAm?{~fKЗza僚7H#_fNו>m0(|^`Bs3FVdwz)3XϔN'f|ep} }mHj>3Ekz"1:SbU:\󕹬˫\^F_kD2Ǿ$?Po38 E:~†qѿƙu_TTrY%+954vI>pHۓ s,dy)l%7_ɯzc)VCr#ٽ?nS;aq0Oŗz}KEz0[+Jsy)KYVɚ*῾XS0!w>uomKb%?_*;Qe.Iyw՝hy8Guю8ܸboVFٍ|iXKs ڶjBcfeW|qlqՕ/$+UKiω]#D@2z|<~N./ar\^V^h{/R/neW|p|ܯ=jY2\%+b)?RI+<+,3+fm'rP3$O cq_: .jR~l>[+>ڲKZ.imA N!bJr,_]ŪlR\2W\e _ c?z?8 O_o޳jw2Z7'}|mw>]J*3MoXx1ƍO#5l/-feGIf~ʪW U˙*S#d;۫cǿ}㏫&m:5Un;TvŅ\qmh x2>5l+_˕rRN\]vcRղP\1T^1{~'v|^N^-'n)岥hm)#sԶd̯!/e KeUc-|)jQlGߤwf]RWezbV|YWz,M}Rb[#<~DaҎURG *):9zm쌾!ϊumt{|mT[rzUvL#n>iiC~[v+wMKut*t֯Lc|u׳8uȏupO"q,Mk?dbT%sMmۖeo=co&lk[88Bm,֫߹?r/߶c✥/vT bLjm.[{0]__oݕrz0xRKdNqwn*nU;~Zsձ76?:D_#}Bo'kp0_S`8ذSwqvމ?Ɏ=ZuӶjmU|<ζ֜c `-}u78u:rP=sb|>!c+*doڍ k;T!c2B>^1XO}_Qa\ncw@ƿ NK7? $~?(:8վA=sb|0TßD#߯;v}wsb|/d2mllg%)q}{UUm\eY{jXEQ۝:WK_r Bۀb|8~pVۛ?~_N۾]oP s.tC~7{CYNZ<ݐz b:o&>;j{0]/j'a?+?-l?~}9B˥~%?*kNې~N'L S>8ޗe u=mǴl1۝ZtZt18??;YY-<_y~2˲U+R5_~539WGITU~SLwBp;;ʲtY<7CR[N7}n '_)Iu_){f6]f32de2c '9V?P~? {~9˻=I-;ɶ7UU%=KK+w}k>8;;+Jjh ќcL&?_5B*wꫯ8??2IrUY/ 7~|x7,zWEQEqe2I/0 ߿ \v>_-˲,B-7I-ɮcn!=Tl6XEGrMgrgrVYYyDլ{ۇ*G z-!mi8-Q~1ѽwm,KNi(ҿaqLM32RJ_1[ߖr C>|c?Ƕ*=rUEH6noޟɟ|oo`1Chs_}Coc]=VJᐿwW_}ݻo}ןWr>"ҖqT[__couW?7=6䬊Y,|>*&AB'=﫞s}n֖?e;?m_e߃n9,r;fj5kUEqZf棢Cz#x͏ .J|tUT{y~~~q~~lvUM MN}t\lkybw=ƶDI]yPwTeUUyѼl6]eYTU՝&>/x6_{0]::)UelvX,>իeS_6m;A>Wy@+vl&6AtΕb\nVݢ|vmt1-v)ngus$M:˲61o9tOzImö ιT~jq(e2`H-:*ezl\r>_hַco~NeNe|-?lhtCKU`b;wMisآivp4ۖ)BٹdA~^Nn|Y=Ch >&a'׷C[ߺzmh菽 8;ߥJA2p7;=0 vޥf}*LېyG.76mKȷu{BbGsTD%OȾ=0uN[;SNN1:{:w:w7p/)ۀ-JB]%Yd ŨRTq O 6Nѣ1b+Lb T&;:A_|*Io7w]ts0!G_nμG Q`+3W|)sd䪺ugGyF~n4s|,|O?2 f\/e٭l)T|coo>`Gޣ+Uj\(,](,*W|I!wwUx?}'ݾ?ؽ/~?w;L1׶?~;zMQr9_EWR6?+I%::z}G{O|MCPuy*^:BrKRILO?sޡtuǿÌvm]7e\^.cvЬdABݟC;׏v}2@9z9R˙rZWiX^Z披L< ~纟};c=^?/GoG\sAJFOXQҢ+])kG襐)X.T^txÙBa)TScO? myz| ӱ'@?w 7:z?_Z*/,Ms٭JǨL*b+P ˅ʫs-o߾7_~۷iyqjm:#Oto};c0>a \VXTXdfW *o15H+DGX*c^U-X,byykݾL7__\mDVӉW?s?;+P^? ؿޡtuqծey%?[){ucM+1;TjaղPVҺm}Y&tt#C=S"m]*WՇ3-/ןOPV^rm͗Z?߸}:||̑>,U}+Jnq2fgVљ)+o\Q{cEb*;.ɍc\! yn^OZO˿xß_d7tkz5*y߼ہi:_}rO\⋿__}[+ Ɯ[k[}dNh~7k >D4}u/1z)UVO]fnsd =N39 lڃGM_+מn tܱ76Gm&Eu^:iQښGm7V~Z5'|m|~mێJ[0X:F\|=>tkk^]fx[$őn1ue+cHf[@ =Uݳ=s[O!xF3vJ?͇Y' =N9Xw /xmeu~/6cWj@ |^ahO ҝv; `@CpFf.+IJ:$[7G!f>ɮ=kW?v}-hNV﷟|ED=/搋םzO^v_b}Thjvw`RUg;z{g?ԗZt'cƎ=0nl!ߎFv|e+dػh͆8iv[wqy?p"Uܼ?&5#K_skY~1n\fC>ݙh{wCؘ}Uz|m$g3 zVU:V`[ T6FW??c~iXBf%_Jck#8QNKk_wvwMނرu~hP$s^ +hWLqMM.B\ ;ӦӄϿ{thLkSвjT`6> <|Q3*I~_Z4(X.8TS9(3Ӳk~;kB~/)to όǗW&M sbƙDmɩ?T&o|k ǮpSze)bpʚvim<Ê|^ARYce.*wQuiB~2ݮk~417#qʔ{t*J'UN>ź|IyeMn]>hfϢdMWŐMX'LBP|^α7t >u'@hxwkUZdB^g,9V/68`REZ\2S\yY䂓oZu팏A!VqBgy/gw>Rox{ShsUE&[yeSLy0h :K)v!J-P:wQʽ)85 MU6CPy**YppNp}B;GuwE(\,뾜ͲyT*v"kji?BNdH?&Ȕעr*CsI@R:Be`h\Utײ)*֡y*^y ~v|c,ڧWO\`nJkV!!Hv|Upg| $ЈԙTHUT6tC>CqcS=ӗ3'tco Ǡ+_{> %~mRg!edۄR;P[CԆ^ЃзU>ō?}Iϭ]^ek,X&X)6JnWn?4ckCC6 >'&x'`=oě>5t1lv|ND?w֨=E`}=xLa[Lk`#@`Ķt! Ou|*:xV F{lt.<5NT7z>5[#E`n}8 _E0!|`B !B&l5=  !BgL8%);0dщ>o#2' >/Ife#({YۇYTݦ>qГfD!ses61Y30}to\Te澼뙽)m2m )TGzWx:{5Aw&&kL )m>o }y5_^WW33_#NL;¢p1,}m*#h=7)s9.(Ae L!bo??~~.r_? |}wfJ}cX_>2!R9)wNryW}x%l$-;|^ 2 AN+mu5ؖ}~FE3zS=:) 3_L}< #+&g&|Xi~Lm`[A NZ7Ys ,yIT*XM[dx{YRzD]UL%UO*K,,4C Ϧ)fT|Ll"+U45'vw u—hQjV1Փ6(U14&xbi}TƝ礐fVQh#J|?%L.+e,',Rp>䤪}̴RK+(c^g֓zWY@X*Sٜ`_ȱ[ޚ&ϋwAy6&ְ)>[av״rj9P>q~>J]޾f|FǜzϚ$P >5޹xgL3ĺhs2Vh)I\ b$~of[nI3^LidfWjmdt=8,\+}g9:ﮤ3|IڦӽD֐}s5tOԎܿξDo@mwCyaWli28]&Y][&_4kbwR\5ց8XvG |i֚u?}So\~\|ɰFvcgkvf-7 {<&xl`gPӾDE_l!>k|)if)j}0ٖFuJ) /a> Bͧ}h[>>tvt.ʹ +sY%W啹&Ջenx~߻HOP'|_~=JWr.kh<<|؞ fY%K(g+J~ՓLru̾qZń{R~ѼV\^RU5D?@f뺷W|/({uc2$TX;Pq|fq7_W_]+{uF~4_9߄| m߀S3_EWŭōWWVTX$_T +/='mUdW#J~RFO߫x}Օō|q+Wf, g5Hpd|_[v~E $XBC36h{Jg\_{S=7'Ҳ/5{Ί/RW2W\G.Ӗ*sTk貕\qme,>ZMRtRU7*S d L\;zBm^ϗ'|yk'_[vv)W\eu?MW>$)hJY4?UsoJ٥빪eԵ+4kY3G'[ԟ});`~v-˗+%=|h&:_Zn+2˂*ٕU3UmIG"ԶĶMDz_|g>X+Ͳ[9_ma{\_˖Rtd旪*!;ՠ6rj9y=ggu{Nq--eDaݖd̯!/e KeUc-|)jQlLR|dg$[Yd{L8i*)ĤWJmtW b6vv}`6q}T[ izYLWm9u}*WL`'ӮӆX8WJ[o{*goqPoa~8!8 WR h1mٲ&Ӵ-o6JrRn8^p2SeӎzAnJ9݃Y e81*nU;~Z?:_#f[Mz &졝r~[=[7>ٽ?co!B`2飂L>0!F{ >0!|`BЃ zaT !B&|`sG>0!|`B =tT !B&L>0!|`B !B&L>0!|`B !B&L>0!|`B !B&L>0!|`B !B&L>0!|`B !B&L>0!|`BnRKpIENDB`nwdiag-1.0.4/examples/nwdiag/node_groups1.svg0000644000076600000240000001244312021306063022000 0ustar tkomiyastaff00000000000000 blockdiag diagram { network Sample_front { address = "192.168.10.0/24"; // define group group web { web01 [address = ".1"]; web02 [address = ".2"]; } } network Sample_back { address = "192.168.20.0/24"; web01 [address = ".1"]; web02 [address = ".2"]; db01 [address = ".101"]; db02 [address = ".102"]; // define network using defined nodes group db { db01; db02; } } } Sample_front 192.168.10.0/24 Sample_back 192.168.20.0/24 .1 .1 web01 .2 .2 web02 .101 db01 .102 db02 nwdiag-1.0.4/examples/nwdiag/node_groups2.diag0000644000076600000240000000034711655736343022132 0ustar tkomiyastaff00000000000000diagram { // define group at outside network definitions group { color = "#FF7777"; web01; web02; db01; } network dmz { web01; web02; } network internal { web01; web02; db01; } } nwdiag-1.0.4/examples/nwdiag/node_groups2.png0000644000076600000240000003353612021306063021774 0ustar tkomiyastaff00000000000000PNG  IHDR`y7%IDATxMo+}_Uu7I\{k{`1u,o & ;+1v&ęsϹH"jE[34(Q]?ڄ0;\`# 00`# 00`# 00`# 00`# 00`# 00`# 00`# 00`N"`# 00`# 00`# 00`# 00`# 00`# 00`# 00`# 00`# 00wBcpTi\cػ6!tT0OR0 1 oEl`8>`# 9`3CsC9` ،Б88`# 9`3GYSG1 Fl48`# 9`g969`Fp`c燓}ah 'b`g%6!9ms;0qL'1f='\a>vSm,~"ha`PݚxV^x5{pv>tU[iu )!]CL _{[&UUcRߢ1!Ԇm! SA I芛 !X; !x]EL"j}YK–[km}m"|aJ`?C5Mu[8m;<Trykw5ι:c~U0LD:Ԅ7Mcs?O^{u.W_ ~Ieueee<,˪.5ZjCc<6!`]Md1|?8Ij_7X,֋vX-uQ,˪& WÜ0s) Лpoq |WÏ>~ϟ?uwwn,*qqJE<S+{s>~\׵ͲKRUUEճ^ S;?^z3I6Yq^1ƫ1 c#k+T]V,u]<1e6Ep>|æi2cLpUEQdYVz+!paJ'{odaLӧO߷<7,˛o!ȣP3/IWo]뫲,UU- a*'կԁǯx4LCWZ bC;f2NO'Iג+! \/~/\Hc s06ĤÃ`Ml'Yc:>^Vj/?|;ϟ?yww,e,zq?u߁НXE^VWr-b&Y'Aź_B{9.HrَkX^]]}jU(UU-b9?_/JV6ιts}}ǫO6.jmkBrä.Dpmwʹ:i<`sbl6亐kBĤo8_Òι&˲rXܭV߽{qZt2V##tVZqI kmX,֛滲, g?/&jfX-WWW*]e֟c ]`19y^⢯Mro3Gk}}=? eY-ȮOǾvN 'rYuO嶱%*`{~XӮ ueee<Gi=.oev4yout⼯_/?/z!*$'y\x`I{Pc#]<0;;.^NOBG'㍵ya];@ i[ڇѽ9,˻l۵ ~nL{ccMY[5nx "%,/׳Ē.hmJd!Ph`$~_aRwg5 q:Sq8 `eeٝFEYy&Ny:Kr$;ʪ/ qq};PӬTUfT_,UUKuޅ8):Ç:>|Ѿ'!Hk}*ZEq=ؘ6y_˹Z!)#yڡGIj],iJwwkSY^ 5~|@C_ʲREq;V1|Urn-6vc$_}IzVY~u{nofV&SӤÐcstp:/a18\|F$*e٭FYvYsw@yB>lFF/A4zz=~^Ð5ӧ 8cILeYXem E'yw6qff9_ {U UReyZBeRUgC}'޲NN(.} 59_o{fd۰ck5|}o{*k`6Sٌ?6)'n9_xn fVȇk^vWfۃ Ñ~GSv.UA2aq47óP*6i%؜/d^pcї"75Ao!,tǔy(_!p:[b#7NlB&8iCG1Pܡ}{pvg616rYzp>uފɞ8Utr$O9~ t5/a',0DTrg7~beS؁,`T0/ ξ_ aX' *gW0ث=p 0Uݮ7־ʻ_7qU&ICꗿn gLx;.tUА#&{YI֘v$ՌQu+H]Da4rl$m7'v ?5si_`8lg3}nƴ ((5ft9ҾgN  Ǖ ?AǺ6 cVX(=uh_2ޤZZ g۪ZSg醇gut׾_^}Ĕ0&* :Yx_Uvnh, a;L41 ySD!:y,Ug 3F1*U޽۳ 0L ?ҾaV  G"u-IʬZ-Cв 8^CcI/`h0Yɉ8_yxڪiT:{5]o+Y*@׾O/`,g2& D dúi^eD0_0\:džsJ! }1 qb: gp70O0\ tbxU/`xNGܝ}t%:![bX}C0]0\~ןs0t]$`# 00`# 00`# @ĥqJ/` 'wVSh͵}F.1mWhzp /lyǘmƘ{1Fg kFf׾p2Fҿ_~^_6wu[ Ԓ$6?c˿GY癤1VΘvdp3*/?WPF(K*%K%i}M 0]z73F1ʭUmuhANqcj15˜H^,v:PRanYIN[ycua1={KIS[$DW7it|_Q̵}C#YM&8$im)Ǝ1N̨\μLm?5{8S&2`f;+VĶE[i_#sDQݛXkێqF|d*,{gaF]OUoӶ? p`8x0U9U'ܣ{`gB3k_ّ{kmK}ٻ[:~{CC3pꬭՇv{ږD. DJ\ ua 0٣خ3 Ss>([79@~}AA~sqN9.vF`{!ȉÊݯO:9:c0*^`g6!$ 0 kL0 p) K$.81G{vS8nDxa;뿷M~qFdO'a8SaXsD)Ѿ.Dƒ{C;;4 ،~.W?wڏc5XXҧL?"y@p:Ò5֌p|\0*`36\00;u#03`yla<ַ;Tcؙdg&7Y}k‘~= ́{. OTF7T#JWm_t*θ$]h3~y#?r(xo)}OxRD/KN g>_=5\3aɃxb1wAl6C%]~?PW]xϥs=@ޯcJ4]76Cϸ)Ѿ~KגgVE}vJߗ/_M.Pڐ8SjQV޷[GogDCS31t6בֿ*7j+c+E Vք]-Jީiv3v?|[oGai]~qI1& ],UZ{0؅8̈́j?N,IV!8yBU3uqmMPb߷1оtИ]Ū;ieLjY+HOTj1!Ԇ%G5`$ ]q!뽷{罷!o_dYll*BUکiLi[; Ѿ4}N샪*SYlrn)i)+9'Y[vկh1xI]زxkm ]O1=ƐwMd?A&U0*}./T׺zzfʩMo $N</̶lr R]ɘk5M~ϟ?uwwn,*qqNk NmMOoI{ﭵ7Mcs[Iz/y},/㽷ML߿{Iɲº>=H6C,4d=y a1<BPe> aUUm? an//Ç6Mcs*b]&˲{_9 P%CE$yi7=%AzsKӧ[k}ry[M]׷K6c+`,[T5Cgp)mY˪u]LZS1:⑤Ǫaoq`3=Nm\33 ]i%*`I'ya/UU}l4'J?ɥ$cipꇨǾ}gACiJ Uo?߿o>ݻ,ĪLh/E$Qh ijݚPjl{1x5EVoop [5ݬ˹ZUrTme9nVLŸW,Ǫ(jZnmQ<7">y{ׇ| $U6bq{uuEE]źE4yRj׃$jJURU5*,vׄ<| H(w85! ʲFYV(6nswfLs(%BW 9WwoxuuiXE!zq'G¢5<.4Ms^,wfUu]҅e%\+Uյ m6AfTQ][y X#17E1.B*`mFEQiry;'춻wջι&˲rXܭV߽{qZtxؙz,6$^,f]Yq2?ơǥꝪK׵p˵^g*Lu*~Njػv_^EQihjVo\~PTsBiJXZHF6n\~U,| ]BsMefmt#x6-ˢxN X~lZeY(s9w%B(B1Au-5 `~0圔eAE\6*u}_ݻVSQ|Pȹu2 п&`qԨβ|yٛ_v!*Uܻ9kڭ_JewV]n1lq2>`4_fgO*kZmtuuwnt}>(U07>$'y\x`I aԝb KKV5*RUI VMVYnTZɐU4yoUd0k;`;1l+`Ym߳Xs˵V[V7Z,>)?uD^bUn^]6;8+ ZKjʲTiM7.߾9JC,'BXsb絊bbbVQemX&OݮnU|sBgE nП(/NoTץRʲZ5ڸ0nP AO4~s `RvKQ~'폲<.ZRm:\K"=~bz1~Xj䜗1pdomRi`z,'Sj-k>k7,=p8lfDH{ GeB^m!e v[||ۨ"}PQ6,? owLPD%{Գ~ˆY {y\A.>Q|d{umgv~c=}3dU=m1*lX~~!s>k7$]^ޙ~lpzY' R `ؗ6C5 ?HV~HUCfSZ~aS}23vT/&hfCXh0S WA'C(.=`tVHoL~v3mhM5/ۙy_ #y.|I 6F@چPΘ1F!m ~#gPx9_ĮyX{/4ry,1jUNknW͕:sZyӴ ! b{&T`lB Ǻ֢i{yg .Y//`*JQ4+SO@Ï lޗ\u]K\,^:$Ԟ ?۪jW]+^E8Wx{%L|᫛^.@{Sk}4#^sw{ޫWT}!ޅYl>k5E0?ΡF+*crVTrǍF|F7k`DݙVz_Et5Dt5׏̙" NcC_9>?_Jj߆CBCVa["|  =5\8KA`fb%+`zC` J&`KC8l/?{z^c6>3_NO}k```0F ``0F ``0Ƶ 1w\ pꙘ E 9vk5׏f$6 A#cL\dU:k7n=  sÜ/'g$~WPF(K*}W׺^T=({9HHϵI>R0RȬ UQN3F`0Bu]eIʌQnrcTZա.y)u:u(^Z(wiELb0e6u:j霪.|eޫ~,"٫~Ze֪V+kפ<^/ć `12!(m]tNWIʛFjb PlVEiez׽. aS0u\:wJյs̍ZU!lbp,wN,U,ӵsZ9E¦>'ԞZʬժiT{5گ~ŽoDw3Fs*\"zPr ;$Ĺ mij ^bMȹFƭ} SozB3AKWb𲶖sem>S"xg.突meնڅ2ߍ+c@K81ӆ,e|XirIw0Q/?y^(TkZYV**Y[˘fWMpH{!JY׭u!IrR]kmaZA6ʲJErIō b9W& `҄B /6X\,SQhN޷+JURMi6f-=޹F]]}rFYv'JY[ɘFm5Q6eٝFEQUv,UWBMU`@xTKŭZ}˔Z,UQT׋.|1 p8)*`# 00态9_ `# 9`9_ `# 9`9_L 0Fss4*`# 00`# 00`# 00`# 00`# 00`# 00`# 00`# 00`# 00`# 00`# 00`# 07.v:IENDB`nwdiag-1.0.4/examples/nwdiag/node_groups2.svg0000644000076600000240000000674612021306063022012 0ustar tkomiyastaff00000000000000 blockdiag diagram { // define group at outside network definitions group { color = "#FF7777"; web01; web02; db01; } network dmz { web01; web02; } network internal { web01; web02; db01; } } dmz internal web01 web02 db01 nwdiag-1.0.4/examples/nwdiag/simple.diag0000644000076600000240000000044611655736343021015 0ustar tkomiyastaff00000000000000diagram { network dmz { address = "210.x.x.x/24" web01 [address = "210.x.x.1"]; web02 [address = "210.x.x.2"]; } network internal { address = "172.x.x.x/24"; web01 [address = "172.x.x.1"]; web02 [address = "172.x.x.2"]; db01; db02; } } nwdiag-1.0.4/examples/nwdiag/simple.png0000644000076600000240000002704512021306063020655 0ustar tkomiyastaff00000000000000PNG  IHDR-IDATxn#ٹU,Rjgxp Ĉr\|+ߋ/!}9pΒI<;=VK"YU9P-umQZ| ş"5W$!?#@B|H  !>$D"@B|H  !>$D"@B|H  !>$D"@B|H  !>$D"@B|`o,k=86>$D"@B|H  !>$D"@B|H  !>$D"@B|H  !>$D"@B|H  !>$D"@BCۺ;EiAe 3"̓o`J|H у?qe0)sL 30e>$D_ 37j J"@BϜ:5 N3"@B'Ld)1A y) !Zt0s^/^v VE4}p%aSs>)`5@KRO[e1:!H».KQW[]?1y!ж֜(xyeY!lnX,0ruuus0?:蟱uڶ-=38g}Xy} C6!,vw]jc_׷p?/;`_Wc m_]Y۲,UU*+M\>|2lyNNvoɹ B~27/c]חu].,뺮k{X3\=gxinzζ!^E֜y4E=0_+w}\.?,M?p''jjN9k6oH۷o;==]m[pݖS6gYֆ~؇Hw$ĕݻw?o̲+bX,.UYm7EQd=p,#[txH͏?;ao6u]<99qr~=ҥwy7EQljOOOߟXbqC~71hE}},\na讪pWoy4UuYQۺ/Vv4pcoz K}6y7EQ4eY뺾XVNOO޼ysZu߶I>ϡoNwwnAMŸdfۺ/ޯ[+P+OwCt '+F^u}C?QMR|Nw}P߷SoO ՛E{uuWeY[ESUzTU^.rs@m:eYnu]_ugoZt;(8\?eFǡ|Knh>K<bƥ8{_Cti?~+-r]Uպ֣$C׏o_ Bz5?JG eYMUUW:ұVC|Wr1.uQH EQ4R͎%3?[& e9z#͎sÞa;B-cCt%Cp;\9 g:]#?ik8\./=ҥS4^$bd9V<?:UUm=ҥe/ fCWc!qx[?Oy}'x=l6y< N{|ٯ׮6p@q8W85ٰϘvyw>vm5_9Ӄ?s6BK^,v3wrC}oR/'+(˲ !}v93S} gf-٧"o3}⸌gF J(]x si> DwE6MEnJ3>^Nu-Dt]w]^&!f6`?S^c#H ;33|ƌ>O7Qtfn3?!6R3e 1 1σxSfLy=fF~f !>$DɎG؟./}?]<|H ѢëH !R\vc}̍{N sw< ikަ^_)yC̜s Wk>X_s#7àr9Ǻ3tM9yk}̙ϋ^[}6[mC uY,M)ɛu} l 93|BժѲogggue]emeYvOY}׮ :38:cLOea^/</`6gggu}џʶmw̲뺮RR_2Hb2]ͷۭ~juZ>4MS OͲ1qek\_E X4k޾}wg !(,g:n K}Ϝ 6>!?m _eYnbmۢ&0(׼̭R`ɋ kgξ :|uq\/im7=,@J|pM\>j:_׫fhj..Gy#yz}(?HN§v˓zl6k*K} 6Wkl6v-։<PJ} 6CBញixwz4%kFfX_'b š#m[ ׭<\0@|Lę>|Apcc`0k>{cuF]ks/9L&D}) 5fᅌku_}œA/6à%/E(x;T} .>Gpu_p&U./`Dv(@P}*Oc/` fI$kחY{vѢxLww8/ >Gm$w<<޸^[#$sTƁsKN^h"@B|H  !>$D"!,;Hx=>{c>Y V)63}`cteYօ,˺>u0ݿL `Ct!ܞ3S7my7y7YB;g^L} >p3c?߿}/o߾uuunUue۶7(u4O??ˡyeٶ,M]''' eU_`}̞ϋtYyEQ4eYnTU^,rV!PŶmۢ|k돇smMYbqUUڔe-g3S)HK-]emQMQr\.7"ʲl۪`Y&sqrrcxA\V?.rbWEQlh!LgU}MS*/;zX\,󓓓1|UU^˦iQC9(m߼yr<_,UUaQ^m!k}H W+jSj:?===mUU///O6",_=Mj\.?O~j:MJaC/5ms/؇7}WYju^ͦjC>*Me===={ͻj`N-kzR/q#Uu4Muz^m6zݎ'&?_z 4|Z}899y>S]U_6Hɲ,t]7^-ru:.OXEg։iIgXo k4\f^TUպ,[lZL} U>/n\^ce],W5`Djt/nG]k|u]3쇎}ryq1#p©CYm}@EݱSd b]L UUm=/ԍ/5fa 7ֻXO{SrWؚbR_3HܵRQjd|<̵LUQO鹄I9D)={>s Ϩy??ԞJK` |^EJּMx}f'f_zfYx)R}*Kfs&Fx= 4R >LXUUmgAf=vkc~/G+%1'n m;=v3=wenۼ,v數R/=5~52a6ReO!\q{2>;cu&b9Tnq㘛̂z\ZEf~2G}R_1-`(aN !>$Diy}^sI}X[fgL8^weA"L׃m;5fyf"'@B`^8^/:"8/0,kCw]?.ZmCt/gq~S{+? C~Ɛu](˲fss+,\[8/~alCt/]ϦfY7<O7wA)!_AOim{iw8A뺼mۼmۢPiF?Ac ] Y1؇ЇWD_o7뺾c]E̅eY,˺Z;پa0n3l r5ڡ6oAxm1Őݻo凓E\I-NyvG?QUsY۶y4NOOmۖ!\e}}Gu|xϛ),늢,bqUmMQe2Slq iumUUWz>n۶->^WnF{[UD?p||0!)y>3^"W9ݻ}w}{vv͇x^+pC9-~<8H8W,jaZ/ˏⲪ,7ð?{~?<<{/7,﫯CtBz7X-lv,iTf~aO k=ҥ,ap xp?*ZuM_~03냕 gWa,|6}R_3~@B|H?#`(aNԃ?3B>e>0  ! 3uݡb^* fyጪ~^W ю2?1B>乹 >$ >2aO1zxkujq=wyɞc}r@B|HGJm)=]xȔ&)=]T_>G9d!fce^3yz}G{7s1scL%\=9՗#àr9Ǻ3tM9yk} ]aUnݧh۶8P7eYX_C>Go|UUUUU]u].rBy7]̩|,웺/SٶmYu]5S _k^V_C>Gi`v5n3?|ZWՇiBIYݠ?&~L}ߔ! B}ovB(,m<뺮BR_3S`Ћ<UfX\.ڶ-kBYR}kHpj?Úů㙶oB_u]\.im,M=˪i.Iu] `ÇVU^VzlMTM](qQ5oSLD§v˓zl6kK}W3fmٷN1MRk^V_C >BpI4e<;=x5#3>\-Զm1^pyÌ3kffV_pۤg$Τ+ BؔS31:UjvͮNǵW˲2}2~`6޹y_?uskdx}nXWx9]zsn8t}ץE"@B|H  !>$D"@B|HZe c} 02 1ʲlOǵW>ua1g,B]e]ƺx]pcc`B<`"nayydYW!y=0533[|f/_o7/߾}w߿ǏjnʶmoIngi,]emmQMY۪6UUbnU!Em۶.ohq5Mאb EeY[ESŦbq\.?.f!,7X0=/y.WՏ|\~UQ(,kәeU_ӔJ}"pWqvtGZ/ry~rr>z4M9 `0E7oޝ_.⢪!l"ʫ;5us ywEQ4UUm꺾XV秧gmfYBN7rxrr'?g꼮닪6}+El״ͽvpF`b*rZrTMӔ}uB^\ OmUU8zzzz͛wCÝ"<[T_C>[_ǍU]e4E᫮zlv;n4^:}۾wbZV'''vvJkf__c>G)˲ux].,mu^vܣdCXFϬƣvÙCS_ӕB} N/~Eak۶h6M~=yzIyׇvt:Ym}"@oG]k|u]3쇎=R7GᒅS뇎,̶|wXBh-Ç8\7<c;TBט'}xctWؚbR_3`䮍"5s|ל6&M !Usl3snj9m|ǜ6̏bCx9>$DGC; 3"@B,=b@B|H у@2DOꋹ0  !>$D>'sf !>$D`6< >$D"@B|H  !>$D"@B|H  !>$D"@B|H  !>$D"@B|H  !>$D"@B|H  !>$D"@B|H  !>$D"@B|H  !>$D"@B|H  !>$Dͱd$TFGIENDB`nwdiag-1.0.4/examples/nwdiag/simple.svg0000644000076600000240000001127312021306063020664 0ustar tkomiyastaff00000000000000 blockdiag diagram { network dmz { address = "210.x.x.x/24" web01 [address = "210.x.x.1"]; web02 [address = "210.x.x.2"]; } network internal { address = "172.x.x.x/24"; web01 [address = "172.x.x.1"]; web02 [address = "172.x.x.2"]; db01; db02; } } dmz 210.x.x.x/24 internal 172.x.x.x/24 210.x.x.1 172.x.x.1 web01 210.x.x.2 172.x.x.2 web02 db01 db02 nwdiag-1.0.4/examples/packetdiag/0000755000076600000240000000000012451257704017507 5ustar tkomiyastaff00000000000000nwdiag-1.0.4/examples/packetdiag/tcp.diag0000644000076600000240000000072412021246347021120 0ustar tkomiyastaff00000000000000{ colwidth = 32 node_height = 72 0-15: Source Port 16-31: Destination Port 32-63: Sequence Number 64-95: Acknowledgment Number 96-99: Data Offset 100-105: Reserved 106: URG [rotate = 270] 107: ACK [rotate = 270] 108: PSH [rotate = 270] 109: RST [rotate = 270] 110: SYN [rotate = 270] 111: FIN [rotate = 270] 112-127: Window 128-143: Checksum 144-159: Urgent Pointer 160-191: (Options and Padding) 192-223: data [colheight = 3] } nwdiag-1.0.4/LICENSE0000644000076600000240000002613611635001003014570 0ustar tkomiyastaff00000000000000 Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. nwdiag-1.0.4/MANIFEST.in0000644000076600000240000000064312431566250015333 0ustar tkomiyastaff00000000000000include buildout.cfg include bootstrap.py include MANIFEST.in include README.rst include LICENSE include nwdiag.1 include rackdiag.1 include packetdiag.1 include tox.ini include src/nwdiag/tests/VLGothic/* include src/rackdiag/tests/VLGothic/* include src/packetdiag/tests/VLGothic/* recursive-include examples *.diag *.png *.svg recursive-include src *.py *.diag *.gif exclude .drone.io.sh exclude examples/update.sh nwdiag-1.0.4/nwdiag.10000644000076600000240000000371711655736343015146 0ustar tkomiyastaff00000000000000.\" Hey, EMACS: -*- nroff -*- .\" First parameter, NAME, should be all caps .\" Second parameter, SECTION, should be 1-8, maybe w/ subsection .\" other parameters are allowed: see man(7), man(1) .TH NWDIAG 1 "June 11, 2011" .\" Please adjust this date whenever revising the manpage. .\" .\" Some roff macros, for reference: .\" .nh disable hyphenation .\" .hy enable hyphenation .\" .ad l left justify .\" .ad b justify to both left and right margins .\" .nf disable filling .\" .fi enable filling .\" .br insert line break .\" .sp insert n+1 empty lines .\" for manpage-specific macros, see man(7) .SH NAME nwdiag \- generate network-diagram image file from spec-text file. .SH SYNOPSIS .B nwdiag .RI [ options ] " files" .br .SH DESCRIPTION This manual page documents briefly the .B nwdiag commands. .PP .\" TeX users may be more comfortable with the \fB\fP and .\" \fI\fP escape sequences to invode bold face and italics, .\" respectively. \fBnwdiag\fP is generate sequence-diagram image file from spec-text file. .SH OPTIONS These programs follow the usual GNU command line syntax, with long options starting with two dashes (`-'). A summary of options is included below. For a complete description, see the Info files. .TP .B \-h, \-\-help show this help message and exit. .TP .B \-\-version show program's version number and exit. .TP .B \-a, \-\-antialias Pass diagram image to anti-alias filter. .TP .B \-c FILE, \-\-config=FILE read configurations from FILE. .TP .B \-o FILE write diagram to FILE. .TP .B \-f FONT, \-\-font=FONT use FONT to draw diagram. .TP .B \-T TYPE Output diagram as TYPE format. .SH SEE ALSO The programs are documented fully by .br http://blockdiag.com/en/nwdiag/ .SH AUTHOR nwdiag was written by Takeshi Komiya .PP This manual page was written by Kouhei Maeda , for the Debian project (and may be used by others). nwdiag-1.0.4/packetdiag.10000644000076600000240000000376312021246773015761 0ustar tkomiyastaff00000000000000.\" Hey, EMACS: -*- nroff -*- .\" First parameter, NAME, should be all caps .\" Second parameter, SECTION, should be 1-8, maybe w/ subsection .\" other parameters are allowed: see man(7), man(1) .TH NWDIAG 1 "June 11, 2011" .\" Please adjust this date whenever revising the manpage. .\" .\" Some roff macros, for reference: .\" .nh disable hyphenation .\" .hy enable hyphenation .\" .ad l left justify .\" .ad b justify to both left and right margins .\" .nf disable filling .\" .fi enable filling .\" .br insert line break .\" .sp insert n+1 empty lines .\" for manpage-specific macros, see man(7) .SH NAME packetdiag \- generate packet-header-structure-diagram image file from spec-text file. .SH SYNOPSIS .B packetdiag .RI [ options ] " files" .br .SH DESCRIPTION This manual page documents briefly the .B packetdiag commands. .PP .\" TeX users may be more comfortable with the \fB\fP and .\" \fI\fP escape sequences to invode bold face and italics, .\" respectively. \fBpacketdiag\fP is generate sequence-diagram image file from spec-text file. .SH OPTIONS These programs follow the usual GNU command line syntax, with long options starting with two dashes (`-'). A summary of options is included below. For a complete description, see the Info files. .TP .B \-h, \-\-help show this help message and exit. .TP .B \-\-version show program's version number and exit. .TP .B \-a, \-\-antialias Pass diagram image to anti-alias filter. .TP .B \-c FILE, \-\-config=FILE read configurations from FILE. .TP .B \-o FILE write diagram to FILE. .TP .B \-f FONT, \-\-font=FONT use FONT to draw diagram. .TP .B \-T TYPE Output diagram as TYPE format. .SH SEE ALSO The programs are documented fully by .br http://blockdiag.com/en/nwdiag/ .SH AUTHOR packetdiag was written by Takeshi Komiya .PP This manual page was written by Kouhei Maeda , for the Debian project (and may be used by others). nwdiag-1.0.4/PKG-INFO0000644000076600000240000002125712451257704014701 0ustar tkomiyastaff00000000000000Metadata-Version: 1.1 Name: nwdiag Version: 1.0.4 Summary: nwdiag generates network-diagram image from text Home-page: http://blockdiag.com/ Author: Takeshi Komiya Author-email: i.tkomiya at gmail.com License: Apache License 2.0 Download-URL: http://pypi.python.org/pypi/nwdiag Description: `nwdiag` generate network-diagram image file from spec-text file. .. image:: https://drone.io/bitbucket.org/blockdiag/nwdiag/status.png :target: https://drone.io/bitbucket.org/blockdiag/nwdiag :alt: drone.io CI build status .. image:: https://pypip.in/v/nwdiag/badge.png :target: https://pypi.python.org/pypi/nwdiag/ :alt: Latest PyPI version .. image:: https://pypip.in/d/nwdiag/badge.png :target: https://pypi.python.org/pypi/nwdiag/ :alt: Number of PyPI downloads Features ======== * Generate network-diagram from dot like text (basic feature). * Multilingualization for node-label (utf-8 only). You can get some examples and generated images on `blockdiag.com `_ . Setup ===== Use easy_install or pip:: $ sudo easy_install nwdiag Or $ sudo pip nwdiag spec-text setting sample ======================== Few examples are available. You can get more examples at `blockdiag.com`_ . simple.diag ------------ simple.diag is simply define nodes and transitions by dot-like text format:: diagram { A -> B -> C; lane you { A; B; } lane me { C; } } Usage ===== Execute nwdiag command:: $ nwdiag simple.diag $ ls simple.png simple.png Requirements ============ * Python 2.6, 2.7, 3.2, 3.3, 3.4 * Pillow 2.2.1 or later * funcparserlib 0.3.6 or later * reportlab (optional) * wand and imagemagick (optional) * setuptools License ======= Apache License 2.0 History ======= 1.0.4 (2015-01-01) ------------------ * Support blockdiag 1.5.0 core interface * Fix bugs - Fix ascending syntax was disabled on refactoring parser 1.0.3 (2014-07-03) ------------------ * rackdiag: Fix rackheight syntax (cf. rack { 12U }) was disabled 1.0.2 (2014-07-02) ------------------ * Change interface of docutils node (for sphinxcontrib module) 1.0.1 (2014-06-26) ------------------ * Add options to blockdiag directive (docutils extension) - :width: - :height: - :scale: - :align: - :name: - :class: - :figwidth: - :figclass: 1.0.0 (2013-10-05) ------------------ * Support python 3.2 and 3.3 (thanks to @masayuko) * Drop supports for python 2.4 and 2.5 * Replace dependency: PIL -> Pillow 0.9.4 (2012-12-20) ------------------ * Fix bugs 0.9.3 (2012-12-17) ------------------ * [rackdiag] Allow multiple rackitems in same level * Fix bugs 0.9.2 (2012-11-17) ------------------ * [rackdiag] Add auto-numbering feature * Fix bugs 0.9.1 (2012-10-28) ------------------ * Fix bugs 0.9.0 (2012-10-22) ------------------ * Optimize algorithm for rendering shadow * Add options to docutils directive * [packetdiag] represent splitted packets with dashed-line * Fix bugs 0.8.2 (2012-09-29) ------------------ * Fix bugs 0.8.1 (2012-09-08) ------------------ * Add packetdiag_sphinxhelper 0.8.0 (2012-09-06) ------------------ * Add packetdiag which supports generating packet-header diaagram * [nwdiag] Add diagram attribute: external_connector * Update to new package structure (blockdiag >= 1.1.2) * Allow # to comment syntax * Fix bugs 0.7.0 (2011-11-19) ------------------ * Accept N/A rack-unit * Add fontfamily attribute for switching fontface * Fix bugs 0.6.1 (2011-11-06) ------------------ * [rackdiag] Support multiple racks rendering * [rackdiag] Add rack attribute: unit-height, weight, ampere, ascending * [rackdiag] Support putting multiple items to same rack-unit 0.6.0 (2011-11-06) ------------------ * Add rackdiag which supports genarating rack-structure diagram * Add docutils extension * Fix bugs 0.5.3 (2011-11-01) ------------------ * Add class feature (experimental) 0.5.2 (2011-11-01) ------------------ * Follow blockdiag-0.9.7 interface 0.5.1 (2011-10-19) ------------------ * Follow blockdiag-0.9.5 interface 0.5.0 (2011-10-07) ------------------ * Change shape of trunkline like a pipeline * Add network attribute: color * Add diagram attribute: default_network_color 0.4.2 (2011-09-30) ------------------ * Add diagram attributes: default_text_color * Fix bugs 0.4.1 (2011-09-26) ------------------ * Add diagram attributes: default_node_color, default_group_color and default_line_color * Fix bugs 0.4.0 (2011-08-09) ------------------ * Add syntax for peer network 0.3.3 (2011-08-07) ------------------ * Add syntax for peer network (experimental) * Fix bugs 0.3.2 (2011-08-03) ------------------ * Fix bugs 0.3.1 (2011-08-01) ------------------ * Fix bugs 0.3.0 (2011-07-18) ------------------ * Upgrade layout engine * Allow to note ip addresses directly * Allow node_id including hyphen chars * Fix bugs 0.2.7 (2011-07-05) ------------------ * Fix bugs 0.2.6 (2011-07-03) ------------------ * Allow "." to id token * Support input from stdin * Support multiple node address (using comma) * Do not sort networks (ordered as declarations) * Fix bugs 0.2.5 (2011-06-29) ------------------ * Adjust parameters for span and margin 0.2.4 (2011-05-17) ------------------ * Add --version option * Fix bugs 0.2.3 (2011-05-15) ------------------ * Fix bugs 0.2.2 (2011-05-15) ------------------ * Implement grouping nodes 0.2.1 (2011-05-14) ------------------ * Change license to Apache License 2.0 * Support blockdiag 0.8.1 core interface 0.2.0 (2011-05-02) ------------------ * Rename package to nwdiag 0.1.6 (2011-04-30) ------------------ * Fix bugs 0.1.5 (2011-04-26) ------------------ * Fix bugs 0.1.4 (2011-04-25) ------------------ * Implement jumped edge * Fix bugs 0.1.3 (2011-04-23) ------------------ * Fix sphinxcontrib_netdiag was not worked 0.1.2 (2011-04-23) ------------------ * Support multi-homed host * Drop network-bridge sytanx (cf. net_a -- net_b) 0.1.1 (2011-04-10) ------------------ * Fix bugs 0.1.0 (2011-04-09) ------------------ * First release Keywords: diagram,generator Platform: UNKNOWN Classifier: Development Status :: 3 - Alpha Classifier: Intended Audience :: System Administrators Classifier: License :: OSI Approved :: Apache Software License Classifier: Programming Language :: Python Classifier: Topic :: Software Development Classifier: Topic :: Software Development :: Documentation Classifier: Topic :: Text Processing :: Markup nwdiag-1.0.4/rackdiag.10000644000076600000240000000374011655736343015436 0ustar tkomiyastaff00000000000000.\" Hey, EMACS: -*- nroff -*- .\" First parameter, NAME, should be all caps .\" Second parameter, SECTION, should be 1-8, maybe w/ subsection .\" other parameters are allowed: see man(7), man(1) .TH NWDIAG 1 "June 11, 2011" .\" Please adjust this date whenever revising the manpage. .\" .\" Some roff macros, for reference: .\" .nh disable hyphenation .\" .hy enable hyphenation .\" .ad l left justify .\" .ad b justify to both left and right margins .\" .nf disable filling .\" .fi enable filling .\" .br insert line break .\" .sp insert n+1 empty lines .\" for manpage-specific macros, see man(7) .SH NAME rackdiag \- generate rack-structure-diagram image file from spec-text file. .SH SYNOPSIS .B rackdiag .RI [ options ] " files" .br .SH DESCRIPTION This manual page documents briefly the .B rackdiag commands. .PP .\" TeX users may be more comfortable with the \fB\fP and .\" \fI\fP escape sequences to invode bold face and italics, .\" respectively. \fBrackdiag\fP is generate sequence-diagram image file from spec-text file. .SH OPTIONS These programs follow the usual GNU command line syntax, with long options starting with two dashes (`-'). A summary of options is included below. For a complete description, see the Info files. .TP .B \-h, \-\-help show this help message and exit. .TP .B \-\-version show program's version number and exit. .TP .B \-a, \-\-antialias Pass diagram image to anti-alias filter. .TP .B \-c FILE, \-\-config=FILE read configurations from FILE. .TP .B \-o FILE write diagram to FILE. .TP .B \-f FONT, \-\-font=FONT use FONT to draw diagram. .TP .B \-T TYPE Output diagram as TYPE format. .SH SEE ALSO The programs are documented fully by .br http://blockdiag.com/en/nwdiag/ .SH AUTHOR rackdiag was written by Takeshi Komiya .PP This manual page was written by Kouhei Maeda , for the Debian project (and may be used by others). nwdiag-1.0.4/README.rst0000644000076600000240000001325412451242756015272 0ustar tkomiyastaff00000000000000`nwdiag` generate network-diagram image file from spec-text file. .. image:: https://drone.io/bitbucket.org/blockdiag/nwdiag/status.png :target: https://drone.io/bitbucket.org/blockdiag/nwdiag :alt: drone.io CI build status .. image:: https://pypip.in/v/nwdiag/badge.png :target: https://pypi.python.org/pypi/nwdiag/ :alt: Latest PyPI version .. image:: https://pypip.in/d/nwdiag/badge.png :target: https://pypi.python.org/pypi/nwdiag/ :alt: Number of PyPI downloads Features ======== * Generate network-diagram from dot like text (basic feature). * Multilingualization for node-label (utf-8 only). You can get some examples and generated images on `blockdiag.com `_ . Setup ===== Use easy_install or pip:: $ sudo easy_install nwdiag Or $ sudo pip nwdiag spec-text setting sample ======================== Few examples are available. You can get more examples at `blockdiag.com`_ . simple.diag ------------ simple.diag is simply define nodes and transitions by dot-like text format:: diagram { A -> B -> C; lane you { A; B; } lane me { C; } } Usage ===== Execute nwdiag command:: $ nwdiag simple.diag $ ls simple.png simple.png Requirements ============ * Python 2.6, 2.7, 3.2, 3.3, 3.4 * Pillow 2.2.1 or later * funcparserlib 0.3.6 or later * reportlab (optional) * wand and imagemagick (optional) * setuptools License ======= Apache License 2.0 History ======= 1.0.4 (2015-01-01) ------------------ * Support blockdiag 1.5.0 core interface * Fix bugs - Fix ascending syntax was disabled on refactoring parser 1.0.3 (2014-07-03) ------------------ * rackdiag: Fix rackheight syntax (cf. rack { 12U }) was disabled 1.0.2 (2014-07-02) ------------------ * Change interface of docutils node (for sphinxcontrib module) 1.0.1 (2014-06-26) ------------------ * Add options to blockdiag directive (docutils extension) - :width: - :height: - :scale: - :align: - :name: - :class: - :figwidth: - :figclass: 1.0.0 (2013-10-05) ------------------ * Support python 3.2 and 3.3 (thanks to @masayuko) * Drop supports for python 2.4 and 2.5 * Replace dependency: PIL -> Pillow 0.9.4 (2012-12-20) ------------------ * Fix bugs 0.9.3 (2012-12-17) ------------------ * [rackdiag] Allow multiple rackitems in same level * Fix bugs 0.9.2 (2012-11-17) ------------------ * [rackdiag] Add auto-numbering feature * Fix bugs 0.9.1 (2012-10-28) ------------------ * Fix bugs 0.9.0 (2012-10-22) ------------------ * Optimize algorithm for rendering shadow * Add options to docutils directive * [packetdiag] represent splitted packets with dashed-line * Fix bugs 0.8.2 (2012-09-29) ------------------ * Fix bugs 0.8.1 (2012-09-08) ------------------ * Add packetdiag_sphinxhelper 0.8.0 (2012-09-06) ------------------ * Add packetdiag which supports generating packet-header diaagram * [nwdiag] Add diagram attribute: external_connector * Update to new package structure (blockdiag >= 1.1.2) * Allow # to comment syntax * Fix bugs 0.7.0 (2011-11-19) ------------------ * Accept N/A rack-unit * Add fontfamily attribute for switching fontface * Fix bugs 0.6.1 (2011-11-06) ------------------ * [rackdiag] Support multiple racks rendering * [rackdiag] Add rack attribute: unit-height, weight, ampere, ascending * [rackdiag] Support putting multiple items to same rack-unit 0.6.0 (2011-11-06) ------------------ * Add rackdiag which supports genarating rack-structure diagram * Add docutils extension * Fix bugs 0.5.3 (2011-11-01) ------------------ * Add class feature (experimental) 0.5.2 (2011-11-01) ------------------ * Follow blockdiag-0.9.7 interface 0.5.1 (2011-10-19) ------------------ * Follow blockdiag-0.9.5 interface 0.5.0 (2011-10-07) ------------------ * Change shape of trunkline like a pipeline * Add network attribute: color * Add diagram attribute: default_network_color 0.4.2 (2011-09-30) ------------------ * Add diagram attributes: default_text_color * Fix bugs 0.4.1 (2011-09-26) ------------------ * Add diagram attributes: default_node_color, default_group_color and default_line_color * Fix bugs 0.4.0 (2011-08-09) ------------------ * Add syntax for peer network 0.3.3 (2011-08-07) ------------------ * Add syntax for peer network (experimental) * Fix bugs 0.3.2 (2011-08-03) ------------------ * Fix bugs 0.3.1 (2011-08-01) ------------------ * Fix bugs 0.3.0 (2011-07-18) ------------------ * Upgrade layout engine * Allow to note ip addresses directly * Allow node_id including hyphen chars * Fix bugs 0.2.7 (2011-07-05) ------------------ * Fix bugs 0.2.6 (2011-07-03) ------------------ * Allow "." to id token * Support input from stdin * Support multiple node address (using comma) * Do not sort networks (ordered as declarations) * Fix bugs 0.2.5 (2011-06-29) ------------------ * Adjust parameters for span and margin 0.2.4 (2011-05-17) ------------------ * Add --version option * Fix bugs 0.2.3 (2011-05-15) ------------------ * Fix bugs 0.2.2 (2011-05-15) ------------------ * Implement grouping nodes 0.2.1 (2011-05-14) ------------------ * Change license to Apache License 2.0 * Support blockdiag 0.8.1 core interface 0.2.0 (2011-05-02) ------------------ * Rename package to nwdiag 0.1.6 (2011-04-30) ------------------ * Fix bugs 0.1.5 (2011-04-26) ------------------ * Fix bugs 0.1.4 (2011-04-25) ------------------ * Implement jumped edge * Fix bugs 0.1.3 (2011-04-23) ------------------ * Fix sphinxcontrib_netdiag was not worked 0.1.2 (2011-04-23) ------------------ * Support multi-homed host * Drop network-bridge sytanx (cf. net_a -- net_b) 0.1.1 (2011-04-10) ------------------ * Fix bugs 0.1.0 (2011-04-09) ------------------ * First release nwdiag-1.0.4/setup.cfg0000644000076600000240000000041112451257704015412 0ustar tkomiyastaff00000000000000[egg_info] tag_build = tag_date = 0 tag_svn_revision = 0 [build] build-base = _build [sdist] formats = gztar [wheel] universal = 1 [aliases] release = check -r -s register sdist bdist_wheel upload [check] strict = 1 restructuredtext = 1 [flake8] ignore = _ nwdiag-1.0.4/setup.py0000644000076600000240000000370612451242630015305 0ustar tkomiyastaff00000000000000# -*- coding: utf-8 -*- import sys from setuptools import setup, find_packages sys.path.insert(0, 'src') import nwdiag classifiers = [ "Development Status :: 3 - Alpha", "Intended Audience :: System Administrators", "License :: OSI Approved :: Apache Software License", "Programming Language :: Python", "Topic :: Software Development", "Topic :: Software Development :: Documentation", "Topic :: Text Processing :: Markup", ] test_requires = ['nose', 'pep8>=1.3', 'reportlab', 'docutils'] # only for Python2.6 if sys.version_info > (2, 6) and sys.version_info < (2, 7): test_requires.append('unittest2') setup( name='nwdiag', version=nwdiag.__version__, description='nwdiag generates network-diagram image from text', long_description=open("README.rst").read(), classifiers=classifiers, keywords=['diagram', 'generator'], author='Takeshi Komiya', author_email='i.tkomiya at gmail.com', url='http://blockdiag.com/', download_url='http://pypi.python.org/pypi/nwdiag', license='Apache License 2.0', py_modules=[ 'nwdiag_sphinxhelper', 'rackdiag_sphinxhelper', 'packetdiag_sphinxhelper', ], packages=find_packages('src'), package_dir={'': 'src'}, package_data={'': ['buildout.cfg']}, include_package_data=True, install_requires=[ 'setuptools', 'blockdiag>=1.5.0', # -*- Extra requirements: -*- ], extras_require=dict( testing=test_requires, pdf=[ 'reportlab', ], rst=[ 'docutils', ], ), test_suite='nose.collector', tests_require=test_requires, entry_points=""" [console_scripts] nwdiag = nwdiag.command:main rackdiag = rackdiag.command:main packetdiag = packetdiag.command:main [blockdiag_noderenderer] _packet_node = packetdiag.noderenderers """, ) nwdiag-1.0.4/src/0000755000076600000240000000000012451257704014364 5ustar tkomiyastaff00000000000000nwdiag-1.0.4/src/nwdiag/0000755000076600000240000000000012451257704015635 5ustar tkomiyastaff00000000000000nwdiag-1.0.4/src/nwdiag/__init__.py0000644000076600000240000000117312451242567017751 0ustar tkomiyastaff00000000000000# -*- coding: utf-8 -*- # Copyright 2011 Takeshi KOMIYA # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. __version__ = '1.0.4' nwdiag-1.0.4/src/nwdiag/builder.py0000644000076600000240000002513612236403152017633 0ustar tkomiyastaff00000000000000# -*- coding: utf-8 -*- # Copyright 2011 Takeshi KOMIYA # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. from collections import namedtuple from nwdiag import parser from nwdiag.elements import (Diagram, DiagramNode, DiagramEdge, Network, Route, NodeGroup) from blockdiag.utils import unquote, XY class DiagramTreeBuilder: def build(self, tree): self.diagram = Diagram() self.instantiate(None, None, tree) for network in self.diagram.networks: nodes = [n for n in self.diagram.nodes if network in n.networks] if len(nodes) == 0: self.diagram.networks.remove(network) for i, network in enumerate(self.diagram.networks): network.xy = XY(0, i) for subgroup in self.diagram.groups: if len(subgroup.nodes) == 0: self.diagram.groups.remove(subgroup) for node in self.diagram.nodes: if len(node.networks) == 0: msg = "DiagramNode %s does not belong to any networks" raise RuntimeError(msg % node.id) # show networks including same nodes for nw in self.diagram.networks: if nw.hidden and len(nw.nodes) == 2: nodes = nw.nodes is_same = lambda x: set(nodes) & set(x.nodes) == set(nodes) for n in self.diagram.networks: if n != nw and is_same(n): nw.hidden = False break # show network for multiple peer networks from same node nodes = [] for nw in self.diagram.networks: if nw.hidden and len(nw.nodes) == 2: nodes.append(nw.nodes[0]) # parent node (FROM node) for node in [n for n in set(nodes) if nodes.count(n) > 1]: for network in node.networks: if len(network.nodes) == 2: network.hidden = False return self.diagram def instantiate(self, network, group, tree): for stmt in tree.stmts: if isinstance(stmt, parser.Node): node = DiagramNode.get(stmt.id) node.set_attributes(network, stmt.attrs) if group: if (node.group and node.group != self.diagram and (group != node.group)): msg = "DiagramNode could not belong to two groups" raise RuntimeError(msg) node.group = group group.nodes.append(node) elif node.group is None: node.group = self.diagram if network is not None: if network not in node.networks: node.networks.append(network) if node not in network.nodes: network.nodes.append(node) if node not in self.diagram.nodes: self.diagram.nodes.append(node) elif isinstance(stmt, parser.Network): subnetwork = Network.get(stmt.id) subnetwork.label = stmt.id if subnetwork not in self.diagram.networks: self.diagram.networks.append(subnetwork) substmt = namedtuple('Statements', 'stmts')([]) for s in stmt.stmts: if isinstance(s, parser.Attr): subnetwork.set_attribute(s) else: substmt.stmts.append(s) self.instantiate(subnetwork, group, substmt) elif isinstance(stmt, parser.Group): subgroup = NodeGroup.get(stmt.id) if subgroup not in self.diagram.groups: self.diagram.groups.append(subgroup) substmt = namedtuple('Statements', 'stmts')([]) for s in stmt.stmts: if isinstance(s, parser.Attr): subgroup.set_attribute(s) else: substmt.stmts.append(s) self.instantiate(network, subgroup, substmt) elif isinstance(stmt, parser.Peer): nodes = [] for edge in stmt.edges: nodes.append(DiagramNode.get(edge.from_node)) nodes.append(DiagramNode.get(edge.to_node)) for node in nodes: if node.group is None: node.group = self.diagram if node not in self.diagram.nodes: self.diagram.nodes.append(node) if len(nodes[0].networks) == 0: nw = Network.create_anonymous([nodes[0]]) if nw: self.diagram.networks.append(nw) for edge in stmt.edges: from_node = DiagramNode.get(edge.from_node) to_node = DiagramNode.get(edge.to_node) _nodes = [from_node, to_node] nw = Network.create_anonymous(_nodes, edge.attrs) if nw: self.diagram.networks.append(nw) elif isinstance(stmt, parser.Route): nodes = [DiagramNode.get(n) for n in stmt.nodes] for node1, node2 in zip(nodes[:-1], nodes[1:]): route = Route(node1, node2) route.set_attributes(stmt.attrs) self.diagram.routes.append(route) elif isinstance(stmt, parser.Attr): self.diagram.set_attribute(stmt) elif isinstance(stmt, parser.Extension): if stmt.type == 'class': name = unquote(stmt.name) Diagram.classes[name] = stmt elif stmt.type == 'plugin': self.diagram.set_plugin(stmt.name, stmt.attrs) elif isinstance(stmt, parser.Statements): self.instantiate(network, group, stmt) return network class DiagramLayoutManager: def __init__(self, diagram): self.diagram = diagram self.coordinates = [] def run(self): self.do_layout() self.diagram.fixiate() def do_layout(self): self.layout_nodes() self.set_network_size() def layout_nodes(self, group=None): networks = self.diagram.networks if group: nodes = (n for n in self.diagram.nodes if n.group == group) else: nodes = self.diagram.nodes for node in nodes: if node.layouted: continue joined = [g for g in node.networks if g.hidden is False] y1 = min(networks.index(g) for g in node.networks) if joined: y2 = max(networks.index(g) for g in joined) else: y2 = y1 if node.group and node.group != self.diagram and group: starts = min(n.xy.x for n in group.nodes if n.layouted) else: nw = [n for n in node.networks if n.xy.y == y1][0] nodes = [n for n in self.diagram.nodes if nw in n.networks] layouted = [n for n in nodes if n.xy.x > 0] starts = 0 if layouted: layouted.sort(key=lambda a: a.xy.x) basenode = layouted[0] commonnw = set(basenode.networks) & set(node.networks) if basenode.xy.y == y1: starts = basenode.xy.x + 1 elif commonnw and list(commonnw)[0].hidden is True: starts = basenode.xy.x else: starts = basenode.xy.x + 1 - len(nodes) if starts < 0: starts = 0 for x in range(starts, len(self.diagram.nodes)): points = [XY(x, y) for y in range(y1, y2 + 1)] if not set(points) & set(self.coordinates): node.xy = XY(x, y1) node.layouted = True self.coordinates += points break if node.group and node.group != self.diagram and group is None: self.layout_nodes(node.group) if group: self.set_coordinates(group) def set_coordinates(self, group): self.set_group_size(group) xy = group.xy for i in range(xy.x, xy.x + group.colwidth): for j in range(xy.y, xy.y + group.colheight): self.coordinates.append(XY(i, j)) def set_network_size(self): for network in self.diagram.networks: nodes = [n for n in self.diagram.nodes if network in n.networks] nodes.sort(key=lambda a: a.xy.x) x0 = min(n.xy.x for n in nodes) network.xy = XY(x0, network.xy.y) x1 = max(n.xy.x for n in nodes) network.colwidth = x1 - x0 + 1 def set_group_size(self, group): nodes = list(group.nodes) nodes.sort(key=lambda a: a.xy.x) x0 = min(n.xy.x for n in nodes) y0 = min(n.xy.y for n in nodes) group.xy = XY(x0, y0) x1 = max(n.xy.x for n in nodes) y1 = max(n.xy.y for n in nodes) group.colwidth = x1 - x0 + 1 group.colheight = y1 - y0 + 1 class ScreenNodeBuilder: @classmethod def build(cls, tree): DiagramNode.clear() DiagramEdge.clear() NodeGroup.clear() Network.clear() diagram = DiagramTreeBuilder().build(tree) DiagramLayoutManager(diagram).run() diagram = cls.update_network_status(diagram) return diagram @classmethod def update_network_status(cls, diagram): for node in diagram.nodes: above = [nw for nw in node.networks if nw.xy.y <= node.xy.y] if len(above) > 1 and [nw for nw in above if nw.hidden]: for nw in above: nw.hidden = False below = [nw for nw in node.networks if nw.xy.y > node.xy.y] if len(below) > 1 and [nw for nw in below if nw.hidden]: for nw in below: nw.hidden = False return diagram nwdiag-1.0.4/src/nwdiag/command.py0000644000076600000240000000154412220717601017620 0ustar tkomiyastaff00000000000000# -*- coding: utf-8 -*- # Copyright 2011 Takeshi KOMIYA # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. import sys import nwdiag import nwdiag.builder import nwdiag.drawer import nwdiag.parser from blockdiag.utils.bootstrap import Application class NwdiagApp(Application): module = nwdiag def main(args=sys.argv[1:]): return NwdiagApp().run(args) nwdiag-1.0.4/src/nwdiag/drawer.py0000644000076600000240000001473412355217265017505 0ustar tkomiyastaff00000000000000# -*- coding: utf-8 -*- # Copyright 2011 Takeshi KOMIYA # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. from __future__ import division import blockdiag.drawer from nwdiag.metrics import DiagramMetrics from blockdiag.utils import Box, XY class DiagramDraw(blockdiag.drawer.DiagramDraw): def create_metrics(self, *args, **kwargs): return DiagramMetrics(*args, **kwargs) def __init__(self, _format, diagram, filename=None, **kwargs): super(DiagramDraw, self).__init__(_format, diagram, filename, **kwargs) self.drawer.set_options(jump_forward='vertical', jump_radius=self.metrics.jump_radius, jump_shift=self.metrics.jump_shift) @property def groups(self): return self.diagram.groups def pagesize(self, scaled=False): return super(DiagramDraw, self).pagesize(scaled).to_integer_point() def _draw_background(self): super(DiagramDraw, self)._draw_background() self.trunklines_shadow() def trunklines_shadow(self): for network in self.diagram.networks: if network.hidden is False and network.color != 'none': self.trunkline(network, shadow=True) def trunklines(self): metrics = self.metrics for network in self.diagram.networks: if network.hidden is False: self.trunkline(network) if (self.diagram.external_connector and (network == self.diagram.networks[0])): r = metrics.trunk_diameter // 2 pt = metrics.network(network).top pt0 = XY(pt.x, pt.y - metrics.span_height * 2 // 3) pt1 = XY(pt.x, pt.y - r) self.drawer.line([pt0, pt1], fill=network.linecolor) def trunkline(self, network, shadow=False): metrics = self.metrics m = metrics.network(network) r = metrics.trunk_diameter // 2 pt1, pt2 = m.trunkline box = Box(pt1.x, pt1.y - r, pt2.x, pt2.y + r) if shadow: xdiff = self.metrics.shadow_offset.x ydiff = self.metrics.shadow_offset.y // 2 box = Box(pt1.x + xdiff, pt1.y - r + ydiff, pt2.x + xdiff, pt2.y + r + ydiff) if self.format == 'SVG': from blockdiag.imagedraw.simplesvg import pathdata path = pathdata(box[0], box[1]) path.line(box[2], box[1]) path.ellarc(r // 2, r, 0, 0, 1, box[2], box[3]) path.line(box[0], box[3]) path.ellarc(r // 2, r, 0, 0, 1, box[0], box[1]) if shadow: self.drawer.path(path, fill=self.shadow, filter='blur') else: self.drawer.path(path, fill=network.color, outline=network.linecolor) path = pathdata(box[2], box[3]) path.ellarc(r // 2, r, 0, 0, 1, box[2], box[1]) self.drawer.path(path, fill='none', outline=network.linecolor) # for edge jumping line = (XY(box[0], box[1]), XY(box[2], box[1])) self.drawer.line(line, fill='none', jump=True) else: lsection = Box(box[0] - r // 2, box[1], box[0] + r // 2, box[3]) rsection = Box(box[2] - r // 2, box[1], box[2] + r // 2, box[3]) if shadow: color = self.shadow _filter = 'blur' else: color = network.color _filter = None # fill background self.drawer.rectangle(box, outline=color, fill=color, filter=_filter) self.drawer.ellipse(lsection, outline=color, fill=color, filter=_filter) self.drawer.ellipse(rsection, outline=color, fill=color, filter=_filter) if not shadow: upper = (XY(box[0], box[1]), XY(box[2], box[1])) self.drawer.line(upper, fill=network.linecolor, jump=True) bottom = (XY(box[0], box[3]), XY(box[2], box[3])) self.drawer.line(bottom, fill=network.linecolor, jump=True) self.drawer.arc(lsection, 90, 270, fill=network.linecolor) self.drawer.ellipse(rsection, outline=network.linecolor, fill=network.color) def _draw_elements(self): self.trunklines() for network in self.diagram.networks: self.trunkline_label(network) super(DiagramDraw, self)._draw_elements() def trunkline_label(self, network): if network.display_label: m = self.metrics.network(network) self.drawer.textarea(m.textbox, network.display_label, self.metrics.font_for(network), fill=network.textcolor, halign="right") def node(self, node, **kwargs): m = self.metrics for connector in m.node(node).connectors: self.draw_connector(connector) if hasattr(connector, 'subject'): network = connector.subject.network else: network = connector.network if network in node.address: label = node.address[network] self.drawer.textarea(connector.textbox, label, self.metrics.font_for(node), fill=node.textcolor, halign="left") super(DiagramDraw, self).node(node, **kwargs) def draw_connector(self, connector): self.drawer.line(connector.line, fill=connector.network.linecolor, jump=True) def group_label(self, group): if group.label: m = self.metrics.cell(group) self.drawer.textarea(m.grouplabelbox, group.label, self.metrics.font_for(group), valign='top', fill=group.textcolor) nwdiag-1.0.4/src/nwdiag/elements.py0000644000076600000240000001130312355217265020022 0ustar tkomiyastaff00000000000000# -*- coding: utf-8 -*- # Copyright 2011 Takeshi KOMIYA # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. import re import blockdiag.elements from blockdiag.utils import images, unquote class NodeGroup(blockdiag.elements.NodeGroup): pass class DiagramNode(blockdiag.elements.DiagramNode): def __init__(self, _id): super(DiagramNode, self).__init__(_id) self.address = {} self.networks = [] self.layouted = False def set_attributes(self, network, attrs=None): if attrs is None: attrs, network = network, None for attr in attrs: if attr.name == 'address': address = re.sub('\s*,\s*', '\n', unquote(attr.value)) self.address[network] = address else: self.set_attribute(attr) class DiagramEdge(blockdiag.elements.DiagramEdge): pass class Network(blockdiag.elements.NodeGroup): basecolor = (185, 203, 228) linecolor = (0, 0, 0) @classmethod def set_default_linecolor(cls, color): cls.linecolor = images.color_to_rgb(color) @classmethod def set_default_textcolor(cls, color): cls.textcolor = images.color_to_rgb(color) @classmethod def clear(cls): super(Network, cls).clear() cls.basecolor = (185, 203, 228) cls.linecolor = (0, 0, 0) def __init__(self, _id): super(Network, self).__init__(_id) self.address = None self.hidden = False self.colwidth = 1 self.colheight = 1 @classmethod def create_anonymous(cls, nodes, attrs=None): if len(set(nodes)) != len(nodes): msg = "Do not connect same node to peer network: %s" raise RuntimeError(msg % nodes[0].id) # search networks including same nodes is_same = lambda nw: set(nodes) & set(nw.nodes) == set(nodes) if [nw for nw in nodes[0].networks if nw.hidden and is_same(nw)]: return None network = cls(None) network.hidden = True for node in nodes: node.networks.append(network) network.nodes.append(node) if attrs: node.set_attributes(network, attrs) return network @property def display_label(self): if self.label: if self.address: label = "%s\n%s" % (self.label, self.address) else: label = self.label else: label = self.address return label class Route(blockdiag.elements.DiagramEdge): pass class Diagram(blockdiag.elements.Diagram): _DiagramNode = DiagramNode _Network = Network _Route = Route def set_default_linecolor(self, color): super(Diagram, self).set_default_linecolor(color) self._Network.set_default_linecolor(self.linecolor) def set_default_textcolor(self, color): super(Diagram, self).set_default_textcolor(color) self._Network.set_default_text_color(self.textcolor) def set_default_fontsize(self, fontsize): super(Diagram, self).set_default_fontsize(fontsize) self._Network.set_default_fontsize(fontsize) def set_default_fontfamily(self, familyname): super(Diagram, self).set_default_fontfamily(familyname) self._Network.set_default_fontfamily(familyname) def set_default_network_color(self, color): color = images.color_to_rgb(color) self._Network.set_default_color(color) def __init__(self): super(Diagram, self).__init__() self.orientation = 'portrait' self.external_connector = True self.groups = [] self.networks = [] self.routes = [] def set_external_connector(self, value): value = value.lower() if value == 'none': self.external_connector = False else: msg = "unknown external connector: %s\n" % value raise AttributeError(msg) def fixiate(self): self.colwidth = max(n.xy.x + n.colwidth for n in self.nodes) self.colheight = max(n.xy.y + n.colheight for n in self.nodes) colheight = max(nw.xy.y + nw.colheight - 1 for nw in self.networks) if self.colheight < colheight: self.colheight = colheight nwdiag-1.0.4/src/nwdiag/metrics.py0000644000076600000240000001367112217202643017655 0ustar tkomiyastaff00000000000000# -*- coding: utf-8 -*- # Copyright 2011 Takeshi KOMIYA # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. from __future__ import division import math from collections import namedtuple import blockdiag.metrics from nwdiag import elements from blockdiag.utils import Box, XY cellsize = blockdiag.metrics.DiagramMetrics.cellsize class DiagramMetrics(blockdiag.metrics.DiagramMetrics): node_width = cellsize * 13 span_width = cellsize * 6 span_height = cellsize * 13 def __init__(self, diagram, **kwargs): super(DiagramMetrics, self).__init__(diagram, **kwargs) self.networks = diagram.networks self.trunk_diameter = self.cellsize self.jump_shift = self.trunk_diameter // 2 self.jump_radius = self.trunk_diameter self.page_padding = [self.span_height // 2, 0, 0, self.node_width] for node in diagram.nodes: bottom = [n for n in node.networks if n.xy.y > node.xy.y] cnwidth = (len(bottom) + 1) * self.cellsize * 2 if self.cell(node).width < cnwidth: node.width = cnwidth self.spreadsheet.set_node_width(node.xy.x, cnwidth) def node(self, node): n = super(DiagramMetrics, self).cell(node) return NodeMetrics(node, self, n.x1, n.y1, n.x2, n.y2) def cell(self, node): if isinstance(node, elements.Network): metrics = super(DiagramMetrics, self).cell(node, use_padding=False) elif isinstance(node, elements.NodeGroup): n = super(DiagramMetrics, self).cell(node) metrics = GroupMetrics(node, self, n.x1, n.y1, n.x2, n.y2) else: metrics = super(DiagramMetrics, self).cell(node) return metrics def network(self, network): n = self.cell(network) return NetworkMetrics(self, n.x1, n.y1, n.x2, n.y2) class NetworkMetrics(blockdiag.metrics.NodeMetrics): @property def trunkline(self): x0 = self.left.x x1 = self.right.x y = self.top.y return [XY(x0, y), XY(x1, y)] @property def top(self): pt = self.box.top return XY(pt.x, pt.y - self.span_height // 2) @property def left(self): pt = self.box.left return XY(pt.x - self.span_width // 2, pt.y) @property def right(self): pt = self.box.right return XY(pt.x + self.span_width // 2, pt.y) @property def textbox(self): x = self.left.x y = self.top.y width = self.node_width * 3 // 2 height = self.node_height return Box(x - width, y - height // 2, x, y + height // 2) class NodeMetrics(blockdiag.metrics.NodeMetrics): def __init__(self, node, metrics, x1, y1, x2, y2): super(NodeMetrics, self).__init__(metrics, x1, y1, x2, y2) self.node = node @property def connectors(self): above = [n for n in self.node.networks if n.xy.y <= self.node.xy.y] above.sort(key=lambda a: a.xy.y, reverse=True) bottom = [n for n in self.node.networks if n.xy.y > self.node.xy.y] bottom.sort(key=lambda a: a.xy.y) Connector = namedtuple('Connector', 'network line textbox') connectors = [] for networks in [above, bottom]: for network in networks: if network.hidden: span = 0 else: span = self.trunk_diameter // 2 if network.xy.y <= self.node.xy.y: x, y2 = self.top y1 = self.network(network).top.y + span else: x, y1 = self.bottom y2 = self.network(network).top.y - span if len(networks) == 1: dx = 0 else: pos = networks.index(network) base_x = (len(networks) - 1) / 2.0 - pos dx = int(math.floor(base_x * self.cellsize * 2)) width = self.node_width + self.span_width textbox = Box(x + dx + self.cellsize // 2, y2 - self.span_height // 2, x + width - self.cellsize // 2, y2) line = [XY(x + dx, y1), XY(x + dx, y2)] cn = Connector(network, line, textbox) connectors.append(cn) return connectors class GroupMetrics(blockdiag.metrics.NodeMetrics): def __init__(self, group, metrics, x1, y1, x2, y2): super(GroupMetrics, self).__init__(metrics, x1, y1, x2, y2) self.is_root_group = False if group.nodes: networks = group.nodes[0].networks[:] networks.sort(key=lambda a: a.xy.y) network = min(networks) if self.top.x == metrics.network(network).top.x: self.is_root_group = True @property def grouplabelbox(self): box = super(GroupMetrics, self).grouplabelbox span = self.cellsize box = Box(box[0], box[1] + span, box[2], box[3] + span) if self.is_root_group: width = (self.node_width + self.span_width) // 2 box = Box(box[0] + width, box[1], box[2] + width, box[3]) return box @property def marginbox(self): box = super(GroupMetrics, self).box margin_x = self.span_height // 2 - self.cellsize margin_y = self.cellsize return Box(box[0] - margin_y, box[1] - margin_x, box[2] + margin_y, box[3] + margin_x) nwdiag-1.0.4/src/nwdiag/parser.py0000644000076600000240000002027612355217265017513 0ustar tkomiyastaff00000000000000# -*- coding: utf-8 -*- # Copyright (c) 2008/2009 Andrey Vlasovskikh # # 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. r'''A DOT language parser using funcparserlib. The parser is based on [the DOT grammar][1]. It is pretty complete with a few not supported things: * Ports and compass points * XML identifiers At the moment, the parser builds only a parse tree, not an abstract syntax tree (AST) or an API for dealing with DOT. [1]: http://www.graphviz.org/doc/info/lang.html ''' import io from re import MULTILINE, DOTALL from collections import namedtuple from funcparserlib.lexer import make_tokenizer, Token, LexerError from funcparserlib.parser import (some, a, maybe, many, finished, skip) from blockdiag.parser import create_mapper, oneplus_to_list from blockdiag.utils.compat import u Diagram = namedtuple('Diagram', 'id stmts') Network = namedtuple('Network', 'id stmts') Group = namedtuple('Group', 'id stmts') Node = namedtuple('Node', 'id attrs') Attr = namedtuple('Attr', 'name value') Edge = namedtuple('Edge', 'from_node edge_type to_node attrs') Peer = namedtuple('Peer', 'edges') Route = namedtuple('Route', 'edges') Extension = namedtuple('Extension', 'type name attrs') Statements = namedtuple('Statements', 'stmts') class ParseException(Exception): pass def tokenize(string): """str -> Sequence(Token)""" # flake8: NOQA specs = [ # NOQA ('Comment', (r'/\*(.|[\r\n])*?\*/', MULTILINE)), # NOQA ('Comment', (r'(//|#).*',)), # NOQA ('NL', (r'[\r\n]+',)), # NOQA ('Space', (r'[ \t\r\n]+',)), # NOQA ('Name', (u('[A-Za-z_\u0080-\uffff]') + # NOQA u('[A-Za-z_\\-.0-9\u0080-\uffff]*'),)), # NOQA ('Op', (r'([{};,=\[\]]|--|->)',)), # NOQA ('IPAddr', (r'([0-9]+(\.[0-9]+){3}|[:0-9a-fA-F]+)',)), # NOQA ('Number', (r'-?(\.[0-9]+)|([0-9]+(\.[0-9]*)?)',)), # NOQA ('String', (r'(?P"|\').*?(? object""" id_tokens = ['Name', 'IPAddr', 'Number', 'String'] tokval = lambda x: x.value op = lambda s: a(Token('Op', s)) >> tokval op_ = lambda s: skip(op(s)) _id = some(lambda t: t.type in id_tokens) >> tokval keyword = lambda s: a(Token('Name', s)) >> tokval def make_peer(first, edge_type, second, followers, attrs): edges = [Edge(first, edge_type, second, attrs)] from_node = second for edge_type, to_node in followers: edges.append(Edge(from_node, edge_type, to_node, attrs)) from_node = to_node return Peer(edges) def make_route(first, edge_type, second, followers, attrs): edges = [Edge(first, edge_type, second, attrs)] from_node = second for edge_type, to_node in followers: edges.append(Edge(from_node, edge_type, to_node, attrs)) from_node = to_node return Route(edges) # # parts of syntax # node_list = ( _id + many(op_(',') + _id) >> create_mapper(oneplus_to_list) ) option_stmt = ( _id + maybe(op_('=') + _id) >> create_mapper(Attr) ) option_list = ( maybe(op_('[') + option_stmt + many(op_(',') + option_stmt) + op_(']')) >> create_mapper(oneplus_to_list, default_value=[]) ) # node statement:: # A; # B [attr = value, attr = value]; # node_stmt = ( _id + option_list >> create_mapper(Node) ) # peer network statement:: # A -- B; # edge_stmt = ( _id + op('--') + _id + many(op('--') + _id) + option_list >> create_mapper(make_peer) ) # attributes statement:: # default_shape = box; # default_fontsize = 16; # attribute_stmt = ( _id + op_('=') + _id >> create_mapper(Attr) ) # extension statement (class, plugin):: # class red [color = red]; # plugin attributes [name = Name]; # extension_stmt = ( (keyword('class') | keyword('plugin')) + _id + option_list >> create_mapper(Extension) ) # group statement:: # group { # A; # } # group_inline_stmt = ( attribute_stmt | node_stmt ) group_inline_stmt_list = ( many(group_inline_stmt + skip(maybe(op(';')))) ) group_stmt = ( skip(keyword('group')) + maybe(_id) + op_('{') + group_inline_stmt_list + op_('}') >> create_mapper(Group) ) # network statement:: # network { # A; # } # network_inline_stmt = ( attribute_stmt | group_stmt | node_stmt ) network_inline_stmt_list = ( many(network_inline_stmt + skip(maybe(op(';')))) ) network_stmt = ( skip(keyword('network')) + maybe(_id) + op_('{') + network_inline_stmt_list + op_('}') >> create_mapper(Network) ) # route statement:: # route { # A -> B -> C; # } # route_inline_stmt = ( _id + op_('->') + _id + many(op_('->') + _id) + option_list >> create_mapper(make_route) ) route_stmt = ( skip(keyword('route')) + maybe(_id) + op_('{') + network_inline_stmt_list + op_('}') >> create_mapper(Network) ) # # diagram statement:: # nwdiag { # A; # } # diagram_id = ( (keyword('diagram') | keyword('nwdiag')) + maybe(_id) >> list ) diagram_inline_stmt = ( extension_stmt | network_stmt | group_stmt | attribute_stmt | route_stmt | edge_stmt | node_stmt ) diagram_inline_stmt_list = ( many(diagram_inline_stmt + skip(maybe(op(';')))) ) diagram = ( maybe(diagram_id) + op_('{') + diagram_inline_stmt_list + op_('}') >> create_mapper(Diagram) ) dotfile = diagram + skip(finished) return dotfile.parse(seq) def sort_tree(tree): def weight(node): if isinstance(node, (Attr, Extension)): return 1 else: return 2 if hasattr(tree, 'stmts'): tree.stmts.sort(key=lambda x: weight(x)) for stmt in tree.stmts: sort_tree(stmt) return tree def parse_string(string): try: tree = parse(tokenize(string)) return sort_tree(tree) except LexerError as e: message = "Got unexpected token at line %d column %d" % e.place raise ParseException(message) except Exception as e: raise ParseException(str(e)) def parse_file(path): code = io.open(path, 'r', encoding='utf-8-sig').read() return parse_string(code) nwdiag-1.0.4/src/nwdiag/tests/0000755000076600000240000000000012451257704016777 5ustar tkomiyastaff00000000000000nwdiag-1.0.4/src/nwdiag/tests/__init__.py0000644000076600000240000000000012220717577021101 0ustar tkomiyastaff00000000000000nwdiag-1.0.4/src/nwdiag/tests/diagrams/0000755000076600000240000000000012451257704020566 5ustar tkomiyastaff00000000000000nwdiag-1.0.4/src/nwdiag/tests/diagrams/autoexpand_node_width.diag0000644000076600000240000000030512013035776025763 0ustar tkomiyastaff00000000000000{ network { A } network { A } network { A } network { A } network { A } network { A } network { A } network { A } network { A } network { A } network { A } network { B } } nwdiag-1.0.4/src/nwdiag/tests/diagrams/connected_networks.diag0000644000076600000240000000006511635001003025271 0ustar tkomiyastaff00000000000000{ network { A; } network { A; B; } } nwdiag-1.0.4/src/nwdiag/tests/diagrams/connected_networks2.diag0000644000076600000240000000010211635001003025343 0ustar tkomiyastaff00000000000000{ network { A; B; C; D; E; } network { E; Z; } } nwdiag-1.0.4/src/nwdiag/tests/diagrams/connected_networks3.diag0000644000076600000240000000015011635001003025347 0ustar tkomiyastaff00000000000000{ network { A; B; C; D; E; F; G; } network { A; H; I; } network { G; J; K; } } nwdiag-1.0.4/src/nwdiag/tests/diagrams/diagram_attributes.diag0000644000076600000240000000037211672674633025300 0ustar tkomiyastaff00000000000000{ node_height = 160; node_width = 160; span_width = 32; span_height = 32; default_fontsize = 16; default_fontfamily = 'serif'; default_network_color = red; default_textcolor = red; default_linecolor = red; network { A; } } nwdiag-1.0.4/src/nwdiag/tests/diagrams/errors/0000755000076600000240000000000012451257704022102 5ustar tkomiyastaff00000000000000nwdiag-1.0.4/src/nwdiag/tests/diagrams/errors/peer_network_in_same_node.diag0000644000076600000240000000001611635001003030107 0ustar tkomiyastaff00000000000000{ a -- a; } nwdiag-1.0.4/src/nwdiag/tests/diagrams/group_across_network.diag0000644000076600000240000000013011635001003025643 0ustar tkomiyastaff00000000000000{ group { A; B; C; } network { A; B; } network { A; B; C; } } nwdiag-1.0.4/src/nwdiag/tests/diagrams/group_and_peer_network.diag0000644000076600000240000000007711641525315026156 0ustar tkomiyastaff00000000000000{ A -- B; network { group{ B; } C; } } nwdiag-1.0.4/src/nwdiag/tests/diagrams/group_inner_network.diag0000644000076600000240000000007011635001003025467 0ustar tkomiyastaff00000000000000{ network { group { A; B; } } } nwdiag-1.0.4/src/nwdiag/tests/diagrams/group_network.diag0000644000076600000240000000015011641525315024311 0ustar tkomiyastaff00000000000000{ network { A; B; } network { B; C; D; E; } group { B; D; } } nwdiag-1.0.4/src/nwdiag/tests/diagrams/group_outer_network.diag0000644000076600000240000000007611635001003025520 0ustar tkomiyastaff00000000000000{ network { A; B; } group { A; B; } } nwdiag-1.0.4/src/nwdiag/tests/diagrams/node_address_attribute.diag0000644000076600000240000000016611635001003026112 0ustar tkomiyastaff00000000000000{ network { web01 [address = 192.168.0.1]; web02 [address = 2001:0db8:bd05:01d2:288a:1fc0:0001:10ee]; } } nwdiag-1.0.4/src/nwdiag/tests/diagrams/node_attributes.diag0000644000076600000240000000014311635001003024563 0ustar tkomiyastaff00000000000000{ network { A [address = "192.168.0.1"]; B [address = "192.168.0.2, 192.168.0.3"]; } } nwdiag-1.0.4/src/nwdiag/tests/diagrams/node_belongs_to_multiple_networks.diag0000644000076600000240000000011111635001003030372 0ustar tkomiyastaff00000000000000{ network { A; } network { A; } network { A; } } nwdiag-1.0.4/src/nwdiag/tests/diagrams/node_including_hyphen.diag0000644000076600000240000000005411635001003025725 0ustar tkomiyastaff00000000000000{ network { web-01; web-02; } } nwdiag-1.0.4/src/nwdiag/tests/diagrams/peer_network.diag0000644000076600000240000000010011635001003024065 0ustar tkomiyastaff00000000000000{ A [shape = ellipse]; A -- B; network { B; C; } } nwdiag-1.0.4/src/nwdiag/tests/diagrams/peer_network2.diag0000644000076600000240000000005511635001003024160 0ustar tkomiyastaff00000000000000{ network { A; B; } B -- C; } nwdiag-1.0.4/src/nwdiag/tests/diagrams/peer_network3.diag0000644000076600000240000000006211635001003024157 0ustar tkomiyastaff00000000000000{ network { A; B; } B -- C -- D; } nwdiag-1.0.4/src/nwdiag/tests/diagrams/peer_network4.diag0000644000076600000240000000003011641525315024171 0ustar tkomiyastaff00000000000000{ A -- B; A -- C; } nwdiag-1.0.4/src/nwdiag/tests/diagrams/peer_network5.diag0000644000076600000240000000010311641525315024173 0ustar tkomiyastaff00000000000000{ network { A; B; C; } network { D; } A -- B; } nwdiag-1.0.4/src/nwdiag/tests/diagrams/peer_network_branched.diag0000644000076600000240000000006711635001003025727 0ustar tkomiyastaff00000000000000{ A -- B; B -- C; network { B; D; } } nwdiag-1.0.4/src/nwdiag/tests/diagrams/same_peer_network.diag0000644000076600000240000000012611635001003025102 0ustar tkomiyastaff00000000000000{ A -- B -- A -- B; network { B; C; } network { C; D; } } nwdiag-1.0.4/src/nwdiag/tests/diagrams/single_network.diag0000644000076600000240000000003311635001003024420 0ustar tkomiyastaff00000000000000{ network { A; } } nwdiag-1.0.4/src/nwdiag/tests/diagrams/split_group.diag0000644000076600000240000000012511641525315023755 0ustar tkomiyastaff00000000000000{ network { A; B; C; D; E; } group { B; D; } group { C; } } nwdiag-1.0.4/src/nwdiag/tests/diagrams/two_networks.diag0000644000076600000240000000006311635001003024136 0ustar tkomiyastaff00000000000000{ network { A; } network { B; } } nwdiag-1.0.4/src/nwdiag/tests/test_builder.py0000644000076600000240000001476312220717577022054 0ustar tkomiyastaff00000000000000# -*- coding: utf-8 -*- from __future__ import print_function from nwdiag.tests.utils import BuilderTestCase class TestBuilder(BuilderTestCase): def test_diagram_attributes(self): diagram = self.build('diagram_attributes.diag') self.assertEqual(160, diagram.node_width) self.assertEqual(160, diagram.node_height) self.assertEqual(32, diagram.span_width) self.assertEqual(32, diagram.span_height) self.assertEqual(16, diagram.nodes[0].fontsize) self.assertEqual('serif', diagram.nodes[0].fontfamily) self.assertEqual((255, 0, 0), diagram.networks[0].color) self.assertEqual(16, diagram.networks[0].fontsize) self.assertEqual('serif', diagram.networks[0].fontfamily) def test_node_attributes(self): diagram = self.build('node_attributes.diag') network = diagram.networks[0] assert diagram.nodes[0].address[network] == '192.168.0.1' assert diagram.nodes[1].address[network] == '192.168.0.2\n192.168.0.3' def test_node_address_attribute(self): diagram = self.build('node_address_attribute.diag') network = diagram.networks[0] self.assertEqual('192.168.0.1', diagram.nodes[0].address[network]) self.assertEqual('2001:0db8:bd05:01d2:288a:1fc0:0001:10ee', diagram.nodes[1].address[network]) def test_node_including_hyphen_diagram(self): diagram = self.build('node_including_hyphen.diag') self.assertEqual('web-01', diagram.nodes[0].id) self.assertEqual('web-02', diagram.nodes[1].id) def test_single_network_diagram(self): diagram = self.build('single_network.diag') self.assertEqual(1, len(diagram.nodes)) self.assertEqual(1, len(diagram.networks)) self.assertNodeXY(diagram, {'A': (0, 0)}) def test_two_networks_diagram(self): diagram = self.build('two_networks.diag') self.assertNodeXY(diagram, {'A': (0, 0), 'B': (0, 1)}) def test_node_belongs_to_multiple_networks_diagram(self): diagram = self.build('node_belongs_to_multiple_networks.diag') self.assertNodeXY(diagram, {'A': (0, 0)}) def test_connected_networks_diagram(self): diagram = self.build('connected_networks.diag') self.assertNodeXY(diagram, {'A': (0, 0), 'B': (1, 1)}) def test_connected_networks2_diagram(self): diagram = self.build('connected_networks2.diag') self.assertNodeXY(diagram, {'A': (0, 0), 'B': (1, 0), 'C': (2, 0), 'D': (3, 0), 'E': (4, 0), 'Z': (3, 1)}) def test_connected_networks3_diagram(self): diagram = self.build('connected_networks3.diag') self.assertNodeXY(diagram, {'A': (0, 0), 'B': (1, 0), 'C': (2, 0), 'D': (3, 0), 'E': (4, 0), 'F': (5, 0), 'G': (6, 0), 'H': (1, 1), 'I': (2, 1), 'J': (4, 2), 'K': (5, 2)}) def test_group_inner_network_diagram(self): diagram = self.build('group_inner_network.diag') self.assertEqual(2, len(diagram.groups[0].nodes)) self.assertEqual(2, diagram.groups[0].colwidth) self.assertEqual(1, diagram.groups[0].colheight) self.assertNodeXY(diagram, {'A': (0, 0), 'B': (1, 0)}) def test_group_outer_network_diagram(self): diagram = self.build('group_outer_network.diag') self.assertEqual(2, len(diagram.groups[0].nodes)) self.assertEqual(2, diagram.groups[0].colwidth) self.assertEqual(1, diagram.groups[0].colheight) self.assertNodeXY(diagram, {'A': (0, 0), 'B': (1, 0)}) def test_group_across_network_diagram(self): diagram = self.build('group_across_network.diag') self.assertEqual(3, len(diagram.groups[0].nodes)) self.assertEqual(3, diagram.groups[0].colwidth) self.assertEqual(2, diagram.groups[0].colheight) self.assertNodeXY(diagram, {'A': (0, 0), 'B': (1, 0), 'C': (2, 1)}) def test_group_network_diagram(self): diagram = self.build('group_network.diag') self.assertNodeXY(diagram, {'A': (0, 0), 'B': (1, 0), 'C': (0, 1), 'D': (2, 1), 'E': (3, 1)}) def test_split_group_diagram(self): diagram = self.build('split_group.diag') self.assertNodeXY(diagram, {'A': (0, 0), 'B': (1, 0), 'C': (3, 0), 'D': (2, 0), 'E': (4, 0)}) def test_peer_network_diagram(self): diagram = self.build('peer_network.diag') self.assertNodeXY(diagram, {'A': (0, 0), 'B': (0, 1), 'C': (1, 2)}) def test_peer_network2_diagram(self): diagram = self.build('peer_network2.diag') self.assertNodeXY(diagram, {'A': (0, 0), 'B': (1, 0), 'C': (1, 1)}) def test_peer_network3_diagram(self): diagram = self.build('peer_network3.diag') self.assertNodeXY(diagram, {'A': (0, 0), 'B': (1, 0), 'C': (1, 1), 'D': (1, 2)}) def test_peer_network4_diagram(self): diagram = self.build('peer_network4.diag') self.assertNodeXY(diagram, {'A': (0, 0), 'B': (1, 1), 'C': (1, 2)}) def test_peer_network5_diagram(self): diagram = self.build('peer_network5.diag') self.assertNodeXY(diagram, {'A': (0, 0), 'B': (1, 0), 'C': (2, 0), 'D': (2, 1)}) def test_peer_network_branched_diagram(self): diagram = self.build('peer_network_branched.diag') self.assertNodeXY(diagram, {'A': (0, 0), 'B': (0, 1), 'C': (1, 2), 'D': (1, 3)}) def test_same_peer_network_diagram(self): diagram = self.build('same_peer_network.diag') self.assertNodeXY(diagram, {'A': (0, 0), 'B': (0, 1), 'C': (1, 2), 'D': (0, 3)}) def test_group_and_peer_network_diagram(self): diagram = self.build('group_and_peer_network.diag') self.assertNodeXY(diagram, {'A': (0, 0), 'B': (0, 1), 'C': (1, 2)}) def test_peer_network_in_same_node_diagram(self): with self.assertRaises(RuntimeError): self.build('errors/peer_network_in_same_node.diag') nwdiag-1.0.4/src/nwdiag/tests/test_generate_diagram.py0000644000076600000240000000063112236360323023657 0ustar tkomiyastaff00000000000000# -*- coding: utf-8 -*- import os import nwdiag.command from blockdiag.tests.test_generate_diagram import ( get_diagram_files, testcase_generator ) def test_generate(): mainfunc = nwdiag.command.main basepath = os.path.dirname(__file__) files = get_diagram_files(basepath) options = [] for testcase in testcase_generator(basepath, mainfunc, files, options): yield testcase nwdiag-1.0.4/src/nwdiag/tests/test_pep8.py0000644000076600000240000000324712355217265021273 0ustar tkomiyastaff00000000000000# -*- coding: utf-8 -*- from __future__ import print_function import os import sys import pep8 CURRENT_DIR = os.path.dirname(os.path.abspath(__file__)) BASE_DIR = os.path.dirname(CURRENT_DIR) def test_pep8(): arglist = [['statistics', True], ['show-source', True], ['repeat', True], ['paths', [BASE_DIR]]] pep8style = pep8.StyleGuide(arglist, parse_argv=False, config_file=True) options = pep8style.options if options.doctest: import doctest fail_d, done_d = doctest.testmod(report=False, verbose=options.verbose) fail_s, done_s = pep8.selftest(options) count_failed = fail_s + fail_d if not options.quiet: count_passed = done_d + done_s - count_failed print("%d passed and %d failed." % (count_passed, count_failed)) if count_failed: print("Test failed.") else: print("Test passed.") if count_failed: sys.exit(1) if options.testsuite: pep8.init_tests(pep8style) report = pep8style.check_files() if options.statistics: report.print_statistics() if options.benchmark: report.print_benchmark() if options.testsuite and not options.quiet: report.print_results() if report.total_errors: if options.count: sys.stderr.write(str(report.total_errors) + '\n') # sys.exit(1) # reporting errors (additional summary) errors = report.get_count('E') warnings = report.get_count('W') message = 'pep8: %d errors / %d warnings' % (errors, warnings) print(message) assert report.total_errors == 0, message nwdiag-1.0.4/src/nwdiag/tests/test_rst_directives.py0000644000076600000240000007664412433562723023462 0ustar tkomiyastaff00000000000000# -*- coding: utf-8 -*- import sys if sys.version_info < (2, 7): import unittest2 as unittest else: import unittest import os from blockdiag.tests.utils import capture_stderr, with_pil, TemporaryDirectory from docutils import nodes from docutils.core import publish_doctree from docutils.parsers.rst import directives as docutils from nwdiag.utils.rst import directives from blockdiag.utils.compat import u class TestRstDirectives(unittest.TestCase): def setUp(self): self._tmpdir = TemporaryDirectory() def tearDown(self): if 'nwdiag' in docutils._directives: del docutils._directives['nwdiag'] self._tmpdir.clean() @property def tmpdir(self): return self._tmpdir.name def test_setup(self): directives.setup() options = directives.directive_options self.assertIn('nwdiag', docutils._directives) self.assertEqual(directives.NwdiagDirective, docutils._directives['nwdiag']) self.assertEqual('PNG', options['format']) self.assertEqual(False, options['antialias']) self.assertEqual(None, options['fontpath']) self.assertEqual(False, options['nodoctype']) self.assertEqual(False, options['noviewbox']) self.assertEqual(False, options['inline_svg']) def test_setup_with_args(self): directives.setup(format='SVG', antialias=True, fontpath='/dev/null', nodoctype=True, noviewbox=True, inline_svg=True) options = directives.directive_options self.assertIn('nwdiag', docutils._directives) self.assertEqual(directives.NwdiagDirective, docutils._directives['nwdiag']) self.assertEqual('SVG', options['format']) self.assertEqual(True, options['antialias']) self.assertEqual('/dev/null', options['fontpath']) self.assertEqual(True, options['nodoctype']) self.assertEqual(True, options['noviewbox']) self.assertEqual(True, options['inline_svg']) @capture_stderr def test_cleanup(self): directives.setup(format='SVG', outputdir=self.tmpdir, noviewbox=False) text = (".. nwdiag::\n" "\n" " plugin autoclass\n" " network {" " A" " B" " }") publish_doctree(text) from blockdiag import plugins self.assertEqual([], plugins.loaded_plugins) def test_setup_fontpath1(self): with self.assertRaises(RuntimeError): directives.setup(format='SVG', fontpath=['dummy.ttf'], outputdir=self.tmpdir) text = (".. nwdiag::\n" "\n" " network {" " A" " B" " }") publish_doctree(text) def test_setup_fontpath2(self): with self.assertRaises(RuntimeError): directives.setup(format='SVG', fontpath='dummy.ttf', outputdir=self.tmpdir) text = (".. nwdiag::\n" "\n" " network {" " A" " B" " }") publish_doctree(text) def test_setup_nodoctype_is_true(self): directives.setup(format='SVG', outputdir=self.tmpdir, nodoctype=True) text = (".. nwdiag::\n" "\n" " network {" " A" " B" " }") doctree = publish_doctree(text) self.assertEqual(1, len(doctree)) self.assertEqual(nodes.image, type(doctree[-1])) svg = open(doctree[0]['uri']).read() self.assertNotEqual("\n" "\n" "\n" "`_ . Setup ===== Use easy_install or pip:: $ sudo easy_install nwdiag Or $ sudo pip nwdiag spec-text setting sample ======================== Few examples are available. You can get more examples at `blockdiag.com`_ . simple.diag ------------ simple.diag is simply define nodes and transitions by dot-like text format:: diagram { A -> B -> C; lane you { A; B; } lane me { C; } } Usage ===== Execute nwdiag command:: $ nwdiag simple.diag $ ls simple.png simple.png Requirements ============ * Python 2.6, 2.7, 3.2, 3.3, 3.4 * Pillow 2.2.1 or later * funcparserlib 0.3.6 or later * reportlab (optional) * wand and imagemagick (optional) * setuptools License ======= Apache License 2.0 History ======= 1.0.4 (2015-01-01) ------------------ * Support blockdiag 1.5.0 core interface * Fix bugs - Fix ascending syntax was disabled on refactoring parser 1.0.3 (2014-07-03) ------------------ * rackdiag: Fix rackheight syntax (cf. rack { 12U }) was disabled 1.0.2 (2014-07-02) ------------------ * Change interface of docutils node (for sphinxcontrib module) 1.0.1 (2014-06-26) ------------------ * Add options to blockdiag directive (docutils extension) - :width: - :height: - :scale: - :align: - :name: - :class: - :figwidth: - :figclass: 1.0.0 (2013-10-05) ------------------ * Support python 3.2 and 3.3 (thanks to @masayuko) * Drop supports for python 2.4 and 2.5 * Replace dependency: PIL -> Pillow 0.9.4 (2012-12-20) ------------------ * Fix bugs 0.9.3 (2012-12-17) ------------------ * [rackdiag] Allow multiple rackitems in same level * Fix bugs 0.9.2 (2012-11-17) ------------------ * [rackdiag] Add auto-numbering feature * Fix bugs 0.9.1 (2012-10-28) ------------------ * Fix bugs 0.9.0 (2012-10-22) ------------------ * Optimize algorithm for rendering shadow * Add options to docutils directive * [packetdiag] represent splitted packets with dashed-line * Fix bugs 0.8.2 (2012-09-29) ------------------ * Fix bugs 0.8.1 (2012-09-08) ------------------ * Add packetdiag_sphinxhelper 0.8.0 (2012-09-06) ------------------ * Add packetdiag which supports generating packet-header diaagram * [nwdiag] Add diagram attribute: external_connector * Update to new package structure (blockdiag >= 1.1.2) * Allow # to comment syntax * Fix bugs 0.7.0 (2011-11-19) ------------------ * Accept N/A rack-unit * Add fontfamily attribute for switching fontface * Fix bugs 0.6.1 (2011-11-06) ------------------ * [rackdiag] Support multiple racks rendering * [rackdiag] Add rack attribute: unit-height, weight, ampere, ascending * [rackdiag] Support putting multiple items to same rack-unit 0.6.0 (2011-11-06) ------------------ * Add rackdiag which supports genarating rack-structure diagram * Add docutils extension * Fix bugs 0.5.3 (2011-11-01) ------------------ * Add class feature (experimental) 0.5.2 (2011-11-01) ------------------ * Follow blockdiag-0.9.7 interface 0.5.1 (2011-10-19) ------------------ * Follow blockdiag-0.9.5 interface 0.5.0 (2011-10-07) ------------------ * Change shape of trunkline like a pipeline * Add network attribute: color * Add diagram attribute: default_network_color 0.4.2 (2011-09-30) ------------------ * Add diagram attributes: default_text_color * Fix bugs 0.4.1 (2011-09-26) ------------------ * Add diagram attributes: default_node_color, default_group_color and default_line_color * Fix bugs 0.4.0 (2011-08-09) ------------------ * Add syntax for peer network 0.3.3 (2011-08-07) ------------------ * Add syntax for peer network (experimental) * Fix bugs 0.3.2 (2011-08-03) ------------------ * Fix bugs 0.3.1 (2011-08-01) ------------------ * Fix bugs 0.3.0 (2011-07-18) ------------------ * Upgrade layout engine * Allow to note ip addresses directly * Allow node_id including hyphen chars * Fix bugs 0.2.7 (2011-07-05) ------------------ * Fix bugs 0.2.6 (2011-07-03) ------------------ * Allow "." to id token * Support input from stdin * Support multiple node address (using comma) * Do not sort networks (ordered as declarations) * Fix bugs 0.2.5 (2011-06-29) ------------------ * Adjust parameters for span and margin 0.2.4 (2011-05-17) ------------------ * Add --version option * Fix bugs 0.2.3 (2011-05-15) ------------------ * Fix bugs 0.2.2 (2011-05-15) ------------------ * Implement grouping nodes 0.2.1 (2011-05-14) ------------------ * Change license to Apache License 2.0 * Support blockdiag 0.8.1 core interface 0.2.0 (2011-05-02) ------------------ * Rename package to nwdiag 0.1.6 (2011-04-30) ------------------ * Fix bugs 0.1.5 (2011-04-26) ------------------ * Fix bugs 0.1.4 (2011-04-25) ------------------ * Implement jumped edge * Fix bugs 0.1.3 (2011-04-23) ------------------ * Fix sphinxcontrib_netdiag was not worked 0.1.2 (2011-04-23) ------------------ * Support multi-homed host * Drop network-bridge sytanx (cf. net_a -- net_b) 0.1.1 (2011-04-10) ------------------ * Fix bugs 0.1.0 (2011-04-09) ------------------ * First release Keywords: diagram,generator Platform: UNKNOWN Classifier: Development Status :: 3 - Alpha Classifier: Intended Audience :: System Administrators Classifier: License :: OSI Approved :: Apache Software License Classifier: Programming Language :: Python Classifier: Topic :: Software Development Classifier: Topic :: Software Development :: Documentation Classifier: Topic :: Text Processing :: Markup nwdiag-1.0.4/src/nwdiag.egg-info/requires.txt0000644000076600000240000000015212451257676021735 0ustar tkomiyastaff00000000000000setuptools blockdiag>=1.5.0 [pdf] reportlab [rst] docutils [testing] nose pep8>=1.3 reportlab docutils nwdiag-1.0.4/src/nwdiag.egg-info/SOURCES.txt0000644000076600000240000001071312451257677021226 0ustar tkomiyastaff00000000000000LICENSE MANIFEST.in README.rst bootstrap.py buildout.cfg nwdiag.1 packetdiag.1 rackdiag.1 setup.cfg setup.py tox.ini examples/nwdiag/node_groups1.diag examples/nwdiag/node_groups1.png examples/nwdiag/node_groups1.svg examples/nwdiag/node_groups2.diag examples/nwdiag/node_groups2.png examples/nwdiag/node_groups2.svg examples/nwdiag/simple.diag examples/nwdiag/simple.png examples/nwdiag/simple.svg examples/packetdiag/tcp.diag src/nwdiag_sphinxhelper.py src/packetdiag_sphinxhelper.py src/rackdiag_sphinxhelper.py src/nwdiag/__init__.py src/nwdiag/builder.py src/nwdiag/command.py src/nwdiag/drawer.py src/nwdiag/elements.py src/nwdiag/metrics.py src/nwdiag/parser.py src/nwdiag.egg-info/PKG-INFO src/nwdiag.egg-info/SOURCES.txt src/nwdiag.egg-info/dependency_links.txt src/nwdiag.egg-info/entry_points.txt src/nwdiag.egg-info/requires.txt src/nwdiag.egg-info/top_level.txt src/nwdiag/tests/__init__.py src/nwdiag/tests/test_builder.py src/nwdiag/tests/test_generate_diagram.py src/nwdiag/tests/test_pep8.py src/nwdiag/tests/test_rst_directives.py src/nwdiag/tests/utils.py src/nwdiag/tests/VLGothic/LICENSE src/nwdiag/tests/VLGothic/LICENSE.en src/nwdiag/tests/VLGothic/LICENSE_E.mplus src/nwdiag/tests/VLGothic/LICENSE_J.mplus src/nwdiag/tests/VLGothic/VL-Gothic-Regular.ttf src/nwdiag/tests/diagrams/autoexpand_node_width.diag src/nwdiag/tests/diagrams/connected_networks.diag src/nwdiag/tests/diagrams/connected_networks2.diag src/nwdiag/tests/diagrams/connected_networks3.diag src/nwdiag/tests/diagrams/diagram_attributes.diag src/nwdiag/tests/diagrams/group_across_network.diag src/nwdiag/tests/diagrams/group_and_peer_network.diag src/nwdiag/tests/diagrams/group_inner_network.diag src/nwdiag/tests/diagrams/group_network.diag src/nwdiag/tests/diagrams/group_outer_network.diag src/nwdiag/tests/diagrams/node_address_attribute.diag src/nwdiag/tests/diagrams/node_attributes.diag src/nwdiag/tests/diagrams/node_belongs_to_multiple_networks.diag src/nwdiag/tests/diagrams/node_including_hyphen.diag src/nwdiag/tests/diagrams/peer_network.diag src/nwdiag/tests/diagrams/peer_network2.diag src/nwdiag/tests/diagrams/peer_network3.diag src/nwdiag/tests/diagrams/peer_network4.diag src/nwdiag/tests/diagrams/peer_network5.diag src/nwdiag/tests/diagrams/peer_network_branched.diag src/nwdiag/tests/diagrams/same_peer_network.diag src/nwdiag/tests/diagrams/single_network.diag src/nwdiag/tests/diagrams/split_group.diag src/nwdiag/tests/diagrams/two_networks.diag src/nwdiag/tests/diagrams/errors/peer_network_in_same_node.diag src/nwdiag/utils/__init__.py src/nwdiag/utils/rst/__init__.py src/nwdiag/utils/rst/directives.py src/nwdiag/utils/rst/nodes.py src/packetdiag/__init__.py src/packetdiag/builder.py src/packetdiag/command.py src/packetdiag/drawer.py src/packetdiag/elements.py src/packetdiag/metrics.py src/packetdiag/noderenderers.py src/packetdiag/parser.py src/packetdiag/tests/test_generate_diagram.py src/packetdiag/tests/test_pep8.py src/packetdiag/tests/test_rst_directives.py src/packetdiag/tests/VLGothic/VL-Gothic-Regular.ttf src/packetdiag/tests/diagrams/oneliner.diag src/packetdiag/tests/diagrams/oneliner_with_quoted.diag src/packetdiag/tests/diagrams/oneliner_without_last_semicolon.diag src/packetdiag/tests/diagrams/scale_direction.diag src/packetdiag/tests/diagrams/scale_interval.diag src/packetdiag/tests/diagrams/tcp.diag src/packetdiag/tests/diagrams/tcp_2.diag src/packetdiag/utils/__init__.py src/packetdiag/utils/rst/__init__.py src/packetdiag/utils/rst/directives.py src/packetdiag/utils/rst/nodes.py src/rackdiag/__init__.py src/rackdiag/builder.py src/rackdiag/command.py src/rackdiag/drawer.py src/rackdiag/elements.py src/rackdiag/metrics.py src/rackdiag/parser.py src/rackdiag/tests/test_builder.py src/rackdiag/tests/test_generate_diagram.py src/rackdiag/tests/test_pep8.py src/rackdiag/tests/test_rst_directives.py src/rackdiag/tests/VLGothic/VL-Gothic-Regular.ttf src/rackdiag/tests/diagrams/ascending.diag src/rackdiag/tests/diagrams/autonumber.diag src/rackdiag/tests/diagrams/multi_rackitem.diag src/rackdiag/tests/diagrams/multi_racks.diag src/rackdiag/tests/diagrams/oneliner.diag src/rackdiag/tests/diagrams/oneliner_with_quoted.diag src/rackdiag/tests/diagrams/oneliner_without_last_semicolon.diag src/rackdiag/tests/diagrams/rack_height.diag src/rackdiag/tests/diagrams/rack_height_for_multi_racks.diag src/rackdiag/tests/diagrams/simple.diag src/rackdiag/utils/__init__.py src/rackdiag/utils/math.py src/rackdiag/utils/rst/__init__.py src/rackdiag/utils/rst/directives.py src/rackdiag/utils/rst/nodes.pynwdiag-1.0.4/src/nwdiag.egg-info/top_level.txt0000644000076600000240000000013512451257676022070 0ustar tkomiyastaff00000000000000nwdiag nwdiag_sphinxhelper packetdiag packetdiag_sphinxhelper rackdiag rackdiag_sphinxhelper nwdiag-1.0.4/src/nwdiag_sphinxhelper.py0000644000076600000240000000201012224140073020755 0ustar tkomiyastaff00000000000000# -*- coding: utf-8 -*- # Copyright 2011 Takeshi KOMIYA # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. __all__ = [ 'core', 'utils' ] import nwdiag.parser import nwdiag.builder import nwdiag.drawer core = nwdiag import nwdiag.utils.rst.nodes import nwdiag.utils.rst.directives utils = nwdiag.utils import blockdiag.utils.bootstrap utils.bootstrap = blockdiag.utils.bootstrap import blockdiag.utils.compat utils.compat = blockdiag.utils.compat import blockdiag.utils.fontmap utils.fontmap = blockdiag.utils.fontmap nwdiag-1.0.4/src/packetdiag/0000755000076600000240000000000012451257704016460 5ustar tkomiyastaff00000000000000nwdiag-1.0.4/src/packetdiag/__init__.py0000644000076600000240000000122012013036077020554 0ustar tkomiyastaff00000000000000# -*- coding: utf-8 -*- # Copyright 2011 Takeshi KOMIYA # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. from nwdiag import __version__ __version__ nwdiag-1.0.4/src/packetdiag/builder.py0000644000076600000240000000752712355217265020474 0ustar tkomiyastaff00000000000000# -*- coding: utf-8 -*- # Copyright 2011 Takeshi KOMIYA # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. from __future__ import division from packetdiag import parser from packetdiag.elements import Diagram, FieldItem, DiagramNode from blockdiag.utils import unquote, XY class DiagramTreeBuilder: def build(self, tree): self.diagram = Diagram() self.instantiate(tree) return self.diagram def instantiate(self, tree): for stmt in tree.stmts: if isinstance(stmt, parser.Attr): self.diagram.set_attribute(stmt) elif isinstance(stmt, parser.FieldItem): item = FieldItem(stmt.begin, stmt.end, unquote(stmt.label)) item.set_attributes(stmt.attrs) if item.number is None: if len(self.diagram.fields) == 0: item.number = 0 else: last_item = self.diagram.fields[-1] item.number = last_item.number + last_item.colwidth self.diagram.fields.append(item) elif isinstance(stmt, parser.AttrPlugin): self.diagram.set_plugin(stmt.name, stmt.attrs) class DiagramLayoutManager: def __init__(self, diagram): self.diagram = diagram def split_field_by_column(self): for field in self.diagram.fields: while True: x = field.number % self.diagram.colwidth if x + field.colwidth <= self.diagram.colwidth: break else: colwidth = self.diagram.colwidth - x splitted = field.duplicate() splitted.colwidth = colwidth if self.diagram.scale_direction == "left_to_right": splitted.separated_right = True else: splitted.separated_left = True self.diagram.fields.append(splitted) field.number += colwidth field.colwidth -= colwidth if self.diagram.scale_direction == "left_to_right": field.separated_left = True else: field.separated_right = True yield field def run(self): filled = {} for field in self.split_field_by_column(): x = field.number % self.diagram.colwidth y = field.number // self.diagram.colwidth if filled.get(y) is None: filled[y] = {} for rx in range(x, x + field.colwidth): if filled[y].get(rx): msg = ("Field '%s' is conflicted to other field\n" % field.label) raise AttributeError(msg) filled[y][rx] = True if self.diagram.scale_direction == "right_to_left": x = self.diagram.colwidth - x - field.colwidth field.xy = XY(x, y) self.diagram.fixiate() class ScreenNodeBuilder: @classmethod def build(cls, tree): DiagramNode.clear() Diagram.clear() return cls(tree).run() def __init__(self, tree): self.diagram = DiagramTreeBuilder().build(tree) def run(self): DiagramLayoutManager(self.diagram).run() return self.diagram nwdiag-1.0.4/src/packetdiag/command.py0000644000076600000240000000160012222145075020436 0ustar tkomiyastaff00000000000000# -*- coding: utf-8 -*- # Copyright 2011 Takeshi KOMIYA # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. import sys import packetdiag import packetdiag.builder import packetdiag.drawer import packetdiag.parser from blockdiag.utils.bootstrap import Application class PacketdiagApp(Application): module = packetdiag def main(args=sys.argv[1:]): return PacketdiagApp().run(args) nwdiag-1.0.4/src/packetdiag/drawer.py0000644000076600000240000000334012217202643020306 0ustar tkomiyastaff00000000000000# -*- coding: utf-8 -*- # Copyright 2011 Takeshi KOMIYA # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. import blockdiag.drawer from packetdiag.metrics import DiagramMetrics from blockdiag.utils.compat import u class DiagramDraw(blockdiag.drawer.DiagramDraw): def create_metrics(self, *args, **kwargs): return DiagramMetrics(*args, **kwargs) def _draw_background(self): # do not call blockdiag.DiagramDraw#_draw_background() scale_interval = self.diagram.scale_interval if scale_interval is None: scale_interval = self.diagram.colwidth / 2 # draw measure lines and labels font = self.metrics.font_for(None) for i in range(self.diagram.colwidth + 1): line = self.metrics.measure_line(i) self.drawer.line(line, fill=self.diagram.linecolor) if (i % scale_interval) == 0: box = self.metrics.measure_label(i) if self.diagram.scale_direction == "left_to_right": label = u(str(i)) else: label = u(str(self.diagram.colwidth - i)) self.drawer.textarea(box, label, font, fill=self.diagram.textcolor) nwdiag-1.0.4/src/packetdiag/elements.py0000644000076600000240000000462012355217265020651 0ustar tkomiyastaff00000000000000# -*- coding: utf-8 -*- # Copyright 2011 Takeshi KOMIYA # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. import blockdiag.elements class DiagramNode(blockdiag.elements.DiagramNode): pass class FieldItem(blockdiag.elements.DiagramNode): shape = '_packet_node' desctable = ['number', 'label', 'description'] attrname = dict(number='Seq', label='Name', description='Description') def __init__(self, begin, end, label): super(FieldItem, self).__init__(None) self.label = label self.separated_right = False self.separated_left = False if begin is None: self.number = None self.colwidth = 1 elif end is None: self.number = int(begin) self.colwidth = 1 else: self.number = int(begin) self.colwidth = int(end) - int(begin) + 1 if self.colwidth <= 0: msg = ("Invalid field size definition: %d-%d: %s\n" % (begin, end, label)) raise AttributeError(msg) def set_height(self, value): self.colheight = int(value) def set_len(self, value): self.colwidth = int(value) class Diagram(blockdiag.elements.Diagram): _DiagramNode = FieldItem def __init__(self): super(Diagram, self).__init__() self.colwidth = 16 self.scale_interval = None self.scale_direction = "left_to_right" self.int_attrs.append('scale_interval') @property def fields(self): return self.nodes def set_scale_direction(self, value): value = value.lower() if value in ('ltr', 'left_to_right'): self.scale_direction = 'left_to_right' elif value in ('rtl', 'right_to_left'): self.scale_direction = 'right_to_left' else: msg = "unknown scale_direction: %s\n" % value raise AttributeError(msg) nwdiag-1.0.4/src/packetdiag/metrics.py0000644000076600000240000000446112217202643020475 0ustar tkomiyastaff00000000000000# -*- coding: utf-8 -*- # Copyright 2011 Takeshi KOMIYA # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. import blockdiag.metrics from collections import defaultdict, namedtuple from blockdiag.utils import Box, XY class DiagramMetrics(blockdiag.metrics.DiagramMetrics): def __init__(self, diagram, **kwargs): span_height = self.span_height span_width = self.span_width self.span_height = 0 self.span_width = 0 self.node_width = self.cellsize * 3 self.colwidth = diagram.colwidth super(DiagramMetrics, self).__init__(diagram, **kwargs) # reset node_width FORCE self.spreadsheet.node_width = defaultdict(lambda: self.node_width) self.spreadsheet.set_span_height(0, span_height * 2) self.spreadsheet.set_span_height(diagram.colheight, span_height) self.spreadsheet.set_span_width(0, span_width) self.spreadsheet.set_span_width(diagram.colwidth, span_width) def measure_line(self, n): _Node = namedtuple('Node', 'xy') if n == self.colwidth: node = _Node(XY(n - 1, 0)) pt = self.spreadsheet._node_topleft(node, use_padding=False) pt = pt.shift(x=self.node_width) else: node = _Node(XY(n, 0)) pt = self.spreadsheet._node_topleft(node, use_padding=False) if n * 2.0 % self.colwidth == 0: return (XY(pt.x, pt.y - self.cellsize * 4), pt) elif n * 4.0 % self.colwidth == 0: return (XY(pt.x, pt.y - self.cellsize * 4), pt) else: return (XY(pt.x, pt.y - self.cellsize * 2), pt) def measure_label(self, n): top, _ = self.measure_line(n) cellsize = self.cellsize return Box(top.x - cellsize * 4, top.y - cellsize * 3, top.x + cellsize * 4, top.y) nwdiag-1.0.4/src/packetdiag/noderenderers.py0000644000076600000240000000337312222145142021663 0ustar tkomiyastaff00000000000000# -*- coding: utf-8 -*- # Copyright 2011 Takeshi KOMIYA # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. from blockdiag.noderenderer import NodeShape from blockdiag.noderenderer import install_renderer class PacketNode(NodeShape): def render_shape(self, drawer, _, **kwargs): # draw outline box = self.metrics.cell(self.node).box if kwargs.get('shadow'): pass else: drawer.rectangle(box, fill=self.node.color, outline=self.node.color) if self.node.background: drawer.loadImage(self.node.background, self.textbox) self.line(drawer, box.topleft, box.topright, False) self.line(drawer, box.topright, box.bottomright, self.node.separated_right) self.line(drawer, box.bottomright, box.bottomleft, False) self.line(drawer, box.bottomleft, box.topleft, self.node.separated_left) def line(self, drawer, _from, _to, is_dashed): if is_dashed: style = 'dashed' else: style = self.node.style drawer.line((_from, _to), fill=self.node.linecolor, style=style) def setup(self): install_renderer('_packet_node', PacketNode) nwdiag-1.0.4/src/packetdiag/parser.py0000644000076600000240000001525312355217265020335 0ustar tkomiyastaff00000000000000# -*- coding: utf-8 -*- # Copyright (c) 2008/2009 Andrey Vlasovskikh # # 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. r'''A DOT language parser using funcparserlib. The parser is based on [the DOT grammar][1]. It is pretty complete with a few not supported things: * Ports and compass points * XML identifiers At the moment, the parser builds only a parse tree, not an abstract syntax tree (AST) or an API for dealing with DOT. [1]: http://www.graphviz.org/doc/info/lang.html ''' import re import io from re import MULTILINE, DOTALL from collections import namedtuple from funcparserlib.lexer import make_tokenizer, Token, LexerError from funcparserlib.parser import (some, a, maybe, many, finished, skip) from blockdiag.parser import create_mapper, oneplus_to_list from blockdiag.utils.compat import u Diagram = namedtuple('Diagram', 'id stmts') FieldItem = namedtuple('FieldItem', 'begin end label attrs') Attr = namedtuple('Attr', 'name value') Extension = namedtuple('Extension', 'type name attrs') class ParseException(Exception): pass def tokenize(string): """str -> Sequence(Token)""" # flake8: NOQA specs = [ # NOQA ('Comment', (r'/\*(.|[\r\n])*?\*/', MULTILINE)), # NOQA ('Comment', (r'(//|#).*',)), # NOQA ('NL', (r'[\r\n]+',)), # NOQA ('Number', (r'[0-9]+',)), # NOQA ('QuotedFieldItem', (r'(?<=[:*\-])\s*(?P"|\').*?(?"|\').*?(? object""" fielditem_tokens = ['QuotedFieldItem', 'FieldItem'] tokval = lambda x: x.value op = lambda s: a(Token('Op', s)) >> tokval op_ = lambda s: skip(op(s)) _id = some(lambda t: t.type in ['Name', 'Number', 'String']) >> tokval keyword = lambda s: a(Token('Name', s)) >> tokval number = some(lambda t: t.type == 'Number').named('number') >> tokval field_item = some(lambda t: t.type in fielditem_tokens) >> tokval def make_num_field_item(_from, to, text, attr): return FieldItem(_from, to, text.strip(), attr) def make_nonnum_field_item(text, attr): return FieldItem(None, None, text.strip(), attr) # # parts of syntax # option_stmt = ( _id + maybe(op_('=') + _id) >> create_mapper(Attr) ) option_list = ( maybe(op_('[') + option_stmt + many(op_(',') + option_stmt) + op_(']')) >> create_mapper(oneplus_to_list, default_value=[]) ) # field statement:: # 1: A # 2-3: B [attr = value, attr = value]; # * C [attr = value, attr = value]; # * D [attr = value, attr = value]; # numbered_field_item_stmt = ( number + maybe(op_('-') + number) + op_(':') + field_item + option_list >> create_mapper(make_num_field_item) ) nonnumbered_field_item_stmt = ( (op_('-') | op_('*')) + field_item + option_list >> create_mapper(make_nonnum_field_item) ) field_item_stmt = ( numbered_field_item_stmt | nonnumbered_field_item_stmt ) # attributes statement:: # default_shape = box; # default_fontsize = 16; # attribute_stmt = ( _id + op_('=') + _id >> create_mapper(Attr) ) # extension statement (plugin):: # plugin attributes [name = Name]; # extension_stmt = ( keyword('plugin') + _id + option_list >> create_mapper(Extension) ) # # diagram statement:: # packetdiag { # A; # } # diagram_id = ( (keyword('diagram') | keyword('packetdiag')) + maybe(_id) >> list ) diagram_inline_stmt = ( extension_stmt | field_item_stmt | attribute_stmt ) diagram_inline_stmt_list = ( many(diagram_inline_stmt + skip(maybe(op(';')))) ) diagram = ( maybe(diagram_id) + op_('{') + diagram_inline_stmt_list + op_('}') >> create_mapper(Diagram) ) dotfile = diagram + skip(finished) return dotfile.parse(seq) def sort_tree(tree): def weight(node): if isinstance(node, (Attr, Extension)): return 1 else: return 2 if hasattr(tree, 'stmts'): tree.stmts.sort(key=lambda x: weight(x)) for stmt in tree.stmts: sort_tree(stmt) return tree def parse_string(string): try: tree = parse(tokenize(string)) return sort_tree(tree) except LexerError as e: message = "Got unexpected token at line %d column %d" % e.place raise ParseException(message) except Exception as e: raise ParseException(str(e)) def parse_file(path): code = io.open(path, 'r', encoding='utf-8-sig').read() return parse_string(code) nwdiag-1.0.4/src/packetdiag/tests/0000755000076600000240000000000012451257704017622 5ustar tkomiyastaff00000000000000nwdiag-1.0.4/src/packetdiag/tests/diagrams/0000755000076600000240000000000012451257704021411 5ustar tkomiyastaff00000000000000nwdiag-1.0.4/src/packetdiag/tests/diagrams/oneliner.diag0000644000076600000240000000003512355217265024051 0ustar tkomiyastaff00000000000000{ 0: A; 1: B; 2: C; 3: D; } nwdiag-1.0.4/src/packetdiag/tests/diagrams/oneliner_with_quoted.diag0000644000076600000240000000003712355217265026467 0ustar tkomiyastaff00000000000000{ 0: A; 1: B; 2: C; 3: "D}" } nwdiag-1.0.4/src/packetdiag/tests/diagrams/oneliner_without_last_semicolon.diag0000644000076600000240000000003412355217265030726 0ustar tkomiyastaff00000000000000{ 0: A; 1: B; 2: C; 3: D } nwdiag-1.0.4/src/packetdiag/tests/diagrams/scale_direction.diag0000644000076600000240000000024712115140622025354 0ustar tkomiyastaff00000000000000{ scale_direction = rtl; 0-3: Source Port 4-7: Destination Port 8-11: Sequence Number 12-15: Acknowledgment Number 16-19: Data Offset 20-27: Reserved } nwdiag-1.0.4/src/packetdiag/tests/diagrams/scale_interval.diag0000644000076600000240000000024412115141141025212 0ustar tkomiyastaff00000000000000{ scale_interval = 2; 0-3: Source Port 4-7: Destination Port 8-11: Sequence Number 12-15: Acknowledgment Number 16-19: Data Offset 20-27: Reserved } nwdiag-1.0.4/src/packetdiag/tests/diagrams/tcp.diag0000644000076600000240000000072412036770551023027 0ustar tkomiyastaff00000000000000{ colwidth = 32 node_height = 72 0-15: Source Port 16-31: Destination Port 32-63: Sequence Number 64-95: Acknowledgment Number 96-99: Data Offset 100-105: Reserved 106: URG [rotate = 270] 107: ACK [rotate = 270] 108: PSH [rotate = 270] 109: RST [rotate = 270] 110: SYN [rotate = 270] 111: FIN [rotate = 270] 112-127: Window 128-143: Checksum 144-159: Urgent Pointer 160-191: (Options and Padding) 192-223: data [colheight = 3] } nwdiag-1.0.4/src/packetdiag/tests/diagrams/tcp_2.diag0000644000076600000240000000074112236436223023244 0ustar tkomiyastaff00000000000000{ colwidth = 32 * Source Port [len = 16] * Destination Port [len = 16] * Sequence Number [len = 32] * Acknowledgement Number [len = 32] * Data Offset [len = 4] * Reserved [len = 6] * URG [rotate = 270] * ACK [rotate = 270] * PSH [rotate = 270] * RST [rotate = 270] * SYN [rotate = 270] * FIN [rotate = 270] * Window [len = 16] * Checksum [len = 16] * Urgent Pointer [len = 16] * (Options and Padding) [len = 32] * data [len = 32, height = 3] } nwdiag-1.0.4/src/packetdiag/tests/test_generate_diagram.py0000644000076600000240000000064112236360351024504 0ustar tkomiyastaff00000000000000# -*- coding: utf-8 -*- import os import packetdiag.command from blockdiag.tests.test_generate_diagram import ( get_diagram_files, testcase_generator ) def test_generate(): mainfunc = packetdiag.command.main basepath = os.path.dirname(__file__) files = get_diagram_files(basepath) options = [] for testcase in testcase_generator(basepath, mainfunc, files, options): yield testcase nwdiag-1.0.4/src/packetdiag/tests/test_pep8.py0000644000076600000240000000324712355217265022116 0ustar tkomiyastaff00000000000000# -*- coding: utf-8 -*- from __future__ import print_function import os import sys import pep8 CURRENT_DIR = os.path.dirname(os.path.abspath(__file__)) BASE_DIR = os.path.dirname(CURRENT_DIR) def test_pep8(): arglist = [['statistics', True], ['show-source', True], ['repeat', True], ['paths', [BASE_DIR]]] pep8style = pep8.StyleGuide(arglist, parse_argv=False, config_file=True) options = pep8style.options if options.doctest: import doctest fail_d, done_d = doctest.testmod(report=False, verbose=options.verbose) fail_s, done_s = pep8.selftest(options) count_failed = fail_s + fail_d if not options.quiet: count_passed = done_d + done_s - count_failed print("%d passed and %d failed." % (count_passed, count_failed)) if count_failed: print("Test failed.") else: print("Test passed.") if count_failed: sys.exit(1) if options.testsuite: pep8.init_tests(pep8style) report = pep8style.check_files() if options.statistics: report.print_statistics() if options.benchmark: report.print_benchmark() if options.testsuite and not options.quiet: report.print_results() if report.total_errors: if options.count: sys.stderr.write(str(report.total_errors) + '\n') # sys.exit(1) # reporting errors (additional summary) errors = report.get_count('E') warnings = report.get_count('W') message = 'pep8: %d errors / %d warnings' % (errors, warnings) print(message) assert report.total_errors == 0, message nwdiag-1.0.4/src/packetdiag/tests/test_rst_directives.py0000644000076600000240000007060612433562723024275 0ustar tkomiyastaff00000000000000# -*- coding: utf-8 -*- import sys if sys.version_info < (2, 7): import unittest2 as unittest else: import unittest import os from blockdiag.tests.utils import capture_stderr, with_pil, TemporaryDirectory from docutils import nodes from docutils.core import publish_doctree from docutils.parsers.rst import directives as docutils from packetdiag.utils.rst import directives from blockdiag.utils.compat import u class TestRstDirectives(unittest.TestCase): def setUp(self): self._tmpdir = TemporaryDirectory() def tearDown(self): if 'packetdiag' in docutils._directives: del docutils._directives['packetdiag'] self._tmpdir.clean() @property def tmpdir(self): return self._tmpdir.name def test_setup(self): directives.setup() options = directives.directive_options self.assertIn('packetdiag', docutils._directives) self.assertEqual(directives.PacketdiagDirective, docutils._directives['packetdiag']) self.assertEqual('PNG', options['format']) self.assertEqual(False, options['antialias']) self.assertEqual(None, options['fontpath']) self.assertEqual(False, options['nodoctype']) self.assertEqual(False, options['noviewbox']) self.assertEqual(False, options['inline_svg']) def test_setup_with_args(self): directives.setup(format='SVG', antialias=True, fontpath='/dev/null', nodoctype=True, noviewbox=True, inline_svg=True) options = directives.directive_options self.assertIn('packetdiag', docutils._directives) self.assertEqual(directives.PacketdiagDirective, docutils._directives['packetdiag']) self.assertEqual('SVG', options['format']) self.assertEqual(True, options['antialias']) self.assertEqual('/dev/null', options['fontpath']) self.assertEqual(True, options['nodoctype']) self.assertEqual(True, options['noviewbox']) self.assertEqual(True, options['inline_svg']) @capture_stderr def test_cleanup(self): directives.setup(format='SVG', outputdir=self.tmpdir, noviewbox=False) text = (".. packetdiag::\n" "\n" " plugin autoclass\n" " 1: server\n" " 2: database\n") publish_doctree(text) from blockdiag import plugins self.assertEqual([], plugins.loaded_plugins) def test_setup_fontpath1(self): with self.assertRaises(RuntimeError): directives.setup(format='SVG', fontpath=['dummy.ttf'], outputdir=self.tmpdir) text = (".. packetdiag::\n" "\n" " 1: server\n" " 2: database\n") publish_doctree(text) def test_setup_fontpath2(self): with self.assertRaises(RuntimeError): directives.setup(format='SVG', fontpath='dummy.ttf', outputdir=self.tmpdir) text = (".. packetdiag::\n" "\n" " 1: server\n" " 2: database\n") publish_doctree(text) def test_setup_nodoctype_is_true(self): directives.setup(format='SVG', outputdir=self.tmpdir, nodoctype=True) text = (".. packetdiag::\n" "\n" " 1: server\n" " 2: database\n") doctree = publish_doctree(text) self.assertEqual(1, len(doctree)) self.assertEqual(nodes.image, type(doctree[-1])) svg = open(doctree[0]['uri']).read() self.assertNotEqual("\n" "\n" "\n" " 0: item = rack.nodes[-1] number = item.number + item.colheight else: number = 1 else: number = stmt.number item = RackItem(number, unquote(stmt.label)) item.set_attributes(stmt.attrs) rack.nodes.append(item) elif isinstance(stmt, parser.Rack): _rack = Rack() self.diagram.racks.append(_rack) self.instantiate(_rack, stmt) elif isinstance(stmt, parser.AttrPlugin): self.diagram.set_plugin(stmt.name, stmt.attrs) class DiagramLayoutManager: def __init__(self, diagram): self.diagram = diagram def run(self): x = 0 for rack in self.diagram.racks: self.layout_rack(rack) rack.xy = XY(x, 0) rack.fixiate() x += rack.colwidth self.diagram.fixiate() def layout_rack(self, rack): usage = defaultdict(bool) for item in rack.nodes: item.xy = XY(-1, -1) for item in rack.nodes: if rack.descending: y = rack.colheight - item.number - item.colheight + 1 else: y = item.number - 1 for x in range(255): r = range(y, y + item.colheight) if len([_ for _ in r if usage[(x, _)]]) == 0: break item.xy = XY(x, y) for dy in range(y, y + item.colheight): usage[(x, dy)] = 1 self.validate_rack(rack, item) def validate_rack(self, rack, item): if item.xy.y < 0: msg = "Rack %d is layouted to underground!\n" % item.number raise AttributeError(msg) elif rack.colheight < item.xy.y + item.colheight: msg = "Rack %d is oversized to rack-height\n" % item.number raise AttributeError(msg) class ScreenNodeBuilder: @classmethod def build(cls, tree): Rack.clear() RackItem.clear() Diagram.clear() return cls(tree).run() def __init__(self, tree): self.diagram = DiagramTreeBuilder().build(tree) def run(self): DiagramLayoutManager(self.diagram).run() return self.diagram nwdiag-1.0.4/src/rackdiag/command.py0000644000076600000240000000156212222145107020112 0ustar tkomiyastaff00000000000000# -*- coding: utf-8 -*- # Copyright 2011 Takeshi KOMIYA # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. import sys import rackdiag import rackdiag.builder import rackdiag.drawer import rackdiag.parser from blockdiag.utils.bootstrap import Application class RackdiagApp(Application): module = rackdiag def main(args=sys.argv[1:]): return RackdiagApp().run(args) nwdiag-1.0.4/src/rackdiag/drawer.py0000644000076600000240000000500312217202643017755 0ustar tkomiyastaff00000000000000# -*- coding: utf-8 -*- # Copyright 2011 Takeshi KOMIYA # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. import blockdiag.drawer from rackdiag.metrics import DiagramMetrics from blockdiag.utils import Box from blockdiag.utils.compat import u class DiagramDraw(blockdiag.drawer.DiagramDraw): def create_metrics(self, *args, **kwargs): return DiagramMetrics(*args, **kwargs) def _draw_elements(self, **kwargs): default_font = self.metrics.font_for(self.diagram) for rack in self.diagram.racks: frame = self.metrics.cell(rack, use_padding=False).box self.drawer.rectangle(frame, fill='white', outline=self.diagram.linecolor) for i in range(rack.colheight): box = self.metrics.racknumber(rack, i) number = u("%d") % (i + 1) self.drawer.textarea(box, number, default_font, halign='right', fill=self.diagram.textcolor) if rack.display_label: box = self.metrics.racklabel(rack) self.drawer.textarea(box, rack.display_label, self.metrics.font_for(rack), fill=rack.textcolor) super(DiagramDraw, self)._draw_elements(**kwargs) def _draw_background(self): # do not draw shadow of nodes on super() self.diagram.shadow_style = 'none' super(DiagramDraw, self)._draw_background() # draw shadow of frame dx, dy = self.metrics.shadow_offset for rack in self.diagram.racks: frame = self.metrics.cell(rack, use_padding=False) shadow = Box(frame.x1 + dx, frame.y1 + dy, frame.x2 + dx, frame.y2 + dy) self.drawer.rectangle(shadow, fill=self.shadow, filter='blur') def node(self, node, **kwargs): label, node.label = node.label, node.display_label super(DiagramDraw, self).node(node, **kwargs) node.label = label nwdiag-1.0.4/src/rackdiag/elements.py0000644000076600000240000001600012243053425020305 0ustar tkomiyastaff00000000000000# -*- coding: utf-8 -*- # Copyright 2011 Takeshi KOMIYA # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. from __future__ import division import re import blockdiag.elements from rackdiag.utils.math import lcm from blockdiag.utils import XY from blockdiag.utils.compat import u class DiagramNode(blockdiag.elements.DiagramNode): pass class RackItem(blockdiag.elements.DiagramNode): desctable = [] attrname = {} @classmethod def clear(cls): super(RackItem, cls).clear() cls.desctable = ['number', 'label', 'units', 'ampere', 'weight', 'description'] cls.attrname = dict(number='No', label='Name', units='Height', ampere='Capacity', weight='Weight', description='Description') def __init__(self, number, label): super(RackItem, self).__init__(None) self.number = int(number) self.label = label self.ampere = None self.weight = None if self.label == 'N/A': self.color = 'gray' @property def display_label(self): attrs = [] if self.colheight > 1: attrs.append(u("%dU") % self.colheight) if self.ampere: attrs.append(u("%.1fA") % self.ampere) if self.weight: attrs.append(u("%.1fkg") % self.weight) labels = [] if self.label: labels.append(self.label) if attrs: labels.append(u("[%s]") % u("/").join(attrs)) return u("\n").join(labels) def set_attribute(self, attr): if re.search('^\d+U$', attr.name): self.colheight = int(attr.name[:-1]) elif re.search('^\d+(\.[0-9]+)?A$', attr.name): self.ampere = float(attr.name[:-1]) elif re.search('^\d+(\.[0-9]+)?kg$', attr.name): self.weight = float(attr.name[:-2]) else: return super(RackItem, self).set_attribute(attr) def set_height(self, value): self.colheight = int(value) def to_desctable(self): attrs = [] for name in self.desctable: if name == 'units': attrs.append(u("%dU") % self.colheight) elif name == 'ampere': if self.ampere is None: attrs.append(u("")) else: attrs.append((u("%.1fA") % self.ampere) or u("")) elif name == 'weight': if self.weight is None: attrs.append(u("")) else: attrs.append((u("%.1fkg") % self.weight) or u("")) else: value = getattr(self, name) if value is None: attrs.append(u("")) elif isinstance(value, int): attrs.append(str(value)) else: attrs.append(getattr(self, name)) return attrs class Rack(blockdiag.elements.NodeGroup): def __init__(self): super(Rack, self).__init__(None) self.colheight = 42 self.description = None self.descending = True def set_default_fontsize(self, value): raise AttributeError() # Ignore and pass-through to Diagram @property def display_label(self): attrs = [] if self.description or attrs: attrs.insert(0, u("%dU") % self.colheight) labels = [] if self.description: labels.append(self.description) if attrs: labels.append(u("[%s]") % u("/").join(attrs)) return u("\n").join(labels) def items(self, levels): if isinstance(levels, int): levels = [levels] return [node for node in self.nodes if node.xy.y in levels] def get_linked_levels(self, level): def get_max_height(self, y): try: return max(n.colheight for n in self.items(y)) except: return 0 height = get_max_height(self, level) for dy in range(1, self.colheight - level + 1): if dy < height: height = max(height, get_max_height(self, level + dy) + dy) return range(level, level + height) def adjust_node_widths(self): i = 0 linked_widths = {} widths = [] while i < self.colheight: levels = self.get_linked_levels(i) if levels: linked_widths[i] = [] for level in levels: nodes = self.items(level) if nodes: width = max(n.xy.x for n in nodes) + 1 widths.append(width) linked_widths[i].append(width) i += len(levels) else: i += 1 i = 0 self.colwidth = lcm(*widths) or 1 while i < self.colheight: levels = self.get_linked_levels(i) if levels: colwidth = max(linked_widths[i]) or 1 for level in levels: nodes = self.items(level) if nodes: width = self.colwidth // colwidth for node in nodes: node.xy = XY(node.xy.x * width, node.xy.y) node.colwidth = width i += len(levels) else: i += 1 def fixiate(self): self.adjust_node_widths() for node in self.nodes: node.xy = node.xy.shift(x=self.xy.x) def set_ascending(self, attr): self.descending = False def set_attribute(self, attr): if re.search('^\d+U$', attr.name): self.colheight = int(attr.name[:-1]) else: return super(Rack, self).set_attribute(attr) class Diagram(blockdiag.elements.Diagram): _DiagramNode = RackItem @classmethod def clear(cls): super(Diagram, cls).clear() cls._DiagramNode.clear() def __init__(self): super(Diagram, self).__init__() self.racks = [Rack()] def set_default_fontsize(self, value): super(Diagram, self).set_default_fontsize(value) self.fontsize = int(value) def set_rackheight(self, value): self.racks[0].colheight = int(value) def fixiate(self): self.colwidth = sum(r.colwidth for r in self.racks) self.colheight = max(r.colheight for r in self.racks) def traverse_nodes(self, **kwargs): for rack in self.racks: for node in rack.traverse_nodes(): yield node nwdiag-1.0.4/src/rackdiag/metrics.py0000644000076600000240000000521612217202643020145 0ustar tkomiyastaff00000000000000# -*- coding: utf-8 -*- # Copyright 2011 Takeshi KOMIYA # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. from __future__ import division from collections import defaultdict import blockdiag.metrics from blockdiag.utils import Box, XY from rackdiag import elements class DiagramMetrics(blockdiag.metrics.DiagramMetrics): def __init__(self, diagram, **kwargs): span_height = self.span_height span_width = self.span_width self.span_height = 0 self.span_width = 0 super(DiagramMetrics, self).__init__(diagram, **kwargs) labelsize = [self.textsize(r.display_label, font=self.font_for(r)) for r in diagram.racks if r.display_label] if labelsize: labelheight = (max(size.height for size in labelsize) + self.line_spacing * 2) else: labelheight = 0 # reset node_width FORCE self.spreadsheet.node_width = defaultdict(lambda: self.node_width) self.spreadsheet.set_span_height(0, span_height + labelheight) self.spreadsheet.set_span_height(diagram.colheight, span_height) self.spreadsheet.set_span_width(0, span_width) for rack in diagram.racks: x = rack.xy.x + rack.colwidth self.spreadsheet.set_span_width(x, span_width) if rack.colwidth > 1: node_width = self.node_width // rack.colwidth for i in range(rack.colwidth): self.spreadsheet.set_node_width(rack.xy.x + i, node_width) def racklabel(self, rack): cell = self.cell(rack) textsize = self.textsize(rack.display_label, font=self.font_for(rack)) y1 = cell.y1 - textsize.height - self.line_spacing * 2 return Box(cell.x1, y1, cell.x2, cell.y1) def racknumber(self, rack, number): if rack.descending: y = rack.colheight - number - 1 else: y = number dummy = elements.DiagramNode(None) dummy.xy = XY(rack.xy.x, y) dummy.colwidth = 1 dummy.colheight = 1 box = self.cell(dummy, use_padding=False).box return Box(0, box[1], box[0], box[3]) nwdiag-1.0.4/src/rackdiag/parser.py0000644000076600000240000001746312355700715020010 0ustar tkomiyastaff00000000000000# -*- coding: utf-8 -*- # Copyright (c) 2008/2009 Andrey Vlasovskikh # # 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. r'''A DOT language parser using funcparserlib. The parser is based on [the DOT grammar][1]. It is pretty complete with a few not supported things: * Ports and compass points * XML identifiers At the moment, the parser builds only a parse tree, not an abstract syntax tree (AST) or an API for dealing with DOT. [1]: http://www.graphviz.org/doc/info/lang.html ''' import io from re import MULTILINE, DOTALL from collections import namedtuple from funcparserlib.lexer import make_tokenizer, Token, LexerError from funcparserlib.parser import (some, a, maybe, many, finished, skip) from blockdiag.parser import create_mapper, oneplus_to_list from blockdiag.utils.compat import u Diagram = namedtuple('Diagram', 'id stmts') RackItem = namedtuple('RackItem', 'number label attrs') Attr = namedtuple('Attr', 'name value') Rack = namedtuple('Rack', 'id stmts') Extension = namedtuple('Extension', 'type name attrs') class ParseException(Exception): pass def tokenize(string): """str -> Sequence(Token)""" # flake8: NOQA specs = [ # NOQA ('Comment', (r'/\*(.|[\r\n])*?\*/', MULTILINE)), # NOQA ('Comment', (r'(//|#).*',)), # NOQA ('NL', (r'[\r\n]+',)), # NOQA ('QuotedRackItem', (r'(?<=[:*\-])\s*(?P"|\').*?(?"|\').*?(? object""" id_tokens = ['Name', 'Number', 'String', 'RackHeight', 'Units'] rackitem_tokens = ['QuotedRackItem', 'RackItem'] tokval = lambda x: x.value op = lambda s: a(Token('Op', s)) >> tokval op_ = lambda s: skip(op(s)) _id = some(lambda t: t.type in id_tokens) >> tokval keyword = lambda s: a(Token('Name', s)) >> tokval rackheight = some(lambda t: t.type == 'RackHeight') >> tokval number = some(lambda t: t.type == 'Number').named('number') >> tokval rackitem = some(lambda t: t.type in rackitem_tokens) >> tokval def make_num_rackitem(num, text, attr): return RackItem(num, text.strip(), attr) def make_nonnum_rackitem(text, attr): return RackItem(None, text.strip(), attr) def make_nonvalued_attr(rackheight): return Attr(rackheight, None) # # parts of syntax # option_stmt = ( _id + maybe(op_('=') + _id) >> create_mapper(Attr) ) option_list = ( maybe(op_('[') + option_stmt + many(op_(',') + option_stmt) + op_(']')) >> create_mapper(oneplus_to_list, default_value=[]) ) # attributes statement:: # default_shape = box; # default_fontsize = 16; # 12U; # ascending; # attribute_stmt = ( _id + op_('=') + _id >> create_mapper(Attr) ) rackheight_stmt = ( rackheight >> make_nonvalued_attr ) ascending_stmt = ( keyword('ascending') >> make_nonvalued_attr ) # field statement:: # 1: A # 2: B [attr = value, attr = value]; # * C [attr = value, attr = value]; # * D [attr = value, attr = value]; # numbered_field_item_stmt = ( number + op_(':') + rackitem + option_list >> create_mapper(make_num_rackitem) ) nonnumbered_field_item_stmt = ( (op_('-') | op_('*')) + rackitem + option_list >> create_mapper(make_nonnum_rackitem) ) field_item_stmt = ( numbered_field_item_stmt | nonnumbered_field_item_stmt ) # rack statement:: # rack { # 1: A; # } # # rack definition rack_inline_stmt = ( attribute_stmt | rackheight_stmt | field_item_stmt ) rack_inline_stmt_list = ( many(rack_inline_stmt + skip(maybe(op(';')))) ) rack_stmt = ( skip(keyword('rack')) + maybe(_id) + op_('{') + rack_inline_stmt_list + op_('}') >> create_mapper(Rack) ) # extension statement (plugin):: # plugin attributes [name = Name]; # extension_stmt = ( keyword('plugin') + _id + option_list >> create_mapper(Extension) ) # # diagram statement:: # rackdiag { # A; # } # diagram_id = ( (keyword('diagram') | keyword('rackdiag')) + maybe(_id) >> list ) diagram_inline_stmt = ( ascending_stmt | extension_stmt | rack_stmt | field_item_stmt | attribute_stmt | rackheight_stmt ) diagram_inline_stmt_list = ( many(diagram_inline_stmt + skip(maybe(op(';')))) ) diagram = ( maybe(diagram_id) + op_('{') + diagram_inline_stmt_list + op_('}') >> create_mapper(Diagram) ) dotfile = diagram + skip(finished) return dotfile.parse(seq) def sort_tree(tree): def weight(node): if isinstance(node, (Attr, Extension)): return 1 else: return 2 if hasattr(tree, 'stmts'): tree.stmts.sort(key=lambda x: weight(x)) for stmt in tree.stmts: sort_tree(stmt) return tree def parse_string(string): try: tree = parse(tokenize(string)) return sort_tree(tree) except LexerError as e: message = "Got unexpected token at line %d column %d" % e.place raise ParseException(message) except Exception as e: raise ParseException(str(e)) def parse_file(path): code = io.open(path, 'r', encoding='utf-8-sig').read() return parse_string(code) nwdiag-1.0.4/src/rackdiag/tests/0000755000076600000240000000000012451257704017273 5ustar tkomiyastaff00000000000000nwdiag-1.0.4/src/rackdiag/tests/diagrams/0000755000076600000240000000000012451257704021062 5ustar tkomiyastaff00000000000000nwdiag-1.0.4/src/rackdiag/tests/diagrams/ascending.diag0000644000076600000240000000011112355456500023632 0ustar tkomiyastaff00000000000000{ ascending 1: server 1 2: server 2 3: server 3 4: server 4 } nwdiag-1.0.4/src/rackdiag/tests/diagrams/autonumber.diag0000644000076600000240000000007612052635113024063 0ustar tkomiyastaff00000000000000{ * server 1 * server 2 * server 3 [2U]; * server 4 } nwdiag-1.0.4/src/rackdiag/tests/diagrams/multi_rackitem.diag0000644000076600000240000000033512112061031024676 0ustar tkomiyastaff00000000000000{ rackheight = 12; 1: UPS 1[3U]; 1: UPS 2[3U]; 4: server 1; 4: server 2 [2U]; 5: server 3 [2U]; 6: server 4 [2U]; 6: server 5 [2U]; 6: server 6 [2U]; 8: server 7 [3U]; 9: server 8; 9: server 9; } nwdiag-1.0.4/src/rackdiag/tests/diagrams/multi_racks.diag0000644000076600000240000000023712112061031024203 0ustar tkomiyastaff00000000000000{ rack { * server 1; * server 2; * server 3; * server 4; } rack { * server 5; * server 6; * server 7; * server 8; } } nwdiag-1.0.4/src/rackdiag/tests/diagrams/oneliner.diag0000644000076600000240000000007012355217265023521 0ustar tkomiyastaff00000000000000{ 1: server 1; 2: server 2; 3: server 3; 4: server 4; } nwdiag-1.0.4/src/rackdiag/tests/diagrams/oneliner_with_quoted.diag0000644000076600000240000000007212355217265026137 0ustar tkomiyastaff00000000000000{ 1: server 1; 2: server 2; 3: server 3; 4: "server 4}" } nwdiag-1.0.4/src/rackdiag/tests/diagrams/oneliner_without_last_semicolon.diag0000644000076600000240000000006712355217265030405 0ustar tkomiyastaff00000000000000{ 1: server 1; 2: server 2; 3: server 3; 4: server 4 } nwdiag-1.0.4/src/rackdiag/tests/diagrams/rack_height.diag0000644000076600000240000000010412355217342024150 0ustar tkomiyastaff00000000000000{ 16U; 1: server 1 2: server 2 3: server 3 4: server 4 } nwdiag-1.0.4/src/rackdiag/tests/diagrams/rack_height_for_multi_racks.diag0000644000076600000240000000026212355225763027426 0ustar tkomiyastaff00000000000000{ rack { 8U; * server 1; * server 2; * server 3; * server 4; } rack { 12U; * server 5; * server 6; * server 7; * server 8; } } nwdiag-1.0.4/src/rackdiag/tests/diagrams/simple.diag0000644000076600000240000000007412036770551023201 0ustar tkomiyastaff00000000000000{ 1: server 1 2: server 2 3: server 3 4: server 4 } nwdiag-1.0.4/src/rackdiag/tests/test_builder.py0000644000076600000240000000527412217202643022332 0ustar tkomiyastaff00000000000000# -*- coding: utf-8 -*- from __future__ import print_function import sys if sys.version_info < (2, 7): import unittest2 as unittest else: import unittest import os from rackdiag.builder import ScreenNodeBuilder from rackdiag.parser import parse_string def build(filename): def decorator(fn): def func(self): testdir = os.path.dirname(__file__) pathname = os.path.join(testdir, 'diagrams', filename) code = open(pathname).read() tree = parse_string(code) self.diagram = ScreenNodeBuilder.build(tree) return fn(self) func.__name__ = fn.__name__ return func return decorator class TestBuildDiagram(unittest.TestCase): def assertAttributes(self, **attributes): for rack in self.diagram.racks: for node in rack.nodes: print(node, node.label) for key, attribute in attributes.items(): value = attribute.get(node.label) self.assertEqual(value, getattr(node, key)) @build('simple.diag') def test_simple(self): positions = {'server 1': (0, 41), 'server 2': (0, 40), 'server 3': (0, 39), 'server 4': (0, 38)} self.assertAttributes(xy=positions) @build('autonumber.diag') def test_autonumber(self): positions = {'server 1': (0, 41), 'server 2': (0, 40), 'server 3': (0, 38), 'server 4': (0, 37)} self.assertAttributes(xy=positions) @build('multi_rackitem.diag') def test_multi_rackitem(self): positions = {'UPS 1': (0, 9), 'UPS 2': (6, 9), 'server 1': (0, 8), 'server 2': (3, 7), 'server 3': (0, 6), 'server 4': (3, 5), 'server 5': (6, 5), 'server 6': (9, 5), 'server 7': (0, 2), 'server 8': (4, 3), 'server 9': (8, 3)} colheights = {'UPS 1': 3, 'UPS 2': 3, 'server 1': 1, 'server 2': 2, 'server 3': 2, 'server 4': 2, 'server 5': 2, 'server 6': 2, 'server 7': 3, 'server 8': 1, 'server 9': 1} self.assertAttributes(xy=positions, colheight=colheights) @build('multi_racks.diag') def test_multi_racks(self): positions = {'server 1': (0, 41), 'server 2': (0, 40), 'server 3': (0, 39), 'server 4': (0, 38), 'server 5': (1, 41), 'server 6': (1, 40), 'server 7': (1, 39), 'server 8': (1, 38)} self.assertAttributes(xy=positions) nwdiag-1.0.4/src/rackdiag/tests/test_generate_diagram.py0000644000076600000240000000063512236360400024153 0ustar tkomiyastaff00000000000000# -*- coding: utf-8 -*- import os import rackdiag.command from blockdiag.tests.test_generate_diagram import ( get_diagram_files, testcase_generator ) def test_generate(): mainfunc = rackdiag.command.main basepath = os.path.dirname(__file__) files = get_diagram_files(basepath) options = [] for testcase in testcase_generator(basepath, mainfunc, files, options): yield testcase nwdiag-1.0.4/src/rackdiag/tests/test_pep8.py0000644000076600000240000000324712355217265021567 0ustar tkomiyastaff00000000000000# -*- coding: utf-8 -*- from __future__ import print_function import os import sys import pep8 CURRENT_DIR = os.path.dirname(os.path.abspath(__file__)) BASE_DIR = os.path.dirname(CURRENT_DIR) def test_pep8(): arglist = [['statistics', True], ['show-source', True], ['repeat', True], ['paths', [BASE_DIR]]] pep8style = pep8.StyleGuide(arglist, parse_argv=False, config_file=True) options = pep8style.options if options.doctest: import doctest fail_d, done_d = doctest.testmod(report=False, verbose=options.verbose) fail_s, done_s = pep8.selftest(options) count_failed = fail_s + fail_d if not options.quiet: count_passed = done_d + done_s - count_failed print("%d passed and %d failed." % (count_passed, count_failed)) if count_failed: print("Test failed.") else: print("Test passed.") if count_failed: sys.exit(1) if options.testsuite: pep8.init_tests(pep8style) report = pep8style.check_files() if options.statistics: report.print_statistics() if options.benchmark: report.print_benchmark() if options.testsuite and not options.quiet: report.print_results() if report.total_errors: if options.count: sys.stderr.write(str(report.total_errors) + '\n') # sys.exit(1) # reporting errors (additional summary) errors = report.get_count('E') warnings = report.get_count('W') message = 'pep8: %d errors / %d warnings' % (errors, warnings) print(message) assert report.total_errors == 0, message nwdiag-1.0.4/src/rackdiag/tests/test_rst_directives.py0000644000076600000240000007256612433562723023755 0ustar tkomiyastaff00000000000000# -*- coding: utf-8 -*- import sys if sys.version_info < (2, 7): import unittest2 as unittest else: import unittest import os from blockdiag.tests.utils import capture_stderr, with_pil, TemporaryDirectory from docutils import nodes from docutils.core import publish_doctree from docutils.parsers.rst import directives as docutils from rackdiag.utils.rst import directives from blockdiag.utils.compat import u class TestRstDirectives(unittest.TestCase): def setUp(self): self._tmpdir = TemporaryDirectory() def tearDown(self): if 'rackdiag' in docutils._directives: del docutils._directives['rackdiag'] self._tmpdir.clean() @property def tmpdir(self): return self._tmpdir.name def test_setup(self): directives.setup() options = directives.directive_options self.assertIn('rackdiag', docutils._directives) self.assertEqual(directives.RackdiagDirective, docutils._directives['rackdiag']) self.assertEqual('PNG', options['format']) self.assertEqual(False, options['antialias']) self.assertEqual(None, options['fontpath']) self.assertEqual(False, options['nodoctype']) self.assertEqual(False, options['noviewbox']) self.assertEqual(False, options['inline_svg']) def test_setup_with_args(self): directives.setup(format='SVG', antialias=True, fontpath='/dev/null', nodoctype=True, noviewbox=True, inline_svg=True) options = directives.directive_options self.assertIn('rackdiag', docutils._directives) self.assertEqual(directives.RackdiagDirective, docutils._directives['rackdiag']) self.assertEqual('SVG', options['format']) self.assertEqual(True, options['antialias']) self.assertEqual('/dev/null', options['fontpath']) self.assertEqual(True, options['nodoctype']) self.assertEqual(True, options['noviewbox']) self.assertEqual(True, options['inline_svg']) @capture_stderr def test_cleanup(self): directives.setup(format='SVG', outputdir=self.tmpdir, noviewbox=False) text = (".. rackdiag::\n" "\n" " plugin autoclass\n" " 1: server\n" " 2: database\n") publish_doctree(text) from blockdiag import plugins self.assertEqual([], plugins.loaded_plugins) def test_setup_fontpath1(self): with self.assertRaises(RuntimeError): directives.setup(format='SVG', fontpath=['dummy.ttf'], outputdir=self.tmpdir) text = (".. rackdiag::\n" "\n" " 1: server\n" " 2: database\n") publish_doctree(text) def test_setup_fontpath2(self): with self.assertRaises(RuntimeError): directives.setup(format='SVG', fontpath='dummy.ttf', outputdir=self.tmpdir) text = (".. rackdiag::\n" "\n" " 1: server\n" " 2: database\n") publish_doctree(text) def test_setup_nodoctype_is_true(self): directives.setup(format='SVG', outputdir=self.tmpdir, nodoctype=True) text = (".. rackdiag::\n" "\n" " 1: server\n" " 2: database\n") doctree = publish_doctree(text) self.assertEqual(1, len(doctree)) self.assertEqual(nodes.image, type(doctree[-1])) svg = open(doctree[0]['uri']).read() self.assertNotEqual("\n" "\n" "\n" "