directory_paradise 1.4.4

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of directory_paradise might be problematic. Click here for more details.

Files changed (31) hide show
  1. checksums.yaml +7 -0
  2. data/README.md +213 -0
  3. data/bin/show_directory_content +7 -0
  4. data/directory_paradise.gemspec +45 -0
  5. data/doc/README.gen +185 -0
  6. data/doc/todo/todo.md +4 -0
  7. data/lib/directory_paradise/base/base.rb +195 -0
  8. data/lib/directory_paradise/base/colours.rb +196 -0
  9. data/lib/directory_paradise/constants/newline.rb +14 -0
  10. data/lib/directory_paradise/content/constants.rb +23 -0
  11. data/lib/directory_paradise/content/content.rb +682 -0
  12. data/lib/directory_paradise/project/project.rb +22 -0
  13. data/lib/directory_paradise/report/constants.rb +39 -0
  14. data/lib/directory_paradise/report/initialize.rb +75 -0
  15. data/lib/directory_paradise/report/menu.rb +329 -0
  16. data/lib/directory_paradise/report/misc.rb +675 -0
  17. data/lib/directory_paradise/report/obtain.rb +357 -0
  18. data/lib/directory_paradise/report/report.rb +527 -0
  19. data/lib/directory_paradise/report/reset.rb +174 -0
  20. data/lib/directory_paradise/requires/require_class_content.rb +7 -0
  21. data/lib/directory_paradise/requires/require_class_report.rb +7 -0
  22. data/lib/directory_paradise/requires/require_the_directory_paradise_project.rb +10 -0
  23. data/lib/directory_paradise/sdc.rb +24 -0
  24. data/lib/directory_paradise/to_human_readable/to_human_readable.rb +98 -0
  25. data/lib/directory_paradise/version/version.rb +19 -0
  26. data/lib/directory_paradise/yaml/colours_for_bytes_values.yml +14 -0
  27. data/lib/directory_paradise.rb +1 -0
  28. data/test/testing_class_content.rb +16 -0
  29. data/test/testing_class_report.rb +40 -0
  30. data/test/testing_toplevel_methods.rb +14 -0
  31. metadata +110 -0
@@ -0,0 +1,527 @@
1
+ #!/usr/bin/ruby -w
2
+ # Encoding: UTF-8
3
+ # frozen_string_literal: true
4
+ # =========================================================================== #
5
+ # === DirectoryParadise::Report
6
+ #
7
+ # The purpose of this class is to show the content of a directory, either
8
+ # in a plain variant without any colours, or in a fancified variant, with
9
+ # colours.
10
+ #
11
+ # The initial reason for creating this class was that I needed a general
12
+ # adaptor for when I would be using ruby on windows, or on another
13
+ # operating system, whenever I would try to use larger projects such
14
+ # as the Roebe::Shell component, which is part of the gem called
15
+ # "roebe".
16
+ #
17
+ # In the past, this was the sole use case that class ShowDirectoryContent
18
+ # had to fulfil, but lateron I thought that I could factor this code out
19
+ # into a standalone class, and make it available for other projects as
20
+ # well - as true standalone project. Thus, the directory_content gem
21
+ # was born. \o/
22
+ #
23
+ # This class here has, at least, the following main features that it
24
+ # has to support:
25
+ #
26
+ # - The ability to show the modification time.
27
+ # - The ability to truncate long file names.
28
+ # - The ability to list hidden files.
29
+ # - The ability to sort by size, by passing the argument "size" to it.
30
+ # - The ability to set and define your own colours.
31
+ # - The ability to show a simplified, shorter result.
32
+ # - The ability to make the colour output optional.
33
+ # - The ability to filter on the content, e. g. via '*'.
34
+ #
35
+ # A good general overview for available options for the GNU "ls" command
36
+ # can be found here:
37
+ #
38
+ # https://ss64.com/bash/ls.html
39
+ #
40
+ # =========================================================================== #
41
+ # require 'directory_paradise/report/report.rb'
42
+ # DirectoryParadise::Report.new(ARGV)
43
+ # =========================================================================== #
44
+ require 'directory_paradise/base/base.rb'
45
+
46
+ module DirectoryParadise
47
+
48
+ class Report < Base # === DirectoryParadise::Report
49
+
50
+ require 'colours'
51
+ require 'directory_paradise/project/project.rb'
52
+ require 'directory_paradise/content/content.rb'
53
+ require 'directory_paradise/report/constants.rb'
54
+ require 'directory_paradise/report/initialize.rb'
55
+ require 'directory_paradise/report/menu.rb'
56
+ require 'directory_paradise/report/misc.rb'
57
+ require 'directory_paradise/report/obtain.rb'
58
+ require 'directory_paradise/report/reset.rb'
59
+
60
+ # ========================================================================= #
61
+ # === HASH_COLOURS_FOR_BYTES_VALUE
62
+ # ========================================================================= #
63
+ if File.exist? FILE_COLOURS_FOR_BYTES_VALUES
64
+ HASH_COLOURS_FOR_BYTES_VALUE =
65
+ YAML.load_file(
66
+ FILE_COLOURS_FOR_BYTES_VALUES
67
+ )
68
+ end
69
+
70
+ # ========================================================================= #
71
+ # === try_to_report_the_total_filesize
72
+ #
73
+ # Use this method to report the total filesize from a given directory.
74
+ # ========================================================================= #
75
+ def try_to_report_the_total_filesize
76
+ total_file_size = total_file_size?
77
+ if total_file_size > 0
78
+ ee "\nTotal file size in directory "
79
+ if use_colours?
80
+ e colourize_directory(which_dir?)
81
+ else
82
+ e which_dir?
83
+ end
84
+ n_KB = (total_file_size / 1024.0)
85
+ n_MB = (n_KB / 1024.0)
86
+ e steelblue(
87
+ " #{total_file_size} bytes (#{n_KB.round(2)} KB) (#{n_MB.round(2)} MB)"
88
+ )
89
+ end
90
+ end
91
+
92
+ # ========================================================================= #
93
+ # === return_file_permission_of
94
+ # ========================================================================= #
95
+ def return_file_permission_of(i)
96
+ if condensed? and i.size == 10 # Then we assume we have the long format.
97
+ Roebe::PermissionAsciiFormat[i, :convert_into_decimal_format]
98
+ else # else we must convert it back.
99
+ i # Simply return as-is here.
100
+ end
101
+ end
102
+
103
+ # ========================================================================= #
104
+ # === set_sort_by
105
+ # ========================================================================= #
106
+ def set_sort_by(i)
107
+ @internal_hash[:sort_by] = i
108
+ end; alias sort_by= set_sort_by # === sort_by=
109
+ alias sort_by set_sort_by # === sort_by
110
+
111
+ # ========================================================================= #
112
+ # === sort_how (sort tag, sort how tag)
113
+ #
114
+ # Here we determine how to sort.
115
+ #
116
+ # The sort possibilities are:
117
+ #
118
+ # - by datesort_how
119
+ # - by size
120
+ # - in a reversed manner
121
+ #
122
+ # ========================================================================= #
123
+ def sort_how(
124
+ how = :size
125
+ )
126
+ how = how.to_s.downcase.to_sym # We want a downcased Symbol here.
127
+ case how # case tag
128
+ # ======================================================================= #
129
+ # === :reversed
130
+ # ======================================================================= #
131
+ when :reversed,
132
+ :reverse,
133
+ :by_reverse,
134
+ :by_reversed
135
+ set_sort_by(:reversed)
136
+ # ======================================================================= #
137
+ # === :date
138
+ # ======================================================================= #
139
+ when :date,
140
+ :by_date
141
+ set_sort_by(:date)
142
+ # ======================================================================= #
143
+ # === :size
144
+ # ======================================================================= #
145
+ when :size,
146
+ :sized,
147
+ :by_size # Sort by size.
148
+ set_sort_by(:size)
149
+ # ======================================================================= #
150
+ # === :modification_time
151
+ # ======================================================================= #
152
+ when :modification_time,
153
+ :by_modification_time
154
+ set_sort_by(:modification_time)
155
+ end
156
+ end
157
+
158
+ # ========================================================================= #
159
+ # === show_help_options (help tag)
160
+ #
161
+ # To invoke this method, try:
162
+ #
163
+ # sdc --help
164
+ #
165
+ # ========================================================================= #
166
+ def show_help_options # Help tag.
167
+ e "#{rev}The currently available help options for "\
168
+ "#{simp('DirectoryContent::Report')} are:"
169
+ e
170
+ show_this_help_line :collapse, :short
171
+ show_this_help_line :toggle
172
+ show_this_help_line :nocolours
173
+ show_this_help_line :only_dirs
174
+ show_this_help_line :show_hidden_files
175
+ show_this_help_line :sized
176
+ show_this_help_line :date
177
+ show_this_help_line :lead
178
+ show_this_help_line :disable_show_modification_time
179
+ show_this_help_line :condensed
180
+ e
181
+ e 'Additionally, the following options are a bit more '\
182
+ 'extensively documented here:'
183
+ e
184
+ Colours.eparse ' --show-only-symlinks # '\
185
+ 'This will show only symlinks in the target directory'
186
+ e
187
+ exit
188
+ end
189
+
190
+ # ========================================================================= #
191
+ # === do_sort_by_size
192
+ # ========================================================================= #
193
+ def do_sort_by_size
194
+ sort_how :by_size
195
+ end
196
+
197
+ # ========================================================================= #
198
+ # === consider_sorting
199
+ # ========================================================================= #
200
+ def consider_sorting
201
+ if sort_by?
202
+ @internal_hash[:directory_content].do_sort(sort_by?)
203
+ end
204
+ end
205
+
206
+ # ========================================================================= #
207
+ # === show_content_for
208
+ # ========================================================================= #
209
+ def show_content_for(
210
+ this_path = '/'
211
+ )
212
+ @directory_content.obtain_entries(this_path)
213
+ report
214
+ end
215
+
216
+ # ========================================================================= #
217
+ # === report (report tag, display tag, d tag)
218
+ #
219
+ # This method will always report the main dataset, as determined by
220
+ # class DirectoryParadise::Content.
221
+ # ========================================================================= #
222
+ def report(
223
+ _ = return_directory_content # This will return a Hash.
224
+ )
225
+ @internal_hash[:total_filesize] = 0 # Reset it always here.
226
+ show_condensed_permissions = show_condensed_permissions?
227
+ show_the_index = show_index?
228
+ show_hidden_files = show_hidden_files?
229
+ show_permission_bits = show_permission_bits?
230
+ colourize_path = colourize_path?
231
+ display_only_directories = display_only_directories?
232
+ show_only_symlinks = show_only_symlinks?
233
+ show_modification_time = show_modification_time?
234
+ if display_only_directories
235
+ _.select! {|path, inner_hash| inner_hash[:type] == 'directory' }
236
+ end
237
+ if show_only_symlinks
238
+ _.select! {|path, inner_hash| inner_hash[:type] == 'link' }
239
+ end
240
+ # ======================================================================= #
241
+ # === Build up the header (header tag)
242
+ #
243
+ # Build up the header first, then display it, but only if the user
244
+ # allows this to happen:
245
+ # ======================================================================= #
246
+ if show_header?
247
+ if show_statistics?
248
+ n_files = n_files?
249
+ n_directories = n_directories?
250
+ n_symlinks = n_symlinks?
251
+ file_string = ''
252
+ file_string = 's' if (n_files >= 0) # plural or not.
253
+ # =================================================================== #
254
+ # Pluralize the directory-string.
255
+ # =================================================================== #
256
+ directory_string = 'y'
257
+ symlink_string = 's'
258
+ symlink_string = '' if n_symlinks == 1
259
+ # =================================================================== #
260
+ # Last but not least notify the user of the findings.
261
+ # =================================================================== #
262
+ e rev+'The directory '+
263
+ sdir(work_on_which_directory?)+
264
+ ' contains '+
265
+ sfile(
266
+ n_files.to_s+' file'+file_string
267
+ )+', '+
268
+ sdir(
269
+ n_directories.to_s+' director'+directory_string
270
+ )+' and '+
271
+ ssymlink(
272
+ n_symlinks.to_s+' symlink'+symlink_string
273
+ )+'.'
274
+ end
275
+ header = ''.dup
276
+ header << "#{rev}" if use_colours?
277
+ # ===================================================================== #
278
+ # Add the index next onto the header.
279
+ # ===================================================================== #
280
+ if show_the_index
281
+ header << sfancy('Index'.ljust(6))
282
+ end
283
+ # ===================================================================== #
284
+ # Show permission bits
285
+ # ===================================================================== #
286
+ if show_permission_bits
287
+ header << springgreen('Permissions'.ljust(16))
288
+ end
289
+ # ===================================================================== #
290
+ # Next, determine whether we will display the modification-time
291
+ # or whether we will not:
292
+ # ===================================================================== #
293
+ if show_modification_time
294
+ header << 'ModTime'.ljust(8)
295
+ end
296
+ header << 'FileSize'.ljust(9)
297
+ header << 'Name'.ljust(5)
298
+ eliner
299
+ e header
300
+ end
301
+ # ======================================================================= #
302
+ # This may look like so:
303
+ #
304
+ # "/Depot/j/yodel.rb"=>
305
+ # {:size=>129,ei leader is lined up against a w
306
+ # :type=>"file",
307
+ # :is_executable=>false,
308
+ # :path=>"/Depot/j/yodel.rb",
309
+ # :ascii_representation=>"",
310
+ # :last_modified=>2021-05-31 20:55:53.826658499 +0000,
311
+ # :gid=>0,
312
+ # :inode_number=>93858692,
313
+ # :uid=>0,
314
+ # :access_mode=>"644"}}}>
315
+ #
316
+ # ======================================================================= #
317
+ index = 0
318
+ _.each_pair {|path, inner_hash| # each tag
319
+ if path.end_with?('.') and !show_dots_only_entries? and
320
+ ( (path.end_with? '.') or (path.end_with? '..') )
321
+ next
322
+ end
323
+ if File.basename(path).start_with?('.') and !show_hidden_files
324
+ # =================================================================== #
325
+ # Ignore hidden files if the user specified so.
326
+ # =================================================================== #
327
+ next
328
+ end
329
+ index += 1
330
+ # ===================================================================== #
331
+ # Obtain the file size next, then add it onto the :total_filesize
332
+ # entry in the Hash.
333
+ # ===================================================================== #
334
+ file_size = inner_hash[:size]
335
+ name_of_owner = inner_hash[:name_of_owner]
336
+ name_of_owner = '%-10s' % owner?(name_of_owner) # Beautify this.
337
+ name_of_owner.strip!
338
+ @internal_hash[:total_filesize] += file_size.to_i # .to_i to avoid pesky nil values.
339
+ # ===================================================================== #
340
+ # Make the filesize human readable.
341
+ # ===================================================================== #
342
+ file_size = to_human_readable(file_size)
343
+ last_modified = inner_hash[:last_modified] # Example: 2021-01-11 05:53:35.844402868 +0000,
344
+ # ===================================================================== #
345
+ # All the output will be stored onto the variable called "line".
346
+ # ===================================================================== #
347
+ line = ''.dup
348
+ # ===================================================================== #
349
+ # === Index (index tag)
350
+ #
351
+ # Show the index next, if the user has enabled this.
352
+ # ===================================================================== #
353
+ if show_the_index
354
+ use_this_value_for_ljusting = 6
355
+ if _.size.to_s.size > 3
356
+ use_this_value_for_ljusting += (_.size.to_s.size - 3)
357
+ end
358
+ index_to_display = ("(#{index})") # Add () here as well.
359
+ index_to_display = index_to_display.ljust(use_this_value_for_ljusting)
360
+ if use_colours?
361
+ index_to_display.gsub!(/\((.+)\)/, '('+sfancy("\\1")+')')
362
+ end
363
+ line << index_to_display
364
+ end
365
+ # ===================================================================== #
366
+ # Add the permissions next - either in good old classical number
367
+ # format, such as 755, or as its ascii_representation.
368
+ # ===================================================================== #
369
+ if show_permission_bits
370
+ # =================================================================== #
371
+ # We update the inode-entry next to the hash.
372
+ # =================================================================== #
373
+ if show_inode?
374
+ inode = ' Inode: '
375
+ inode = simp(inode) if use_colours?
376
+ line << inode+File.stat(path).ino.to_s # Add the Inode here.
377
+ end
378
+ # =================================================================== #
379
+ # Next show the permission bits, if requested to do so.
380
+ # =================================================================== #
381
+ line << springgreen("#{return_chmod_value_of_this_file(path).ljust(5)}")
382
+ unless show_condensed_permissions
383
+ line << return_file_permission_of(
384
+ inner_hash[:ascii_representation]
385
+ ).ljust(11)
386
+ end
387
+ end
388
+ # ===================================================================== #
389
+ # === Show the modification time
390
+ #
391
+ # Add the last-modified part next.
392
+ #
393
+ # This could be last_modified.strftime(' %d.%m.%Y %H:%M') instead.
394
+ # ===================================================================== #
395
+ if show_modification_time?
396
+ line << "#{return_assumed_modification_time(last_modified)} "
397
+ end
398
+ file_size = file_size.rjust(8)
399
+ # ===================================================================== #
400
+ # Insert proper units next.
401
+ # ===================================================================== #
402
+ if colourize_kb_and_mb? && use_colours? # use .gsub directly
403
+ hash = hash_colours_for_bytes_value?
404
+ if file_size.include? ' KB'
405
+ file_size.sub!(/KB/, send(hash['KB'].to_sym, 'KB'))
406
+ elsif file_size.include? ' MB'
407
+ file_size.sub!(/MB/, send(hash['MB'].to_sym, 'MB'))
408
+ elsif file_size.include? 'GB'
409
+ file_size.sub!(/GB/, send(hash['GB'].to_sym, 'GB'))
410
+ elsif file_size.include? ' B'
411
+ file_size.sub!(/ B/, send(hash['B'].to_sym, ' B'))
412
+ end
413
+ end
414
+ # ===================================================================== #
415
+ # === Show the Owner
416
+ #
417
+ # Add the owner. Must be padded, like the group name, in order to
418
+ # prevent mis-alignments.
419
+ # ===================================================================== #
420
+ unless show_simplified?
421
+ line << " #{name_of_owner.ljust(6)}"
422
+ end
423
+ # ===================================================================== #
424
+ # === Show the Group Information
425
+ #
426
+ # Add the group, if we allow that.
427
+ # ===================================================================== #
428
+ if show_group_information?
429
+ if inner_hash and inner_hash[:name_of_group]
430
+ line << " #{inner_hash[:name_of_group].ljust(7)}"
431
+ end
432
+ end
433
+ # ===================================================================== #
434
+ # Add the file size next:
435
+ # ===================================================================== #
436
+ line << " #{file_size}"
437
+ # ===================================================================== #
438
+ # === Truncate long file names
439
+ #
440
+ # We have to check whether the filename is too long. If it is then
441
+ # we will modify a call to .shorten_file_elegantly() but only if
442
+ # the user has requested this option.
443
+ #
444
+ # Directories will be handled in a special manner.
445
+ # ===================================================================== #
446
+ if (path.size > FILE_SIZE_THRESHOLD) and truncate_long_file_names?
447
+ # dirname = File.dirname(path)
448
+ # basename = File.basename(path)[0 .. FILE_SIZE_THRESHOLD]
449
+ # path = dirname+'/'+basename
450
+ path = shorten_file_elegantly(path)
451
+ end
452
+ unless show_full_path?
453
+ path = File.basename(path)
454
+ end
455
+ if File.directory?(path) and !path.end_with?('/')
456
+ path << '/'
457
+ end
458
+ line << " #{steelblue(path)}"
459
+ if colourize_path and path.include?('/')
460
+ splitted = path.split('/')
461
+ # =================================================================== #
462
+ # The last part can be a directory, symlink or file, typically.
463
+ # =================================================================== #
464
+ last = splitted.last
465
+ if File.directory? last
466
+ last << '/' unless last.end_with?('/')
467
+ end
468
+ last = lightblue(last)
469
+ path = splitted[0..-2].join('/')+'/'+last
470
+ end
471
+ if File.symlink?(path)
472
+ if stop_on_missing_symlink? # add functionality to stop on a missing symlink.
473
+ if !File.exist?(File.readlink(path))
474
+ add ' ← FILE DOES NOT EXIST!!! STOPPING NOW!'
475
+ exit
476
+ else # ok symlink exists.
477
+ # e ' IS A SYMLINK '
478
+ end
479
+ else
480
+ line << colourize_symlink(path)
481
+ end
482
+ end
483
+ # ===================================================================== #
484
+ # Finally display the line to the user.
485
+ # ===================================================================== #
486
+ e line
487
+ }
488
+ eliner
489
+ # ======================================================================= #
490
+ # Only add the filesize if we will report it.
491
+ # ======================================================================= #
492
+ try_to_report_the_total_filesize if report_the_total_filesize?
493
+ end; alias show report # === show
494
+ alias display report # === display
495
+ alias display_result report # === display_result
496
+ alias display_content report # === display_content
497
+ alias display_listing report # === display_listing
498
+ alias do_report report # === do_report
499
+ alias display_main_string report # === display_main_string
500
+
501
+ # ========================================================================= #
502
+ # === run
503
+ # ========================================================================= #
504
+ def run
505
+ check_whether_we_use_colours
506
+ menu
507
+ report if display_content?
508
+ do_display_content # Re-toggle it again after run() is used.
509
+ end
510
+
511
+ end
512
+
513
+ # =========================================================================== #
514
+ # === DirectoryParadise.show
515
+ # =========================================================================== #
516
+ def self.show(i = ARGV)
517
+ DirectoryParadise::Report.new(i)
518
+ end; self.instance_eval { alias [] show } # === DirectoryParadise[]
519
+ self.instance_eval { alias run show } # === DirectoryParadise.run
520
+ self.instance_eval { alias do_show show } # === DirectoryParadise.do_show
521
+ self.instance_eval { alias report show } # === DirectoryParadise.report
522
+
523
+ end
524
+
525
+ if __FILE__ == $PROGRAM_NAME
526
+ DirectoryParadise::Report.new(ARGV)
527
+ end # rcontent