Class: DocbookFiles::App

Inherits:
Object
  • Object
show all
Defined in:
lib/docbook_files/app.rb

Overview

App class for the binary

Return codes

  • 0 - ok

  • 1 - no arguments or file not found

  • 2 - processing error

Constant Summary collapse

EMPTYVAL =

Replacement for empty values

'-'
XXL_SIZE =

Replacement for monstrously large files sizes

"XXL"
KB =

:stopdoc:

1024
MB =
1048576
GB =
1073741824
TB =
1099511627776
PB =
1125899906842624
<<EOB
docbook_files, Version #{DocbookFiles::VERSION}

Shows the file hierarchy of a DocBook 5 project. 
Files with problems (not found, invalid ...) are marked red.

Usage: docbook_files [options] <DOCBOOK-FILE>
EOB

Instance Method Summary collapse

Constructor Details

#initialize(opts = {}) ⇒ App

Initialize options and reset the FileData storage



76
77
78
79
80
81
82
83
84
85
86
87
# File 'lib/docbook_files/app.rb', line 76

def initialize(opts = {})
  opts[:stdout] ||= $stdout
  opts[:stderr] ||= $stderr
  @opts = opts
  @stdout = opts[:stdout]
  @stderr = opts[:stderr]
  @opts[:output_format] ||= :screen
  @opts[:details] ||= false
  @opts[:json_available] ||= opts[:json_available]
  @props = [:name, :path, :status, :size]
  FileData.reset()
end

Instance Method Details

#emptyval?(val) ⇒ Boolean

Check whether the value is nil or empty.

Returns:

  • (Boolean)


280
281
282
283
284
285
286
# File 'lib/docbook_files/app.rb', line 280

def emptyval?(val)
  if val.nil?
    true
  else
    (val.class == String) ? val.empty? : false
  end
end

#files2table(files) ⇒ Object

Transform the files into something YAML/JSON can handle



150
151
152
153
154
155
156
# File 'lib/docbook_files/app.rb', line 150

def files2table(files)
  files.map { |f|
    f.to_hash([:name, :path, :status, :error_string, :namespace,
               :version, :docbook, :tag, :ts, :size, :checksum,
               :mime, :includes, :included_by, :references, :referenced_by])
  }
end

#format_fds(fds) ⇒ Object

Format a list of FileDatas



224
225
226
227
228
229
230
# File 'lib/docbook_files/app.rb', line 224

def format_fds(fds)
  if (fds.nil? || fds.empty?)
    EMPTYVAL
  else
    fds.map {|p| p.path}.join ','
  end
end

#format_name(level, full_name) ⇒ Object

Format the filename to indicate the level in the hierarchy. Indentation = two spaces per level.

If the file is located somewhere below the main file, only the relative part of the path is shown, else the full path. If the resulting string is too long for display it is shortened.



239
240
241
242
243
244
245
246
# File 'lib/docbook_files/app.rb', line 239

def format_name(level, full_name)
  lnname = '  '*level+full_name
  if (lnname.length > 60)
    lnname[0..3]+'...'+lnname[-54,lnname.length-1]
  else
    lnname
  end
end

#format_size(sz) ⇒ Object

Format a file size for human consumption. Sizes >= 1PB will return ‘XXL’



258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
# File 'lib/docbook_files/app.rb', line 258

def format_size(sz)
  if (emptyval?(sz))
    EMPTYVAL
  else
    case
    when sz < KB then  "#{sz}B"
    when sz >= KB && sz < MB then "#{sz/KB}KB"
    when sz >= MB && sz < GB then "#{sz/MB}MB"
    when sz >= GB && sz < TB then "#{sz/GB}GB"
    when sz >= TB && sz < PB then "#{sz/TB}TB"
    else
      XXL_SIZE
    end
  end
end

#output_details(files) ⇒ Object

Print the FileData representation to the terminal



196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
# File 'lib/docbook_files/app.rb', line 196

def output_details(files)      
  @stdout.puts
  @stdout.puts "Details".bold
  files.each do |t|
    fname = t.path
    @stdout.puts "File: %s" % [((t.status == FileData::STATUS_OK) ? fname : fname.red)]
    @stdout.puts "Includes: %s" % [format_fds(t.includes)] unless t.includes.empty?
    @stdout.puts "Included by: %s" % [format_fds(t.included_by)] unless t.included_by.empty?
    @stdout.puts "References: %s" % [format_fds(t.references)] unless t.references.empty?
    @stdout.puts "Referenced by: %s" % [format_fds(t.referenced_by)] unless t.referenced_by.empty?
    unless t.status == FileData::STATUS_NOT_FOUND
      # show that part only if file exists
      @stdout.puts "Size: %s (%d)" % [format_size(t.size),t.size]
      if (t.docbook)
        @stdout.puts "Type: DocBook, Version #{t.version}, Tag: #{t.tag}"
      else
        @stdout.puts "MIME: #{val_s(t.mime)}"
      end
      @stdout.puts "Timestamp: %s" % [t.ts]
      @stdout.puts "SHA1: %s" % [t.checksum]
    end
    @stdout.puts "Error: %s" % [t.error_string.to_s.red] unless (t.error_string.nil?)            
    @stdout.puts
  end
end

#output_hierarchy(table) ⇒ Object

Terminal output for file hierarchy



159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
# File 'lib/docbook_files/app.rb', line 159

def output_hierarchy(table)
  output_string = "%3d %-60s %4s %10s" 
  @stdout.puts
  @stdout.puts 'File Hierarchy'.bold
  @stdout.puts "%3s %-60s %4s %10s" % ['Lvl', 'File','Type','Size']
  @stdout.puts '-'*80
  sum_size = 0
  sum_not_existing = 0
  sum_xml_err = 0
  table.each do |t|
    output = output_string % [t[:level],
                              format_name(t[:level],t[:path]),
                              t[:type].to_s,
                              format_size(t[:size])]
    sum_size += t[:size]
    if t[:status] == FileData::STATUS_NOT_FOUND
      @stdout.puts output.red
      sum_not_existing += 1
    elsif t[:status] == FileData::STATUS_ERR
      @stdout.puts output.red
      sum_xml_err += 1          
    else
      @stdout.puts output
    end
  end
  @stdout.puts '-'*80
  summary = "#{table.length} file(s) with approx. #{format_size(sum_size)}."
  if sum_not_existing > 0
    summary += " #{sum_not_existing} file(s) not found.".red
  end
  if sum_xml_err > 0
    summary += " #{sum_xml_err} file(s) with errors.".red
  end
  @stdout.puts summary
end

#run(args) ⇒ Object



89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
# File 'lib/docbook_files/app.rb', line 89

def run(args)
  opts = OptionParser.new
  opts.on('--details','List file details') {|val| @opts[:details] = true}
  opts.on('--outputformat=yaml|json',['yaml','json'],
          'Return the result in YAML or JSON format') {|format|
    case
    when format == 'yaml'
      @opts[:output_format] = :yaml
    when format == 'json'
      if @opts[:json_available]
        @opts[:output_format] = :json
      else
        @stderr.puts "Error: JSON not available. Please install the json gem first."
        exit 1
      end
    else
      @stderr.puts "Error: Unknown output format #{format}."
    end
  }        
  opts.banner = @@banner
  rest = opts.parse(args)

  # Print banner if called without arguments
  if rest.length < 1
    @stdout.puts opts.to_s 
    exit 1
  end

  # Fail if argument not found
  @stdout.puts("docbook_files, Version #{DocbookFiles::VERSION}") if @opts[:output_format] == :screen
  unless File.exists?(rest[0])
    @stderr.puts "Error: File #{rest[0]} not found.".red
    exit 1
  end

  # Main
  begin
    dbf = DocbookFiles::Docbook.new(rest[0])
    table = dbf.list_as_table(@props)
    files = FileData.files
  rescue => exc
    @stderr.puts "Something unexpected happend while docbook_files was running ..."
    @stderr.puts exc.inspect.red
    exit 2
  end
  unless table.nil?
    case @opts[:output_format]
    when :json
      out = {:hierarchy => table, :details => files2table(files)}
      @stdout.puts out.to_json
    when :yaml
      out = {:hierarchy => table, :details => files2table(files)}
      YAML.dump(out,@stdout)
    else
      output_hierarchy(table)
      output_details(files) if @opts[:details]        
    end
  end
end

#val_s(val) ⇒ Object

Return a string for the value, ‘-’ if there is none.



275
276
277
# File 'lib/docbook_files/app.rb', line 275

def val_s(val)
  emptyval?(val) ? EMPTYVAL : val.to_s
end