extracter 1.2.32

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.
@@ -0,0 +1,1069 @@
1
+ #!/usr/bin/ruby -w
2
+ # Encoding: UTF-8
3
+ # frozen_string_literal: true
4
+ # =========================================================================== #
5
+ # === Extracter::Extracter
6
+ #
7
+ # The primary purpose of this class is to abstract extracting source files
8
+ # to a target location. You just pass the argument of the file that has
9
+ # to be extracted to this class, and it should handle the rest.
10
+ #
11
+ # The class can be used to "extract" audio files as well, by calling the
12
+ # module ExtractAudio, which is part of MultimediaParadise. You can try
13
+ # this - just pass a .mp4 file as first argument to this class. Make sure
14
+ # to have installed that gem before, via: gem install multimedia_paradise
15
+ #
16
+ # Usage examples:
17
+ #
18
+ # Extracter::Extracter.new(ARGV)
19
+ # Extracter.new('foo.mp3')
20
+ # Extracter.new('xyz-1.0.tar.gz')
21
+ #
22
+ # =========================================================================== #
23
+ # require 'extracter/class/extracter.rb'
24
+ # =========================================================================== #
25
+ require 'extracter/base/base.rb'
26
+
27
+ module Extracter
28
+
29
+ class Extracter < ::Extracter::Base # === Extracter::Extracter
30
+
31
+ require 'fileutils'
32
+ require 'extracter/toplevel_methods/is_this_a_valid_archive.rb'
33
+ require 'extracter/toplevel_methods/misc.rb'
34
+ require 'extracter/version/version.rb'
35
+ require 'extracter/class/extract_this_archive.rb'
36
+
37
+ begin
38
+ require 'opn'
39
+ rescue LoadError; end
40
+
41
+ # ========================================================================= #
42
+ # === NAMESPACE
43
+ # ========================================================================= #
44
+ NAMESPACE = inspect
45
+
46
+ # ========================================================================= #
47
+ # === SHOW_ONLY_THE_SHORT_NAME_OF_THE_ARCHIVE
48
+ #
49
+ # If this constant is set to true then we will only show the shortened
50
+ # name of the archive in question by default.
51
+ # ========================================================================= #
52
+ SHOW_ONLY_THE_SHORT_NAME_OF_THE_ARCHIVE = true
53
+
54
+ # ========================================================================= #
55
+ # === initialize
56
+ #
57
+ # The first argument to this method should be the archive that the user
58
+ # wants to extract. This must be a (locally) existing archive, such as
59
+ # foobar.tar.xz or something similar.
60
+ #
61
+ # The second argument to this method, called `extract_to`, specifies the
62
+ # target location, where this class will extract the archive into, if
63
+ # available. Some keywords and shortcuts exist for this option - for
64
+ # instance, TEMP means $MY_TEMP, which can be set by the user.
65
+ #
66
+ # Specific usage example in pure Ruby:
67
+ #
68
+ # x = Extracter.what_to('pry-0.9.9.4.gem', '/home/Temp')
69
+ #
70
+ # ========================================================================= #
71
+ def initialize(
72
+ commandline_arguments = ARGV,
73
+ extract_to = nil,
74
+ run_already = true,
75
+ &block
76
+ )
77
+ register_sigint
78
+ reset
79
+ @internal_hash[:run_already] = run_already
80
+ set_commandline_arguments(
81
+ commandline_arguments
82
+ )
83
+ if debug? # Some debug-information in this case.
84
+ e "The first argument what is: `#{commandline_arguments}`"
85
+ e "The second argument where_to is: `#{extract_to}`"
86
+ end
87
+ case run_already
88
+ # ======================================================================= #
89
+ # === :dont_run_yet
90
+ # ======================================================================= #
91
+ when :dont_run_yet,
92
+ :do_not_run_yet,
93
+ :default
94
+ @internal_hash[:run_already] = false
95
+ end
96
+ set_extract_to(extract_to) if extract_to
97
+ # ======================================================================= #
98
+ # === Handle blocks next
99
+ # ======================================================================= #
100
+ if block_given?
101
+ yielded = yield
102
+ case yielded
103
+ # ===================================================================== #
104
+ # === :be_silent
105
+ # ===================================================================== #
106
+ when :be_silent,
107
+ :be_quiet
108
+ do_be_quiet
109
+ # ===================================================================== #
110
+ # === :dont_run_yet
111
+ # ===================================================================== #
112
+ when :dont_run_yet,
113
+ :do_not_run_yet,
114
+ :default
115
+ @internal_hash[:run_already] = false
116
+ # ===================================================================== #
117
+ # === :show_the_full_name_of_the_archive
118
+ # ===================================================================== #
119
+ when :show_the_full_name_of_the_archive
120
+ do_show_the_full_name_of_the_archive
121
+ end
122
+ end
123
+ run if run_already?
124
+ end
125
+
126
+ # ========================================================================= #
127
+ # === reset (reset tag)
128
+ # ========================================================================= #
129
+ def reset
130
+ super()
131
+ # ======================================================================= #
132
+ # === :try_to_use_colours
133
+ # ======================================================================= #
134
+ @internal_hash[:try_to_use_colours] = true
135
+ # ======================================================================= #
136
+ # === :colour_to_use_for_directories
137
+ # ======================================================================= #
138
+ @internal_hash[:colour_to_use_for_directories] = 'cyan'
139
+ # ======================================================================= #
140
+ # === :use_opn
141
+ # ======================================================================= #
142
+ @internal_hash[:use_opn] = true # ← Whether to use make use of Opn by default or not.
143
+ # ======================================================================= #
144
+ # === :show_the_full_name_of_the_archive
145
+ # ======================================================================= #
146
+ @internal_hash[:show_the_full_name_of_the_archive] = false
147
+ # ======================================================================= #
148
+ # === :debug
149
+ # ======================================================================= #
150
+ @internal_hash[:debug] = false
151
+ # ======================================================================= #
152
+ # === :append_this_to_the_commandline
153
+ #
154
+ # This variable can always be used to append onto the commandline.
155
+ # That way we can pass additional options to "tar", for instance.
156
+ # ======================================================================= #
157
+ @internal_hash[:append_this_to_the_commandline] = ''.dup
158
+ # ======================================================================= #
159
+ # === :namespace
160
+ #
161
+ # Specify the main namespace to be used. This setting can be modified
162
+ # at "runtime".
163
+ # ======================================================================= #
164
+ @internal_hash[:namespace] = NAMESPACE
165
+ # ======================================================================= #
166
+ # === :be_verbose
167
+ # ======================================================================= #
168
+ @internal_hash[:be_verbose] = true
169
+ # ======================================================================= #
170
+ # === :show_the_name
171
+ #
172
+ # If this variable is true then the name of the class will be shown
173
+ # on the commandline, via opn().
174
+ # ======================================================================= #
175
+ @internal_hash[:show_the_name] = false
176
+ # ======================================================================= #
177
+ # === :show_only_the_short_name_of_the_archive
178
+ # ======================================================================= #
179
+ @internal_hash[:show_only_the_short_name_of_the_archive] =
180
+ SHOW_ONLY_THE_SHORT_NAME_OF_THE_ARCHIVE
181
+ # ======================================================================= #
182
+ # === :run_simulation
183
+ # ======================================================================= #
184
+ @internal_hash[:run_simulation] = false # ← Whether to run in simulation, or for "real".
185
+ # ======================================================================= #
186
+ # === :extract_to
187
+ # ======================================================================= #
188
+ @internal_hash[:extract_to] = return_pwd
189
+ do_show_name # We will show the name usually.
190
+ prepare_the_hash_for_opn
191
+ # ======================================================================= #
192
+ # === :use_colours
193
+ # ======================================================================= #
194
+ enable_colours
195
+ end
196
+
197
+ # ========================================================================= #
198
+ # === do_not_show_name
199
+ #
200
+ # Tells us whether to use opn() or not.
201
+ # ========================================================================= #
202
+ def do_not_show_name
203
+ @internal_hash[:show_the_name] = false
204
+ end
205
+
206
+ # ========================================================================= #
207
+ # === show_the_name?
208
+ # ========================================================================= #
209
+ def show_the_name?
210
+ @internal_hash[:show_the_name]
211
+ end
212
+
213
+ # ========================================================================= #
214
+ # === check_whether_rar_is_available
215
+ #
216
+ # We try to find out whether unrar is available.
217
+ # ========================================================================= #
218
+ def check_whether_rar_is_available
219
+ is_available = false
220
+ ENV['PATH'].split(':').each {|entry|
221
+ is_available = true if File.exist? "#{entry}/unrar"
222
+ }
223
+ unless is_available
224
+ copn; e 'Sorry, unrar is not available. Please install it first.'
225
+ end
226
+ end
227
+
228
+ # ========================================================================= #
229
+ # === debug?
230
+ # ========================================================================= #
231
+ def debug?
232
+ @internal_hash[:debug]
233
+ end
234
+
235
+ # ========================================================================= #
236
+ # === run_already?
237
+ # ========================================================================= #
238
+ def run_already?
239
+ @internal_hash[:run_already]
240
+ end
241
+
242
+ # ========================================================================= #
243
+ # === enable_debug
244
+ # ========================================================================= #
245
+ def enable_debug
246
+ @internal_hash[:debug] = true
247
+ end
248
+
249
+ # ========================================================================= #
250
+ # === return_pwd
251
+ # ========================================================================= #
252
+ def return_pwd
253
+ "#{Dir.pwd}/".squeeze('/')
254
+ end
255
+
256
+ # ========================================================================= #
257
+ # === set_use_opn
258
+ # ========================================================================= #
259
+ def set_use_opn(i = true)
260
+ @internal_hash[:use_opn] = i
261
+ end
262
+
263
+ # ========================================================================= #
264
+ # === use_opn?
265
+ # ========================================================================= #
266
+ def use_opn?
267
+ @internal_hash[:use_opn]
268
+ end
269
+
270
+ # ========================================================================= #
271
+ # === set_commandline_arguments
272
+ # ========================================================================= #
273
+ def set_commandline_arguments(i = '')
274
+ i = [i].flatten.compact
275
+ @commandline_arguments = i
276
+ end
277
+
278
+ # ========================================================================= #
279
+ # === commandline_arguments?
280
+ # ========================================================================= #
281
+ def commandline_arguments?
282
+ @commandline_arguments
283
+ end
284
+
285
+ # ========================================================================= #
286
+ # === first_argument?
287
+ # ========================================================================= #
288
+ def first_argument?
289
+ @commandline_arguments.first
290
+ end; alias first? first_argument? # === first?
291
+
292
+ # ========================================================================= #
293
+ # === padded_extract_to?
294
+ # ========================================================================= #
295
+ def padded_extract_to?
296
+ " -C #{extract_to?} "
297
+ end
298
+
299
+ # ========================================================================= #
300
+ # === set_colour_for_directories
301
+ #
302
+ # Set the colour for directories to use.
303
+ # ========================================================================= #
304
+ def set_colour_for_directories(i)
305
+ @internal_hash[:colour_to_use_for_directories] = ::Colours.beautify(i)
306
+ end
307
+
308
+ # ========================================================================= #
309
+ # === extract_to?
310
+ #
311
+ # Note that this method is guaranteed to return a String.
312
+ # ========================================================================= #
313
+ def extract_to?
314
+ @internal_hash[:extract_to].to_s
315
+ end; alias source_package_location extract_to? # === source_package
316
+ alias extract_to_this_location? extract_to? # === extract_to_this_location?
317
+ alias extracted_to? extract_to? # === extracted_to?
318
+ alias extracted_path? extract_to? # === extracted_path?
319
+
320
+ # ========================================================================= #
321
+ # === opnn
322
+ #
323
+ # This variant will also check whether we should show the name or not.
324
+ # ========================================================================= #
325
+ def opnn(
326
+ use_this_hash = use_this_opn_hash?
327
+ )
328
+ if use_opn? and Object.const_defined?(:Opn) and show_the_name?
329
+ Opn.opn(use_this_hash)
330
+ end
331
+ end; alias opn opnn # === opn
332
+ alias copn opnn # === copn
333
+
334
+ # ========================================================================= #
335
+ # === use_this_opn_hash?
336
+ # ========================================================================= #
337
+ def use_this_opn_hash?
338
+ @internal_hash[:use_this_opn_hash]
339
+ end; alias main_hash? use_this_opn_hash? # === main_hash?
340
+
341
+ # ========================================================================= #
342
+ # === show_help (help tag)
343
+ #
344
+ # This method will show the available - and documented - help options
345
+ # for class Extracter.
346
+ #
347
+ # To call this method via the commandline try:
348
+ #
349
+ # extract --help
350
+ #
351
+ # ========================================================================= #
352
+ def show_help
353
+ e
354
+ opnn; e 'How to extract archives, without helper scripts?'
355
+ e
356
+ e ' tar -zxvf foobar.tar.gz # for .tar.gz'
357
+ e ' tar xvzf foobar.tgz # for .tgz'
358
+ e ' tar xvfJ foobar.tar.xz # for .tar.xz'
359
+ e ' tar jxf foobar.tar.bz2 # for .tar.bz2'
360
+ e ' tar -xf foobar.tar.bz2 # for .tbz'
361
+ e ' tar --lzip -xvf zutils-1.5.tar.lz # for .tar.lz'
362
+ e ' unsquashfs foobar-1.2.3.sxz # for .sxz'
363
+ e ' 7z x -so C:\home\x\src\htop\htop-3.0.5.tar.xz | 6z x -si -ttar # on windows'
364
+ e
365
+ opnn; e 'Furthermore, there are some commandline options '\
366
+ 'that can'
367
+ opnn; e 'be used for this class (class Extracter).'
368
+ e
369
+ e ' --to=/home/Temp # extract into the '\
370
+ 'directory /home/Temp/'
371
+ e
372
+ end
373
+
374
+ # ========================================================================= #
375
+ # === pad (pad tag)
376
+ #
377
+ # This method must be able to deal with ' ' as well as with '()'.
378
+ #
379
+ # The second character is the character that will be used for the
380
+ # padding.
381
+ # ========================================================================= #
382
+ def pad(
383
+ i, with_this_character = "'"
384
+ )
385
+ if i.include?('(') or i.include?(')')
386
+ i.tr!('(','\(')
387
+ i.tr!(')','\)') if i.include? ')'
388
+ i = pad(i, '"')
389
+ else
390
+ return with_this_character+
391
+ i+
392
+ with_this_character
393
+ end
394
+ end
395
+
396
+ # ========================================================================= #
397
+ # === namespace?
398
+ # ========================================================================= #
399
+ def namespace?
400
+ @internal_hash[:namespace]
401
+ end
402
+
403
+ # ========================================================================= #
404
+ # === set_be_verbose
405
+ #
406
+ # This sets the verbosity level of the class. Use only this method
407
+ # when you wish to modify the @be_verbose instance variable.
408
+ # ========================================================================= #
409
+ def set_be_verbose(i = false)
410
+ @internal_hash[:be_verbose] = i
411
+ end; alias set_verbosity set_be_verbose # === set_verbosity
412
+
413
+ # ========================================================================= #
414
+ # === be_verbose?
415
+ #
416
+ # Getter method for whether we will be verbose or not.
417
+ # ========================================================================= #
418
+ def be_verbose?
419
+ @internal_hash[:be_verbose]
420
+ end
421
+
422
+ # ========================================================================= #
423
+ # === register_sigint
424
+ # ========================================================================= #
425
+ def register_sigint
426
+ Signal.trap('SIGINT') {
427
+ e sfancy('Requesting a graceful exit from ')+
428
+ colour_to_use_for_directories?+
429
+ 'class Extracter'+
430
+ sfancy('. Exiting now.')
431
+ exit
432
+ }
433
+ end
434
+
435
+ # ========================================================================= #
436
+ # === colour_to_use_for_directories?
437
+ # ========================================================================= #
438
+ def colour_to_use_for_directories?
439
+ if use_colours?
440
+ return @internal_hash[:colour_to_use_for_directories]
441
+ else
442
+ return ''
443
+ end
444
+ end
445
+
446
+ # ========================================================================= #
447
+ # === do_show_the_full_name_of_the_archive
448
+ # ========================================================================= #
449
+ def do_show_the_full_name_of_the_archive
450
+ @internal_hash[:show_the_full_name_of_the_archive] = true
451
+ end
452
+
453
+ # ========================================================================= #
454
+ # === prefix_namespace_with
455
+ # ========================================================================= #
456
+ def prefix_namespace_with(i)
457
+ @internal_hash[:namespace] = "#{i}#{@internal_hash[:namespace].dup}"
458
+ update_the_main_hash # Also update the opn-hash here.
459
+ end
460
+
461
+ # ========================================================================= #
462
+ # === pad_opn_with_n_tokens
463
+ # ========================================================================= #
464
+ def pad_opn_with_n_tokens(n_tokens = nil)
465
+ if n_tokens
466
+ determine_default_opn_hash # Update this, just in case.
467
+ main_hash?.update(padding: n_tokens)
468
+ end
469
+ end; alias set_pad_opn_with_n_tokens pad_opn_with_n_tokens # === set_pad_opn_with_n_tokens
470
+
471
+ # ========================================================================= #
472
+ # === prepare_the_hash_for_opn
473
+ # ========================================================================= #
474
+ def prepare_the_hash_for_opn(
475
+ use_this_hash = {
476
+ namespace: namespace?,
477
+ use_colours: use_colours?
478
+ }
479
+ )
480
+ # ======================================================================= #
481
+ # === :use_this_opn_hash
482
+ # ======================================================================= #
483
+ @internal_hash[:use_this_opn_hash] = use_this_hash
484
+ return @internal_hash[:use_this_opn_hash]
485
+ end; alias update_the_opn_hash prepare_the_hash_for_opn # === update_the_opn_hash
486
+ alias determine_default_opn_hash prepare_the_hash_for_opn # === determine_default_opn_hash
487
+ alias determine_the_default_opn_hash prepare_the_hash_for_opn # === determine_the_default_opn_hash
488
+ alias update_the_main_hash prepare_the_hash_for_opn # === update_the_main_hash
489
+
490
+ # ========================================================================= #
491
+ # === show_only_the_short_name_of_the_archive?
492
+ # ========================================================================= #
493
+ def show_only_the_short_name_of_the_archive?
494
+ @internal_hash[:show_only_the_short_name_of_the_archive]
495
+ end
496
+
497
+ # ========================================================================= #
498
+ # === set_run_simulation
499
+ # ========================================================================= #
500
+ def set_run_simulation(i = false) # false is the default here.
501
+ @internal_hash[:run_simulation] = i
502
+ end
503
+
504
+ # ========================================================================= #
505
+ # === run_simulation=
506
+ # ========================================================================= #
507
+ def run_simulation=(i)
508
+ @internal_hash[:run_simulation] = i
509
+ end
510
+
511
+ # ========================================================================= #
512
+ # === run_simulation?
513
+ # ========================================================================= #
514
+ def run_simulation?
515
+ @internal_hash[:run_simulation]
516
+ end
517
+
518
+ # ========================================================================= #
519
+ # === strip_components
520
+ #
521
+ # The first argument to this method will determine how far "down" tar
522
+ # will strip the components.
523
+ # ========================================================================= #
524
+ def strip_components(
525
+ by_n = 1
526
+ )
527
+ @internal_hash[:append_this_to_the_commandline] <<
528
+ " --strip-components=#{by_n}"
529
+ end
530
+
531
+ # ========================================================================= #
532
+ # === do_show_name
533
+ #
534
+ # If this method is called then the class here will show the name of
535
+ # the file on the commandline, via opn().
536
+ # ========================================================================= #
537
+ def do_show_name
538
+ @internal_hash[:show_the_name] = true
539
+ end
540
+
541
+ # ========================================================================= #
542
+ # === enable_colours
543
+ # ========================================================================= #
544
+ def enable_colours
545
+ set_use_colours(true)
546
+ @internal_hash[:colour_to_use_for_directories] = cyan?
547
+ end
548
+
549
+ # ========================================================================= #
550
+ # === disable_colours
551
+ #
552
+ # Use this method if you want to disable colour-support of this class.
553
+ # ========================================================================= #
554
+ def disable_colours
555
+ set_use_colours(false)
556
+ @internal_hash[:colour_to_use_for_directories] = ''.dup
557
+ end
558
+
559
+ # ========================================================================= #
560
+ # === set_use_colours
561
+ # ========================================================================= #
562
+ def set_use_colours(i)
563
+ # ======================================================================= #
564
+ # We must also sync this towards our main Hash, for opn(). The next
565
+ # line of code achieves precisely that.
566
+ # ======================================================================= #
567
+ main_hash?.update(use_colours: i)
568
+ @internal_hash[:try_to_use_colours] = i
569
+ end
570
+
571
+ # ========================================================================= #
572
+ # === try_to_use_colours?
573
+ # ========================================================================= #
574
+ def try_to_use_colours?
575
+ @internal_hash[:try_to_use_colours]
576
+ end
577
+
578
+ # ========================================================================= #
579
+ # === remove_file_extension
580
+ # ========================================================================= #
581
+ def remove_file_extension(i)
582
+ _ = File.basename(i)
583
+ return ::Extracter.remove_archive_type(_)
584
+ end; alias remove_extension remove_file_extension # === remove_extensions
585
+ alias remove_ext remove_file_extension # === remove_ext
586
+
587
+ # ========================================================================= #
588
+ # === rds
589
+ # ========================================================================= #
590
+ def rds(i)
591
+ return i.squeeze('/') if i.respond_to? :squeeze
592
+ return i
593
+ end
594
+
595
+ # ========================================================================= #
596
+ # === set_extract_to
597
+ #
598
+ # This is the method that should be used to determine into which
599
+ # directory this class will extract archives into.
600
+ #
601
+ # Note that this target can be modified from the commandline, if
602
+ # the user wants to do so.
603
+ # ========================================================================= #
604
+ def set_extract_to(
605
+ i = :temp_dir
606
+ )
607
+ if i.is_a?(Hash) and i.empty?
608
+ i = :temp_dir
609
+ end
610
+ if i.is_a? Hash
611
+ # ===================================================================== #
612
+ # === :run_already
613
+ # ===================================================================== #
614
+ if i.has_key? :run_already
615
+ @internal_hash[:run_already] = i.delete(:run_already)
616
+ end
617
+ # ===================================================================== #
618
+ # === :prepend_this_namespace
619
+ # ===================================================================== #
620
+ if i.has_key? :prepend_this_namespace
621
+ prefix_with_this = i.delete(:prepend_this_namespace) # Get rid of it from the Hash as well.
622
+ prefix_namespace_with(prefix_with_this)
623
+ end
624
+ # ===================================================================== #
625
+ # === :use_colours
626
+ # ===================================================================== #
627
+ if i.has_key? :use_colours
628
+ set_use_colours(i.delete(:use_colours))
629
+ end
630
+ # ===================================================================== #
631
+ # === :verbosity
632
+ #
633
+ # Handle how verbose the class shall be.
634
+ # ===================================================================== #
635
+ if i.has_key? :verbosity
636
+ set_be_verbose(i.delete(:verbosity))
637
+ # ===================================================================== #
638
+ # === :be_verbose
639
+ # ===================================================================== #
640
+ elsif i.has_key? :be_verbose
641
+ set_be_verbose(i.delete(:be_verbose))
642
+ end
643
+ # ===================================================================== #
644
+ # === :append_this_to_the_commandline
645
+ # ===================================================================== #
646
+ if i.has_key? :append_this_to_the_commandline
647
+ @internal_hash[:append_this_to_the_commandline] =
648
+ i.delete(:append_this_to_the_commandline)
649
+ end
650
+ # ===================================================================== #
651
+ # === :use_opn
652
+ # ===================================================================== #
653
+ if i.has_key? :use_opn
654
+ set_use_opn(i.delete(:use_opn))
655
+ end
656
+ # ===================================================================== #
657
+ # === :pad_opn_with_n_tokens
658
+ # ===================================================================== #
659
+ if i.has_key? :pad_opn_with_n_tokens
660
+ set_pad_opn_with_n_tokens(i.delete(:pad_opn_with_n_tokens))
661
+ end
662
+ # ===================================================================== #
663
+ # === :run_simulation
664
+ # ===================================================================== #
665
+ if i.has_key? :run_simulation
666
+ set_run_simulation(i.delete(:run_simulation))
667
+ end
668
+ # ===================================================================== #
669
+ # === :use_colours
670
+ # ===================================================================== #
671
+ if i.has_key? :use_colours
672
+ set_use_colours(i.delete(use_colours))
673
+ end
674
+ # ===================================================================== #
675
+ # === :extract_to
676
+ #
677
+ # This entry point allows the user to specify another extract-to
678
+ # directory. Note that :to is treated the same way as :extract_to.
679
+ #
680
+ # This entry point must come last. The idea is that it will then
681
+ # become the new value for i.
682
+ # ===================================================================== #
683
+ if i.has_key? :extract_to
684
+ i = i.delete(:extract_to)
685
+ # ===================================================================== #
686
+ # === :to
687
+ # ===================================================================== #
688
+ elsif i.has_key? :to
689
+ i = i.delete(:to)
690
+ end
691
+ end
692
+ case i # case tag
693
+ # ======================================================================= #
694
+ # === :default
695
+ # ======================================================================= #
696
+ when :default
697
+ i = return_pwd
698
+ # ======================================================================= #
699
+ # === TEMP
700
+ # ======================================================================= #
701
+ when 'TEMP',
702
+ 'MY_TEMP',
703
+ 'MYTEMP',
704
+ :temp_dir,
705
+ nil
706
+ i = TEMP_DIR
707
+ end
708
+ i = rds(i)
709
+ i.gsub!(/--to=/,'') if i.include? '--to='
710
+ i = i.to_s.dup # We expect a String most definitely.
711
+ @internal_hash[:extract_to] = i
712
+ end; alias set_extract_to_this_location set_extract_to # === set_extract_to_this_location
713
+ alias extract_to= set_extract_to # === extract_to=
714
+ alias extract_to set_extract_to # === extract_to
715
+
716
+ # ========================================================================= #
717
+ # === try_to_extract_this_iso_file
718
+ # ========================================================================= #
719
+ def try_to_extract_this_iso_file(i)
720
+ opnn; e 'Extracting an .iso file is a bit more complicated '\
721
+ 'than extracting a .tar.gz tarball'
722
+ opnn; e 'archive. This class will first create a helper '\
723
+ 'directory; then mount the .iso there,'
724
+ opnn; e 'then copy the content to the main directory.'
725
+ helper_directory = File.dirname(i)+
726
+ '/READ_ONLY_DIRECTORY_'+
727
+ File.basename(
728
+ i.delete_suffix(File.extname(i))
729
+ )+
730
+ '/'
731
+ mkdir(helper_directory) unless File.directory? helper_directory
732
+ esystem 'mount -o loop '+i+' '+helper_directory
733
+ e 'The helper directory in use is '\
734
+ '`'+sdir(File.absolute_path(helper_directory))+'`.'
735
+ main_directory = File.dirname(i)+
736
+ '/'+
737
+ File.basename(
738
+ i.delete_suffix(File.extname(i))
739
+ )+
740
+ '/'
741
+ e 'Next creating the main directory at `'+sdir(main_directory)+'`.'
742
+ mkdir(main_directory) unless File.directory? main_directory
743
+ e 'Next copying the content of the helper directory recursively '
744
+ e 'from `'+sdir(helper_directory)+'`'
745
+ e 'onto `'+sdir(
746
+ main_directory+File.basename(helper_directory)+'/'
747
+ )+'`.'
748
+ cpr(
749
+ helper_directory,
750
+ main_directory+File.basename(helper_directory)+'/'
751
+ )
752
+ a = main_directory+File.basename(helper_directory)+'/'
753
+ e 'Relocating the files next from:'
754
+ e
755
+ e " #{sdir(a)}"
756
+ e
757
+ Dir[a+'*'].each {|entry|
758
+ mv(
759
+ entry,
760
+ main_directory
761
+ )
762
+ }
763
+ # ======================================================================= #
764
+ # And remove the directory:
765
+ # ======================================================================= #
766
+ remove_this_directory(a)
767
+ e 'The content of the extracted (or rather, mounted) archive is:'
768
+ e
769
+ pp Dir["#{main_directory}*"]
770
+ e
771
+ end
772
+
773
+ # ========================================================================= #
774
+ # === work_on_the_given_input
775
+ # ========================================================================= #
776
+ def work_on_the_given_input(
777
+ array = commandline_arguments?,
778
+ extract_to = extract_to?
779
+ )
780
+ # ======================================================================= #
781
+ # If the user supplied a directory then a random entry will be grabbed
782
+ # from said directory.
783
+ # ======================================================================= #
784
+ if array.is_a?(String) and File.directory?(array)
785
+ array = Dir[rds("#{array}/")+'*'].sample
786
+ end
787
+ case extract_to
788
+ when nil
789
+ extract_to = extract_to?
790
+ end
791
+ if array.empty?
792
+ opnn; e 'No archive (input) was provided. Please provide the file'
793
+ opnn; e 'that is to be extracted.'
794
+ else
795
+ array.each {|this_file|
796
+ # =================================================================== #
797
+ # Create the directory if it does not yet exist.
798
+ # =================================================================== #
799
+ create_directory(extract_to) unless File.directory?(extract_to)
800
+ # =================================================================== #
801
+ # Handle the case when the user did input a number.
802
+ # =================================================================== #
803
+ begin
804
+ if this_file =~ /^\d$/
805
+ this_file = Dir['*'][( this_file.to_i - 1 )] unless File.exist?(this_file)
806
+ end
807
+ rescue ArgumentError => error
808
+ e 'Error for '+sfancy(this_file)+':'
809
+ pp error
810
+ end
811
+ # =================================================================== #
812
+ # If the user supplied a directory then a random entry will be
813
+ # grabbed from said directory.
814
+ #
815
+ # Usage example:
816
+ #
817
+ # rubyextracter /home/x/src/htop/
818
+ #
819
+ # =================================================================== #
820
+ if File.directory? this_file
821
+ this_file = Dir[rds("#{this_file}/")+'*'].sample
822
+ end
823
+ extract_this_archive(this_file, extract_to)
824
+ report_to_the_user(this_file, extract_to)
825
+ }
826
+ end
827
+ end
828
+
829
+ # ========================================================================= #
830
+ # === create_directory (mkdir tag)
831
+ #
832
+ # Use this to create directories.
833
+ # ========================================================================= #
834
+ def create_directory(i)
835
+ FileUtils.mkdir_p(i) unless File.directory?(i)
836
+ end; alias mkdir create_directory # === mkdir
837
+
838
+ # ========================================================================= #
839
+ # === notify_the_user_that_this_extension_has_not_been_registered_yet
840
+ # ========================================================================= #
841
+ def notify_the_user_that_this_extension_has_not_been_registered_yet(i)
842
+ opnn; e "The archive at `#{i}` is #{tomato('not')}"
843
+ opnn; e "registered as a permissive extension."
844
+ fail_message_not_registered(i)
845
+ end
846
+
847
+ # ========================================================================= #
848
+ # === fail_message_not_registered
849
+ #
850
+ # Output a fail message when the archive format is not registered.
851
+ # ========================================================================= #
852
+ def fail_message_not_registered(i)
853
+ copn; e "#{rev}Can not extract `#{sfancy(i)}#{rev}` - it is "\
854
+ "not registered."
855
+ end
856
+
857
+ # ========================================================================= #
858
+ # === try_to_extract_this_img_file
859
+ # ========================================================================= #
860
+ def try_to_extract_this_img_file(i)
861
+ opnn; e 'Handling a squashfs .img file format next:'
862
+ name_without_extension = i.delete_suffix(File.extname(i))
863
+ mkdir(name_without_extension) unless File.directory? name_without_extension
864
+ esystem "mount -o loop -t squashfs #{i} #{name_without_extension}"
865
+ e 'The content of the extracted (or rather, mounted) archive is:'
866
+ pp Dir["#{name_without_extension}*"]
867
+ end
868
+
869
+ # ========================================================================= #
870
+ # === menu (menu tag)
871
+ # ========================================================================= #
872
+ def menu(
873
+ i = commandline_arguments?
874
+ )
875
+ if i.is_a? Array
876
+ i.each {|entry| menu(entry) }
877
+ else
878
+ case i
879
+ # ===================================================================== #
880
+ # === --help
881
+ # ===================================================================== #
882
+ when /^-?-?help$/i
883
+ show_help
884
+ exit
885
+ end
886
+ end
887
+ end
888
+
889
+ # ========================================================================= #
890
+ # === esystem (system tag, esystem tag)
891
+ # ========================================================================= #
892
+ def esystem(
893
+ i, try_to_use_colours = try_to_use_colours?
894
+ )
895
+ i = i.dup if i.frozen?
896
+ # ======================================================================= #
897
+ # Next, consider appending something onto the commandline.
898
+ # ======================================================================= #
899
+ _ = @internal_hash[:append_this_to_the_commandline]
900
+ unless _.empty?
901
+ if i.include? ' '
902
+ splitted = i.split(' ')
903
+ splitted[0] << " #{_}"
904
+ i = splitted.join(' ')
905
+ else
906
+ i << " #{_}"
907
+ end
908
+ end
909
+ if run_simulation?
910
+ copn; e 'As we are running in simulation mode, the following command '
911
+ copn; e 'is the one that we would have been used if we were to not run '
912
+ copn; e 'in simulation mode:'
913
+ if be_verbose?
914
+ if try_to_use_colours
915
+ e steelblue(i)
916
+ else
917
+ e i
918
+ end
919
+ end
920
+ else
921
+ if be_verbose?
922
+ if try_to_use_colours
923
+ e steelblue(i)
924
+ else
925
+ e i
926
+ end
927
+ end
928
+ # ===================================================================== #
929
+ # Next, run the sys-command.
930
+ # ===================================================================== #
931
+ begin
932
+ system i
933
+ # =================================================================== #
934
+ # We have to rescue here because unrar might not be available and
935
+ # so on.
936
+ # =================================================================== #
937
+ rescue Exception => error
938
+ e 'An error has happened upon attempting to run this system command:'
939
+ e
940
+ e " #{i}"
941
+ e
942
+ pp error
943
+ e '-----------'
944
+ pp error.class
945
+ e '-----------'
946
+ end
947
+ end
948
+ end; alias run_this_system_command esystem # === run_this_system_command
949
+
950
+ # ========================================================================= #
951
+ # === report_to_the_user
952
+ #
953
+ # This method reports to the user. Usually this is done only via this
954
+ # file here though.
955
+ # ========================================================================= #
956
+ def report_to_the_user(
957
+ i,
958
+ extract_to = extract_to?
959
+ )
960
+ if be_verbose?
961
+ target = extract_to+
962
+ remove_file_extension(
963
+ File.basename(i)
964
+ )+
965
+ '/'
966
+ opnn; e "#{rev}Finished extracting to `"\
967
+ "#{sdir(target)}#{rev}`." # This is an Array.
968
+ end
969
+ end
970
+
971
+ # ========================================================================= #
972
+ # === be_verbose
973
+ # ========================================================================= #
974
+ def be_verbose
975
+ set_be_verbose(true)
976
+ end
977
+
978
+ # ========================================================================= #
979
+ # === do_be_quiet
980
+ # ========================================================================= #
981
+ def do_be_quiet
982
+ set_be_verbose(false)
983
+ end; alias be_silent do_be_quiet # === be_silent
984
+ alias be_quiet do_be_quiet # === be_quiet
985
+
986
+ # ========================================================================= #
987
+ # === run (run tag, def tag)
988
+ # ========================================================================= #
989
+ def run
990
+ menu
991
+ work_on_the_given_input
992
+ end
993
+
994
+ # ========================================================================= #
995
+ # === Extracter::Extracter.extract_this
996
+ #
997
+ # This method provides a convenient API to extract something to a
998
+ # specified directory, as a class method. It defaults to the
999
+ # current working directory, as that is by far the most convenient
1000
+ # way to extract a source tarball/archive.
1001
+ #
1002
+ # ========================================================================= #
1003
+ def self.extract_this(
1004
+ i = ARGV,
1005
+ to = {}, # This may also be a String rather than a Hash.
1006
+ &block
1007
+ )
1008
+ ::Extracter::Extracter.new(ARGV, to, &block)
1009
+ end; self.instance_eval { alias what_to extract_this } # === Extracter::Extracter.what_to
1010
+ self.instance_eval { alias extract extract_this } # === Extracter::Extracter.extract
1011
+ self.instance_eval { alias extract_what_to extract_this } # === Extracter::Extracter.extract_what_to
1012
+
1013
+ # ========================================================================= #
1014
+ # === Extracter::Extracter[]
1015
+ # ========================================================================= #
1016
+ def self.[](i = ARGV, extract_where_to = Dir.pwd)
1017
+ new(i, extract_where_to)
1018
+ end
1019
+
1020
+ end
1021
+
1022
+ # ========================================================================= #
1023
+ # === Extracter.extract_what_to
1024
+ #
1025
+ # Useage example goes like this:
1026
+ #
1027
+ # Extracter.extract_what_to('foo-1.0.tar.xz', '/tmp')
1028
+ # Extracter.extract_what_to('/Depot/jjjj/tesseract-5.1.0.tar.xz', Dir.pwd+'/')
1029
+ #
1030
+ # ========================================================================= #
1031
+ def self.extract_what_to(
1032
+ what = ARGV,
1033
+ extract_to = :default, # ← This can also be a Hash. It denotes where we want to extract to.
1034
+ run_already = true, # :do_not_run_yet,
1035
+ &block
1036
+ )
1037
+ _ = ::Extracter::Extracter.new(
1038
+ what,
1039
+ extract_to,
1040
+ run_already,
1041
+ &block
1042
+ )
1043
+ return _ # We must return the class, as other projects may depend on this.
1044
+ end; self.instance_eval { alias extract_this extract_what_to } # === Extracter.extract_this
1045
+ self.instance_eval { alias extract extract_what_to } # === Extracter.extract
1046
+ self.instance_eval { alias what_to extract_what_to } # === Extracter.what_to
1047
+ self.instance_eval { alias new extract_what_to } # === Extracter.new
1048
+ self.instance_eval { alias [] extract_what_to } # === Extracter[]
1049
+
1050
+ end
1051
+
1052
+ if __FILE__ == $PROGRAM_NAME
1053
+ _ = Extracter::Extracter.new(ARGV) { :do_not_run_yet }
1054
+ if ARGV.size > 2
1055
+ _ = Extracter::Extracter.new(ARGV, :default) { :do_not_run_yet }
1056
+ else
1057
+ _ = Extracter::Extracter.new(ARGV[0], ARGV[1]) { :do_not_run_yet }
1058
+ end
1059
+ # _.enable_debug
1060
+ _.be_verbose
1061
+ # _.strip_components # This would be equivalent to: --strip-components=1
1062
+ _.run
1063
+ end # rubyextracter
1064
+ # extracter
1065
+ # extracter htop-1.0.2.tar.xz
1066
+ # extracter xfig-3.2.5.tar.bz2
1067
+ # extract htop* /Depot/
1068
+ # extract recode-3.7.tar.xz /Depot/
1069
+ # extract qt-4.8.6.tar.xz --to=/home/Temp