extracter 1.2.32

Sign up to get free protection for your applications and to get access to all the features.
@@ -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