1#!/usr/bin/env ruby
2#
3# Internal helper script to create a markdown file from binaries
4#
5# The --index option creates the index page
6#
7#    bin2md [--index] erbtemplate [binary]
8#
9# by Pjotr Prins (C) 2020
10#
11# The rules are simple USAGE:
12#
13#    usage: can be multiline block anywhere in the output
14#
15# After removing that the next block is the DESCRIPTION.
16# Onle line create a TYPE (see TYPES).
17# The rest are the OPTIONS.
18
19require 'erb'
20require 'date'
21require 'open3'
22
23# cerr << endl << "Type: statistics" << endl << endl;
24# cerr << endl << "Type: transformation" << endl << endl;
25TYPES = ["filter","metrics","phenotype","genotype","transformation","statistics"]
26
27=begin
28
29if (argc == 2) {
30  string h_flag = argv[1];
31  if (h_flag == "-h" || h_flag == "--help") {
32      cerr << R"(
33Generate a random VCF file
34
35Usage: vcfrandom
36
37Example:
38
39    vcfrandom
40
41
42Type: statistics
43
44      )";
45      exit(1);
46    }
47  }
48
49=end
50
51
52VERSION=`cat ./VERSION`.strip
53template = ARGV.shift
54is_man = false # creating man pages?
55if template == "--man"
56  is_man = true
57  template = ARGV.shift
58end
59create_index = false
60if template == "--index"
61  create_index = true
62  template = ARGV.shift
63  index = []
64end
65search = ARGV.shift
66
67bindir = './build'
68$stderr.print("--- Parsing the bin files in #{bindir} for #{VERSION}\n")
69
70d = DateTime.now
71year = d.year
72
73Dir.glob(bindir+'/*').each do|bin|
74  if !File.directory?(bin) and File.executable?(bin)
75    if search and bin !~ /#{search}/
76      next
77    end
78    cmd = File.basename(bin)
79    help_cmd = cmd + " -h"
80    $stderr.print("    "+bin+"\n")
81    stdout, stderr, status = Open3.capture3(bin+" -h")
82    out = stderr + stdout
83    if out == ""
84      help_cmd = cmd
85      stdout, stderr, status = Open3.capture3(bin)
86      out = stderr + stdout
87    end
88    # out = ,:encoding => 'UTF-8'
89    out = out.encode('UTF-8')
90    # $stderr.print(out)
91    lines = (out).split("\n")
92    lines = lines.map{|l| l.gsub(/#{Regexp.escape(cmd)}/,"**#{cmd}**")}
93    lines = lines.map{|l| l.gsub(/\.+\/build\//,"")}
94    lines = lines.map{|l| l.gsub(/INFO: help:?/,"")}
95    lines = lines.map{|l| l.gsub(/INFO: description:/,"")}
96    lines = lines.map{|l| l.gsub(/INFO:\s+/,"")}
97    pydoc_full = lines.map{|l| l=="" ? '>' : l }.join("\n")
98    in_usage = false
99    has_options = nil
100    has_example = false
101    usage = []
102    other = []
103    example = []
104    lines.shift while lines[0] == ""
105    lines.each do | l |
106      break if l == "------------------------------------------------------"
107      if l =~ /usage/i
108        in_usage = true
109      end
110      if in_usage
111        if l == "" or l =~ /^Output/i
112          in_usage = false
113          next
114        end
115        usage << l
116      else
117        if l =~ /^Example:/
118          has_example = true
119        end
120        if has_example
121          example << l
122        else
123          other << l
124        end
125      end
126    end
127    descr = []
128    rest = other
129    type = "unknown"
130    (other+example).each do | l |
131      if l =~ /type: (\S+)/i
132        type = $1
133        raise "Unknown type #{type} for #{cmd}" if !TYPES.include?(type)
134        break
135      end
136    end
137
138    other.each do | l |
139      break if l == "" or l =~ /^Output/i or l =~ /Options/i
140      descr << l
141    end
142
143    if descr == []
144      lineno = 0
145      rr = rest.reverse
146      rr.each_with_index do | l,i |
147        if l != "" and l !~ /^Type/i
148          lineno = i
149          break
150        end
151      end
152      rr = rr[lineno..-1]
153      rr.each do | l |
154        if descr.length and l == "" or l =~ /^\s/
155          descr = descr.reverse
156          break
157        end
158        descr << l
159      end
160      rest = rr.drop(descr.size).reverse
161    else
162      rest = rest.drop(descr.size)
163    end
164
165    body = rest.join("\n")
166    has_options = true if body != ""
167    usage = usage.join(" ").gsub(/#{VERSION}\s+/,"")
168    usage = usage.gsub(/usage:\s+/i,"")
169    usage = usage.gsub(/\s+/," ").strip
170    pydoc_full = pydoc_full.gsub(/#{VERSION}\s+/,"")
171    pydoc_full = pydoc_full.gsub(/\.\.\/build\//,"")
172    # pydoc_full = pydoc_full.gsub(/vcflib/,"VCF")
173    descr = descr.join(" ").gsub(/#{VERSION}\s+/,"")
174    descr = descr.sub(/vcflib/,"VCF")
175    descr = descr.gsub(/\s+/," ").strip
176    example = example.join("\n")
177    # print("HELP:",help_cmd,"\n")
178    # print("DESCRIPTION:",descr,"\n")
179    # print("USAGE:",usage,"\n")
180    # print("TYPE:",type,"\n")
181    # print("BODY:",body,"\n")
182
183    if create_index
184      rec = {
185        cmd: cmd,
186        type: type,
187        descr: descr
188      }
189      index << rec
190    else
191      b = binding
192      renderer = ERB.new(File.read(template))
193
194      File.open("./doc/#{cmd}.md","w") { |f|
195        f.print renderer.result(b)
196      }
197    end
198  end
199end
200if create_index
201  require 'ostruct'
202
203  renderer = ERB.new(File.read("./test/scripts/index-item.erb"))
204  File.open("./doc/vcflib.md","w") { |f|
205    f.print <<HEADER
206% vcflib(1) vcflib | vcfilb (index)
207% Erik Garrison and vcflib contributors
208
209# NAME
210
211**vcflib** index
212
213# DESCRIPTION
214
215vcflib contains tools and libraries for dealing with the Variant Call
216Format (VCF) which is a flat-file, tab-delimited textual format
217intended to describe reference-indexed variations between
218individuals.
219
220VCF provides a common interchange format for the description of
221variation in individuals and populations of samples, and has become
222the defacto standard reporting format for a wide array of genomic
223variant detectors.
224
225vcflib provides methods to manipulate and interpret sequence variation
226as it can be described by VCF. It is both:
227
228* an API for parsing and operating on records of genomic variation as it can be described by the VCF format,
229* and a collection of command-line utilities for executing complex manipulations on VCF files.
230
231The API itself provides a quick and extremely permissive method to
232read and write VCF files. Extensions and applications of the library
233provided in the included utilities (*.cpp) comprise the vast bulk of
234the library's utility for most users.
235
236<!--
237  Created with ./scripts/bin2md.rb --index
238-->
239
240HEADER
241    TYPES.each do | type |
242      f.print   %{
243## #{type}
244
245| #{type} command | description |
246| :-------------- | :---------- |
247}
248
249      index.each do | rec |
250        rec = OpenStruct.new(rec)
251        if rec.type == type
252          b = binding
253          f.print renderer.result(b)
254        end
255      end
256    end
257    github = "https://github.com/vcflib/vcflib"
258    f.print <<FOOTER
259
260# SOURCE CODE
261
262See the source code repository at #{github}
263
264# LICENSE
265
266Copyright 2011-#{year} (C) Erik Garrison and vcflib contributors. MIT licensed.
267
268FOOTER
269  }
270end
271