directory_paradise 1.4.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

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