ws_main.py revision a41bd98b
1#! /usr/bin/env python
2# encoding: utf-8
3# hhaim, 2014 (IL) base on WAF book
4
5"""
6call 'waf --targets=waf.pdf' or use 'waf list' to see the targets available
7"""
8
9VERSION='0.0.1'
10APPNAME='wafdocs'
11
12import os, re, shutil
13import sys
14import shlex
15import subprocess
16import json
17import re
18from waflib import Logs
19
20
21top = '.'
22out = 'build'
23sphinx_version = None
24
25try:
26    from HTMLParser import HTMLParser
27except:
28    from html.parser import HTMLParser
29
30class CTocNode:
31    def __init__ (self):
32        self.name="root"
33        self.level=1; # 1,2,3,4
34        self.link=None;
35        self.parent=None
36        self.childs=[]; # link to CTocNode
37
38    def get_link (self):
39        if self.link==None:
40            name=self.name
41            l=name.split('.');
42            l=l[-1].lower()
43            s='';
44            for c in l:
45                if c.isalpha() or c.isspace():
46                    s+=c
47
48            return  '#_'+'_'.join(s.lower().split());
49        else:
50            return '#'+self.link
51
52
53
54    def add_new_child (self,name,level,link):
55        n=CTocNode();
56        n.name=name;
57        n.link=link
58        n.level=level;
59        n.parent=self;
60        self.childs.append(n);
61        return n
62
63    def to_json_childs (self):
64        l=[]
65        for obj in self.childs:
66            l.append(obj.to_json());
67        return (l);
68
69    def to_open (self):
70        if self.level <3:
71            return True
72        else:
73            return False
74
75
76    def to_json (self):
77        d={"text" : self.name,
78           "link" : self.get_link(),
79           "state"       : {
80                "opened"    : self.to_open()
81                }
82          }
83        if len(self.childs)>0 :
84            d["children"]= self.to_json_childs()
85        return d
86
87
88
89class TocHTMLParser(HTMLParser):
90
91    def __init__ (self):
92        HTMLParser.__init__(self);
93        self.state=0;
94        self.root=CTocNode()
95        self.root.parent=self.root
96        self.level=2;
97        self.attrs=None
98        self.d={};
99        self.last_level=1
100        self.set_level(1,self.root)
101
102
103    def set_level (self,level,node):
104        assert(node!=None);
105        assert(isinstance(node,CTocNode)==True);
106        self.d[str(level)]=node
107
108        # in case we change from high to low level remove the higher level
109        if level<self.last_level:
110            for l in range(level+1,self.last_level+1):
111                self.d.pop(str(l),None)
112
113
114
115    def _get_level (self,level):
116        k=str(level)
117        if k in self.d:
118            n=self.d[k]
119            assert(n!=None);
120            return n
121        else:
122            return None
123
124    def get_level (self,level):
125        for l in range(level,0,-1):
126            n=self._get_level(l)
127            if n != None:
128                return n
129        assert(0);
130
131
132    def is_header (self,tag):
133        if len(tag)==2 and tag[0]=='h' and tag[1].isdigit() and (int(tag[1])>1):
134            return (True);
135
136    def handle_starttag(self, tag, attrs):
137        if self.is_header (tag):
138            self.attrs=attrs
139            self.state=True;
140            self.level=int(tag[1]);
141
142    def handle_endtag(self, tag):
143        if self.is_header (tag):
144            self.state=False;
145
146    def get_id (self):
147        if self.attrs:
148            for obj in self.attrs:
149                if obj[0]=='id':
150                    return obj[1]
151        else:
152            return None
153
154
155    def handle_data(self, data):
156        if self.state:
157
158           level=self.level
159
160           cnode=self.get_level(level-1)
161
162           n=cnode.add_new_child(data,level,self.get_id());
163           assert(n!=None);
164           self.set_level(level,n)
165           self.last_level=level
166
167    def dump_as_json (self):
168        return json.dumps(self.root.to_json_childs(), sort_keys=False, indent=4)
169
170
171
172
173def create_toc_json (input_file,output_file):
174    f = open (input_file)
175    l=f.readlines()
176    f.close();
177    html_input = ''.join(l)
178    parser = TocHTMLParser()
179    parser.feed(html_input);
180    f = open (output_file,'w')
181    f.write(parser.dump_as_json());
182    f.close();
183
184
185
186
187re_xi = re.compile('''^(include|image)::([^.]*.(asciidoc|\\{PIC\\}))\[''', re.M)
188def ascii_doc_scan(self):
189    p = self.inputs[0].parent
190    node_lst = [self.inputs[0]]
191    seen = []
192    depnodes = []
193    while node_lst:
194        nd = node_lst.pop(0)
195        if nd in seen: continue
196        seen.append(nd)
197
198        code = nd.read()
199        for m in re_xi.finditer(code):
200            name = m.group(2)
201            if m.group(3) == '{PIC}':
202
203                ext = '.eps'
204                if self.generator.rule.rfind('A2X') > 0:
205                    ext = '.png'
206
207                k = p.find_resource(name.replace('{PIC}', ext))
208                if k:
209                    depnodes.append(k)
210            else:
211                k = p.find_resource(name)
212                if k:
213                    depnodes.append(k)
214                    node_lst.append(k)
215    return [depnodes, ()]
216
217
218
219def scansize(self):
220    name = 'image::%s\\{PIC\\}\\[.*,(width|height)=(\\d+)' % self.inputs[0].name[:-4]
221    re_src = re.compile(name)
222    lst = self.inputs[0].parent.get_src().ant_glob('*.txt')
223    for x in lst:
224        m = re_src.search(x.read())
225        if m:
226            val = str(int(1.6 * int(m.group(2))))
227            if m.group(1) == 'width':
228                w = val
229                h = "800"
230            else:
231                w = "800"
232                h = val
233
234            ext = self.inputs[0].name[-3:]
235            if ext == 'eps':
236                code = '-geometry %sx%s' % (w, h)
237            elif ext == 'dia':
238                if m.group(1) == 'width':
239                    h = ''
240                else:
241                    w = ''
242                code = '--size %sx%s' % (w, h)
243            else:
244                code = '-Gsize="%s,%s"' % (w, h)
245            break
246    else:
247        return ([], '')
248
249    return ([], code)
250
251def options(opt):
252    opt.add_option('--exe', action='store_true', default=False, help='Execute the program after it is compiled')
253    opt.add_option('--performance', action='store_true', help='Build a performance report based on google analytics')
254
255def configure(conf):
256    search_path = '~/.local/bin /usr/local/bin/ /usr/bin'
257    conf.find_program('asciidoc', path_list=search_path, var='ASCIIDOC')
258    conf.find_program('sphinx-build', path_list=search_path, var='SPHINX')
259    conf.find_program('source-highlight', path_list=search_path, var='SRC_HIGHLIGHT')
260    conf.find_program('dblatex', path_list=search_path, var='DBLATEX')
261    conf.find_program('a2x', path_list=search_path, var='A2X')
262    pass;
263
264def convert_to_pdf(task):
265    input_file = task.outputs[0].abspath()
266    out_dir = task.outputs[0].parent.get_bld().abspath()
267    return  os.system('a2x --no-xmllint %s -f pdf  -d  article %s -D %s ' %('-v' if Log.verbose else '', task.inputs[0].abspath(),out_dir ) )
268
269
270TOC_HEAD = """
271
272<body class="book">
273<div id="toc-section">
274        <div id="toctitle">
275            <img class="trex_logo" src="images/trex_logo_toc.png"/>
276            Table of Contents
277        </div>
278
279        <div id="toggle">
280          <img src="images/icons/toggle.png" title="click to toggle table of contents"/>
281        </div>
282
283        <div id="toc">
284          <div id="nav-tree">
285
286          </div>
287        </div>
288</div>
289
290<div id="content-section">
291
292    <!-- load the theme CSS file -->
293    <link href="https://cdnjs.cloudflare.com/ajax/libs/jstree/3.2.1/themes/default/style.min.css" rel="stylesheet"/>
294
295    <link href="https://code.jquery.com/ui/1.9.2/themes/base/jquery-ui.css" rel="stylesheet" />
296
297    <!-- include the jQuery library -->
298    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.12.1/jquery.min.js">
299    </script>
300
301    <!-- include the jQuery UI library -->
302    <script src="https://cdnjs.cloudflare.com/ajax/libs/jqueryui/1.11.4/jquery-ui.min.js">
303    </script>
304
305    <!-- include the minified jstree source -->
306    <script src="https://cdnjs.cloudflare.com/ajax/libs/jstree/3.2.1/jstree.min.js">
307    </script>
308
309    <!-- Hide TOC on mobile -->
310    <script>
311
312      // Hide TOC when it is mobile
313      checkMobile();
314
315      // Hide TOC by default if it is mobile
316      function checkMobile(){
317        if(isMobileDevice()){
318          hideTOC();
319        }
320      }
321
322      // Check it it it is running on mobile device
323      function isMobileDevice() {
324          if(
325              navigator.userAgent.match(/Android/i) ||
326              navigator.userAgent.match(/BlackBerry/i) ||
327              navigator.userAgent.match(/iPhone|iPad|iPod/i) ||
328              navigator.userAgent.match(/Opera Mini/i) ||
329              navigator.userAgent.match(/IEMobile/i) ||
330              navigator.userAgent.match(/iPhone|iPad|iPod/i)
331            )
332          {
333            return true;
334          }
335          else
336          {
337            return false;
338          }
339      }
340
341      // Hide TOC - for the first time in mobile
342      function hideTOC(){
343          $("#toc").hide();
344          $("#toctitle").hide();
345          // Show the show/hide button
346          $("#toggle").css("right", "-40px");
347          // Fil width
348          $("body").css("margin-left", "50px");
349      }
350
351    </script>
352
353  <div id="content-section-inner">
354
355"""
356
357TOC_END = """
358
359  </div>
360  <!-- End Of Inner Content Section -->
361</div>
362<!-- End of Content Section -->
363
364</body>
365
366<style type="text/css">
367    #toc {
368      margin-bottom: 2.5em;
369    }
370
371    #toctitle {
372      color: #527bbd;
373      font-size: 1.1em;
374      font-weight: bold;
375      margin-top: 1.0em;
376      margin-bottom: 0.1em;
377    }
378
379    @media screen {
380      body {
381        margin-left: 20em;
382      }
383
384      #toc {
385        position: fixed;
386        top: 51px;
387        left: 0;
388        bottom: 0;
389        width: 18em;
390        padding-bottom: 1.5em;
391        margin: 0;
392        overflow-x: auto !important;
393        overflow-y: auto !important;
394        border-right: solid 2px #cfcfcf;
395        background-color: #FAFAFA;
396        white-space: nowrap;
397      }
398
399      #toctitle {
400        font-size: 17px !important;
401        color: #4d4d4d !important;
402        margin-top: 0px;
403        height: 36px;
404        line-height: 36px;
405        background-color: #e4e2e2;
406        padding: 8px 0px 7px 45px;
407        white-space: nowrap;
408        left: 0px;
409        display: block;
410        position: fixed;
411        z-index: 100;
412        width: 245px;
413        top: 0px;
414        overflow: hidden;
415      }
416
417      #toc .toclevel1 {
418        margin-top: 0.5em;
419      }
420
421      #toc .toclevel2 {
422        margin-top: 0.25em;
423        display: list-item;
424        color: #aaaaaa;
425      }
426
427    }
428
429
430  /* Custom for Nave Tree */
431  #nav-tree{
432    margin-left: 10px !important;
433  }
434
435  #nav-tree ul > li {
436    color: #000 !important;
437  }
438
439  .jstree-wholerow.jstree-wholerow-clicked {
440    background-image: url('images/icons/selected_tab_bg.png');
441    background-repeat: repeat-x;
442    color: #fff !important;
443    text-shadow: 0px 1px 1px rgba(0, 0, 0, 1.0);
444  }
445
446        /* For side bar */
447  .ui-resizable-e{
448    height: 100%;
449    width: 4px !important;
450    position: fixed !important;
451    top: 0px !important;
452    cursor: e-resize !important;
453    background: url('images/splitbar.png') repeat scroll right center transparent !important;
454  }
455
456  .jstree-default .jstree-themeicon{
457    display: none !important;
458  }
459
460
461  .jstree-anchor {
462    font-size: 12px !important;
463    color: #91A501 !important;
464  }
465
466
467  .jstree-clicked{
468    color: white !important;
469  }
470
471
472  #toggle {
473    position: fixed;
474    top: 14px;
475    left: 10px;
476    z-index: 210;
477    width: 24px;
478  }
479
480  #toggle img {
481    opacity:0.3;
482  }
483
484  #toggle img:hover {
485    opacity:0.9;
486  }
487
488  .trex_logo{
489    top: 6px;
490    position: relative;
491  }
492
493   html{
494    overflow: hidden;
495  }
496
497  body{
498    margin-right: 0px !important;
499    margin-top: 0px !important;
500    margin-bottom: 0px !important;
501  }
502
503  #toc-section{
504    position: absolute;
505    z-index: 200;
506  }
507
508  #content-section{
509    overflow: auto;
510  }
511
512  #content-section-inner{
513    max-width: 50em;
514  }
515
516
517 </style>
518
519
520
521<script>
522
523      $(document).ready(function(){
524          var isOpen = true;
525
526        // Initialize NavTree
527        initializeNavTree();
528        // Drag TOC left and right
529        initResizable();
530        // Toggle TOC whe clicking on the menu icon
531        toggleTOC();
532        // Handle Mobile - close TOC
533        checkMobile();
534
535        function initializeNavTree() {
536
537          // TOC tree options
538          var toc_tree = $('#nav-tree');
539
540          var toc_tree_options = {
541            'core' : {
542              "animation" :false,
543              "themes" : { "stripes" : false },
544              'data' : {
545                "url" : "./input_replace_me.json",
546                "dataType" : "json" // needed only if you do not supply JSON headers
547              }
548            }
549            ,
550            "plugins" : [ "wholerow" ]
551          };
552
553          $('#nav-tree').jstree(toc_tree_options) ;
554
555          toc_tree.on("changed.jstree", function (e, data) {
556            window.location.href = data.instance.get_selected(true)[0].original.link;
557          });
558        }
559
560        function initResizable() {
561          var toc = $("#toc");
562          var body = $("body");
563
564          // On resize
565          $("#toc").resizable({
566              resize: function(e, ui) {
567                  resized();
568              },
569              handles: 'e'
570          });
571
572        // On zoom changed
573          $(window).resize(function() {
574            if(isOpen){
575                resized();
576            }
577          });
578
579
580         // Do it for the first time
581            var tocWidth = $(toc).outerWidth();
582            var windowHeight = $(window).height();
583            $(".ui-resizable-e").css({"right":$(window).width()-parseInt(tocWidth)+"px"});
584            $("#toctitle").css({"width":parseInt(tocWidth)-45+"px"});
585            $("#toc-section").css({"height":windowHeight + "px"});
586            $("#content-section").css({"height":windowHeight + "px"});
587
588        }
589
590        function resized(){
591          var body = $("body");
592          var tocWidth = $(toc).outerWidth();
593          var windowHeight = $(window).height();
594
595          body.css({"marginLeft":parseInt(tocWidth)+20+"px"});
596          $(".ui-resizable-e").css({"right":$(window).width()-parseInt(tocWidth)+"px"});
597          $("#toctitle").css({"width":parseInt(tocWidth)-45+"px"});
598          $("#toc-section").css({"height":windowHeight + "px"});
599          $("#content-section").css({"height":windowHeight + "px"});
600
601        }
602
603
604        function toggleTOC(){
605          $( "#toggle" ).click(function() {
606            if ( isOpen ) {
607              // Close it
608               closTOC();
609            } else {
610              // Open it
611              openTOC();
612            }
613            // Toggle status
614            isOpen = !isOpen;
615          });
616        }
617
618
619        // Close TOC by default if it is mobile
620        function checkMobile(){
621          if(isMobileDevice()){
622            isOpen=false;
623            $(".ui-resizable-e").hide();
624          }
625        }
626
627        // Check it it it is running on mobile device
628        function isMobileDevice() {
629            if(
630                navigator.userAgent.match(/Android/i) ||
631                navigator.userAgent.match(/BlackBerry/i) ||
632                navigator.userAgent.match(/iPhone|iPad|iPod/i) ||
633                navigator.userAgent.match(/Opera Mini/i) ||
634                navigator.userAgent.match(/IEMobile/i) ||
635                navigator.userAgent.match(/iPhone|iPad|iPod/i)
636              )
637            {
638              return true;
639            }
640            else
641            {
642              return false;
643            }
644        }
645
646        // Close TOC
647        function closTOC(){
648            $("#toc").hide("slide", 500);
649            $("#toctitle").hide("slide", 500);
650            if(!isMobileDevice()){
651                $(".ui-resizable-e").hide("slide", 500);
652            }
653            // Show the show/hide button
654            $("#toggle").css("right", "-40px");
655            // Fil width
656            $("body").animate({"margin-left": "50px"}, 500);
657        }
658
659        // Open TOC
660        function openTOC(){
661            $("#toc").show("slide", 500);
662            $("#toctitle").show("slide", 500);
663            if(!isMobileDevice()){
664              $(".ui-resizable-e").show("slide", 500);
665            }
666            // Show the show/hide button
667            $("#toggle").css("right", "15px");
668            // Minimize page width
669            $("body").animate({"margin-left": $(toc).outerWidth()+20+"px"}, 500);
670        }
671
672      });
673
674</script>
675
676"""
677
678def do_replace (input_file,contents,look,str_replaced):
679    if contents.count(look)!=1 :
680        raise Exception('Cannot find {0} in file {1} '.format(look,input_file))
681
682    return  contents.replace(look, str_replaced)
683
684
685
686def toc_fixup_file (input_file,
687                    out_file,
688                    json_file_name
689                    ):
690
691    file = open(input_file)
692    contents = file.read()
693
694    contents = do_replace(input_file,contents,'<body class="book">', TOC_HEAD);
695    contents = do_replace(input_file,contents,'</body>', TOC_END)
696    contents = do_replace(input_file,contents,'input_replace_me.json', json_file_name)
697
698    file = open(out_file,'w')
699    file.write(contents)
700    file.close();
701
702
703
704def convert_to_html_toc_book(task):
705
706    input_file = task.inputs[0].abspath()
707
708    json_out_file = os.path.splitext(task.outputs[0].abspath())[0]+'.json'
709    tmp = os.path.splitext(task.outputs[0].abspath())[0]+'.tmp'
710    json_out_file_short = os.path.splitext(task.outputs[0].name)[0]+'.json'
711
712    cmd='{0} -a stylesheet={1} -a  icons=true -a docinfo -d book  -o {2} {3}'.format(
713            task.env['ASCIIDOC'][0],
714            task.inputs[1].abspath(),
715            tmp,
716            task.inputs[0].abspath());
717
718    res= os.system( cmd )
719    if res !=0 :
720        return (1)
721
722    create_toc_json(tmp,json_out_file)
723
724    toc_fixup_file(tmp,task.outputs[0].abspath(),json_out_file_short);
725
726    return os.system('rm {0}'.format(tmp));
727
728
729
730
731def convert_to_pdf_book(task):
732    input_file = task.outputs[0].abspath()
733    out_dir = task.outputs[0].parent.get_bld().abspath()
734    return os.system('a2x --no-xmllint %s -f pdf  -d book %s -D %s ' %('-v' if Logs.verbose else '', task.inputs[0].abspath(),out_dir ) )
735
736
737def ensure_dir(f):
738    if not os.path.exists(f):
739        os.makedirs(f)
740
741
742def my_copy(task):
743    input_file=task.outputs[0].abspath()
744    out_dir=task.outputs[0].parent.get_bld().abspath()
745    ensure_dir(out_dir)
746    shutil.copy2(input_file, out_dir+ os.sep+task.outputs[0].name)
747    return (0)
748
749
750def do_visio(bld):
751    for x in bld.path.ant_glob('visio\\*.vsd'):
752        tg = bld(rule='${VIS} -i ${SRC} -o ${TGT} ', source=x, target=x.change_ext('.png'))
753
754def get_sphinx_version(sphinx_path):
755    try:
756        global sphinx_version
757        if not sphinx_version:
758            sphinx_version_regexp = '^Sphinx \(sphinx-build\) (\d+)\.(\d+)\.\d+$'
759            cmd = '%s %s --version' % (sys.executable, sphinx_path)
760            output = subprocess.check_output(shlex.split(cmd), universal_newlines = True)
761            for line in output.splitlines():
762                ver = re.match(sphinx_version_regexp, line)
763                if ver:
764                    sphinx_version = float('%s.%s' % (ver.group(1), ver.group(2)))
765        return sphinx_version
766    except Exception as e:
767        print('Error getting Sphinx version: %s' % e)
768
769def get_trex_core_git():
770    trex_core_git_path = os.path.abspath(os.path.join(os.getcwd(), os.pardir))
771    if not os.path.isdir(trex_core_git_path):
772        trex_core_git_path = os.getenv('TREX_CORE_GIT', None)
773    return trex_core_git_path
774
775def parse_hlt_args(task):
776    trex_core_git_path = get_trex_core_git()
777    if not trex_core_git_path:
778        return 1
779    hltapi_path = os.path.abspath(os.path.join(trex_core_git_path, 'scripts', 'automation', 'trex_control_plane', 'stl', 'trex_stl_lib', 'trex_stl_hltapi.py'))
780    header = ['[options="header",cols="<.^1,^.^1,9<.^e"]', '|=================', '^| Argument | Default ^| Comment']
781    footer = ['|=================\n']
782    hlt_asciidoc = []
783    category_regexp = '^(\S+)_kwargs = {$'
784    comment_line_regexp = '^\s*#\s*(.+)$'
785    arg_line_regexp = "^\s*'([^']+)':\s*'?([^,']+)'?,\s*#?\s*(.+)?$"
786    if not os.path.exists(hltapi_path):
787        raise Exception('Could not find hltapi file: %s' % hltapi_path)
788    with open(hltapi_path) as f:
789        in_args = False
790        for line in f.read().splitlines():
791            if not in_args:
792                if line.startswith('import'):
793                    break
794                category_line = re.match(category_regexp, line)
795                if category_line:
796                    hlt_asciidoc.append('\n===== %s\n' % category_line.group(1))
797                    hlt_asciidoc += header
798                    in_args = True
799                continue
800            comment_line = re.match(comment_line_regexp, line)
801            if comment_line:
802                hlt_asciidoc.append('3+^.^s| %s' % comment_line.group(1).replace('|', '\|'))
803                continue
804            arg_line = re.match(arg_line_regexp, line)
805            if arg_line:
806                arg, default, comment = arg_line.groups()
807                hlt_asciidoc.append('| %s | %s | %s' % (arg, default, comment.replace('|', '\|') if comment else ''))
808                continue
809            if line == '}':
810                hlt_asciidoc += footer
811                in_args = False
812    if not len(hlt_asciidoc):
813        raise Exception('Parsing of hltapi args failed')
814    with open('build/hlt_args.asciidoc', 'w') as f:
815        f.write('\n'.join(hlt_asciidoc))
816    return 0
817
818def build_cp_docs (task):
819    out_dir = task.outputs[0].abspath()
820    export_path = os.path.join(os.getcwd(), 'build', 'cp_docs')
821    trex_core_git_path = get_trex_core_git()
822    if not trex_core_git_path: # there exists a default directory or the desired ENV variable.
823        return 1
824    trex_core_docs_path = os.path.abspath(os.path.join(trex_core_git_path, 'scripts', 'automation', 'trex_control_plane', 'doc'))
825    sphinx_version = get_sphinx_version(task.env['SPHINX'][0])
826    if not sphinx_version:
827        return 1
828    if sphinx_version < 1.3:
829        additional_args = '-D html_theme=default'
830    else:
831        additional_args = ''
832    build_doc_cmd = "{pyt} {sph} {add} {ver} -W -b {bld} {src} {dst}".format(
833        pyt= sys.executable,
834        sph= task.env['SPHINX'][0],
835        add= additional_args,
836        ver= '' if Logs.verbose else '-q',
837        bld= "html",
838        src= ".",
839        dst= out_dir)
840    if Logs.verbose:
841        print(build_doc_cmd)
842    try:
843        return subprocess.call(shlex.split(build_doc_cmd), cwd = trex_core_docs_path)
844    except OSError as e:
845        print('Failed command: %s\nError: %s' % (build_doc_cmd, e))
846        return 1
847
848def build_stl_cp_docs (task):
849    out_dir = task.outputs[0].abspath()
850    export_path = os.path.join(os.getcwd(), 'build', 'cp_stl_docs')
851    trex_core_git_path = get_trex_core_git()
852    if not trex_core_git_path: # there exists a default directory or the desired ENV variable.
853        return 1
854    trex_core_docs_path = os.path.abspath(os.path.join(trex_core_git_path, 'scripts', 'automation', 'trex_control_plane', 'doc_stl'))
855    sphinx_version = get_sphinx_version(task.env['SPHINX'][0])
856    if not sphinx_version:
857        return 1
858    if sphinx_version < 1.3:
859        additional_args = '-D html_theme=default'
860    else:
861        additional_args = ''
862    build_doc_cmd = "{pyt} {sph} {add} {ver} -W -b {bld} {src} {dst}".format(
863        pyt= sys.executable,
864        sph= task.env['SPHINX'][0],
865        add= additional_args,
866        ver= '' if Logs.verbose else '-q',
867        bld= "html",
868        src= ".",
869        dst= out_dir)
870    if Logs.verbose:
871        print(build_doc_cmd)
872    try:
873        return subprocess.call(shlex.split(build_doc_cmd), cwd = trex_core_docs_path)
874    except OSError as e:
875        print('Failed command: %s\nError: %s' % (build_doc_cmd, e))
876        return 1
877
878
879
880def build_cp(bld,dir,root,callback):
881    export_path = os.path.join(os.getcwd(), 'build', dir)
882    trex_core_git_path = get_trex_core_git()
883    if not trex_core_git_path: # there exists a default directory or the desired ENV variable.
884        raise NameError("Environment variable 'TREX_CORE_GIT' is not defined.")
885    trex_core_docs_path = os.path.join(trex_core_git_path, 'scripts', 'automation', 'trex_control_plane', root, 'index.rst')
886    bld(rule=callback,target = dir)
887
888
889
890
891def create_analytic_report(task):
892    try:
893        import AnalyticsWebReport as analytics
894        analytics.main(verbose = Logs.verbose)
895    except Exception as e:
896        raise Exception('Error importing or using AnalyticsWebReport script: %s' % e)
897
898
899
900
901
902def build(bld):
903    bld(rule=my_copy, target='symbols.lang')
904
905    for x in bld.path.ant_glob('images\\**\**.png'):
906            bld(rule=my_copy, target=x)
907            bld.add_group()
908
909
910    for x in bld.path.ant_glob('yaml\\**\**.yaml'):
911            bld(rule=my_copy, target=x)
912            bld.add_group()
913
914
915    for x in bld.path.ant_glob('video\\**\**.mp4'):
916            bld(rule=my_copy, target=x)
917            bld.add_group()
918
919
920    for x in bld.path.ant_glob('images\\**\**.jpg'):
921        bld(rule=my_copy, target=x)
922        bld.add_group()
923
924    if bld.options.performance:
925        bld(rule=create_analytic_report)
926        bld.add_group()
927        bld(rule=convert_to_html_toc_book, source='trex_analytics.asciidoc waf.css', target='trex_analytics.html',scan=ascii_doc_scan);
928        return
929
930    bld(rule=my_copy, target='my_chart.js')
931
932    build_cp(bld,'hlt_args.asciidoc','stl/trex_stl_lib', parse_hlt_args)
933
934    bld.add_group() # separator, the documents may require any of the pictures from above
935
936    if os.path.exists('build/hlt_args.asciidoc'):
937        bld.add_manual_dependency(
938            bld.path.find_node('trex_stateless.asciidoc'),
939            b'build/hlt_args.asciidoc')
940
941    bld(rule='${ASCIIDOC}  -f ../backends/deckjs/deckjs.conf -o ${TGT} ${SRC[0].abspath()}',
942        source='trex_config.asciidoc ', target='trex_config_guide.html', scan=ascii_doc_scan)
943
944
945    bld(rule='${ASCIIDOC}  -f ../backends/deckjs/deckjs.conf -o ${TGT} ${SRC[0].abspath()}',
946        source='trex_preso.asciidoc ', target='trex_preso.html', scan=ascii_doc_scan)
947
948    bld(rule='${ASCIIDOC}  -a stylesheet=${SRC[1].abspath()} -a  icons=true -a max-width=55em  -o ${TGT} ${SRC[0].abspath()}',
949        source='release_notes.asciidoc waf.css', target='release_notes.html', scan=ascii_doc_scan)
950
951    bld(rule='${ASCIIDOC} -a docinfo -a stylesheet=${SRC[1].abspath()} -a  icons=true -a toc2  -a max-width=55em  -d book   -o ${TGT} ${SRC[0].abspath()}',
952        source='draft_trex_stateless.asciidoc waf.css', target='draft_trex_stateless.html', scan=ascii_doc_scan)
953
954    bld(rule='${ASCIIDOC} -a docinfo -a stylesheet=${SRC[1].abspath()} -a  icons=true -a toc2  -a max-width=55em  -d book   -o ${TGT} ${SRC[0].abspath()}',
955        source='draft_trex_stateless_moved1.asciidoc waf.css', target='draft_trex_stateless1.html', scan=ascii_doc_scan)
956
957    bld(rule=convert_to_pdf_book,source='trex_book.asciidoc waf.css', target='trex_book.pdf', scan=ascii_doc_scan)
958
959    bld(rule=convert_to_pdf_book,source='trex_stateless.asciidoc waf.css', target='trex_stateless.pdf', scan=ascii_doc_scan)
960
961    bld(rule=convert_to_pdf_book,source='draft_trex_stateless.asciidoc waf.css', target='draft_trex_stateless.pdf', scan=ascii_doc_scan)
962
963    bld(rule=convert_to_pdf_book,source='trex_vm_manual.asciidoc waf.css', target='trex_vm_manual.pdf', scan=ascii_doc_scan)
964
965    bld(rule=convert_to_pdf_book,source='trex_control_plane_peek.asciidoc waf.css', target='trex_control_plane_peek.pdf', scan=ascii_doc_scan)
966
967    bld(rule=convert_to_pdf_book, source='trex_control_plane_design_phase1.asciidoc waf.css', target='trex_control_plane_design_phase1.pdf', scan=ascii_doc_scan)
968
969    # with nice TOC
970    bld(rule=convert_to_html_toc_book,
971        source='trex_vm_manual.asciidoc waf.css', target='trex_vm_manual.html',scan=ascii_doc_scan)
972
973    bld(rule=convert_to_html_toc_book,
974        source='trex_stateless.asciidoc waf.css', target='trex_stateless.html',scan=ascii_doc_scan);
975
976    bld(rule=convert_to_html_toc_book,
977        source='trex_stateless_bench.asciidoc waf.css', target='trex_stateless_bench.html',scan=ascii_doc_scan);
978
979    bld(rule=convert_to_html_toc_book,
980        source='trex_book.asciidoc waf.css', target='trex_manual.html',scan=ascii_doc_scan);
981
982    bld(rule=convert_to_html_toc_book,
983        source='trex_faq.asciidoc waf.css', target='trex_faq.html',scan=ascii_doc_scan);
984
985    bld(rule=convert_to_html_toc_book,
986        source='trex_rpc_server_spec.asciidoc waf.css', target='trex_rpc_server_spec.html',scan=ascii_doc_scan);
987
988    bld(rule=convert_to_html_toc_book,
989        source='trex_scapy_rpc_server.asciidoc waf.css', target='trex_scapy_rpc_server.html',scan=ascii_doc_scan);
990
991    bld(rule=convert_to_html_toc_book,
992        source='trex-analytics-howto.asciidoc waf.css', target='trex-analytics-howto.html',scan=ascii_doc_scan);
993
994    bld(rule='${ASCIIDOC}   -a stylesheet=${SRC[1].abspath()} -a  icons=true -a toc2 -a max-width=55em  -o ${TGT} ${SRC[0].abspath()}',
995        source='vm_doc.asciidoc waf.css', target='vm_doc.html', scan=ascii_doc_scan)
996
997    bld(rule='${ASCIIDOC}   -a stylesheet=${SRC[1].abspath()} -a  icons=true -a toc2 -a max-width=55em  -o ${TGT} ${SRC[0].abspath()}',
998        source='packet_builder_yaml.asciidoc waf.css', target='packet_builder_yaml.html', scan=ascii_doc_scan)
999
1000
1001    bld(rule='${ASCIIDOC}   -a stylesheet=${SRC[1].abspath()} -a  icons=true -a toc2 -a max-width=55em  -o ${TGT} ${SRC[0].abspath()}',
1002        source='trex_control_plane_design_phase1.asciidoc waf.css', target='trex_control_plane_design_phase1.html', scan=ascii_doc_scan)
1003
1004    bld(rule='${ASCIIDOC}   -a stylesheet=${SRC[1].abspath()} -a  icons=true -a toc2 -a max-width=55em  -o ${TGT} ${SRC[0].abspath()}',
1005        source='trex_control_plane_peek.asciidoc waf.css', target='trex_control_plane_peek.html', scan=ascii_doc_scan)
1006
1007    bld(rule='${ASCIIDOC}   -a stylesheet=${SRC[1].abspath()} -a  icons=true -a toc2 -a max-width=55em  -o ${TGT} ${SRC[0].abspath()}',
1008        source='trex_console.asciidoc waf.css', target='trex_console.html', scan=ascii_doc_scan)
1009
1010    bld(rule='${ASCIIDOC}   -a stylesheet=${SRC[1].abspath()} -a  icons=true  -a max-width=55em  -o ${TGT} ${SRC[0].abspath()}',
1011        source='trex_index.asciidoc waf.css', target='index.html', scan=ascii_doc_scan)
1012
1013    build_cp(bld,'cp_docs','doc',build_cp_docs)
1014
1015    build_cp(bld,'cp_stl_docs','doc_stl',build_stl_cp_docs)
1016
1017
1018class Env(object):
1019    @staticmethod
1020    def get_env(name) :
1021        s= os.environ.get(name);
1022        if s == None:
1023            print("You should define $",name)
1024            raise Exception("Env error");
1025        return (s);
1026
1027    @staticmethod
1028    def get_release_path () :
1029        s= Env().get_env('TREX_LOCAL_PUBLISH_PATH');
1030        s +=get_build_num ()+"/"
1031        return  s;
1032
1033    @staticmethod
1034    def get_remote_release_path () :
1035        s= Env().get_env('TREX_REMOTE_PUBLISH_PATH');
1036        return  s;
1037
1038    @staticmethod
1039    def get_local_web_server () :
1040        s= Env().get_env('TREX_WEB_SERVER');
1041        return  s;
1042
1043    # extral web
1044    @staticmethod
1045    def get_trex_ex_web_key() :
1046        s= Env().get_env('TREX_EX_WEB_KEY');
1047        return  s;
1048
1049    @staticmethod
1050    def get_trex_ex_web_path() :
1051        s= Env().get_env('TREX_EX_WEB_PATH');
1052        return  s;
1053
1054    @staticmethod
1055    def get_trex_ex_web_user() :
1056        s= Env().get_env('TREX_EX_WEB_USER');
1057        return  s;
1058
1059    @staticmethod
1060    def get_trex_ex_web_srv() :
1061        s= Env().get_env('TREX_EX_WEB_SRV');
1062        return  s;
1063
1064    @staticmethod
1065    def get_trex_core() :
1066        s= Env().get_env('TREX_CORE_GIT');
1067        return  s;
1068
1069
1070
1071def release(bld):
1072    # copy all the files to our web server
1073    core_dir = Env().get_trex_core()
1074    release_dir = core_dir +"/scripts/doc/";
1075    os.system('mkdir -p '+release_dir)
1076    os.system('cp -rv build/release_notes.* '+ release_dir)
1077
1078
1079def publish(bld):
1080    # copy all the files to our web server
1081    remote_dir = "%s:%s" % ( Env().get_local_web_server(), Env().get_remote_release_path ()+'../doc/')
1082    os.system('rsync -av --del --rsh=ssh build/ %s' % (remote_dir))
1083
1084
1085def publish_ext(bld):
1086   from_ = 'build/'
1087   os.system('rsync -avz --del -e "ssh -i %s" --rsync-path=/usr/bin/rsync %s %s@%s:%s/doc/' % (Env().get_trex_ex_web_key(),from_, Env().get_trex_ex_web_user(),Env().get_trex_ex_web_srv(),Env().get_trex_ex_web_path() ) )
1088
1089
1090def publish_test(bld):
1091    # copy all the files to our web server
1092    remote_dir = "%s:%s" % ( Env().get_local_web_server(), Env().get_remote_release_path ()+'../test/')
1093    os.system('rsync -av --del --rsh=ssh build/ %s' % (remote_dir))
1094
1095
1096
1097def publish_both(bld):
1098    publish(bld)
1099    publish_ext(bld)
1100
1101
1102def test(bld):
1103    # copy all the files to our web server
1104    toc_fixup_file ('build/trex_stateless.tmp',
1105                    'build/trex_stateless.html',
1106                    'trex_stateless.json')
1107
1108
1109
1110