backup_paradise 1.3.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (48) hide show
  1. checksums.yaml +7 -0
  2. data/README.md +452 -0
  3. data/backup_paradise.gemspec +50 -0
  4. data/bin/backup_for_ingrid +10 -0
  5. data/bin/backup_paradise +7 -0
  6. data/bin/windows_backup_paradise +9 -0
  7. data/doc/README.gen +390 -0
  8. data/doc/TODO.md +130 -0
  9. data/img/BackupParadise_Logo.png +0 -0
  10. data/lib/backup_paradise/actions/README.md +2 -0
  11. data/lib/backup_paradise/actions/backup.rb +62 -0
  12. data/lib/backup_paradise/base/base.rb +529 -0
  13. data/lib/backup_paradise/base/colours.rb +137 -0
  14. data/lib/backup_paradise/base/namespace.rb +16 -0
  15. data/lib/backup_paradise/base/tab.rb +47 -0
  16. data/lib/backup_paradise/colours/colours.rb +88 -0
  17. data/lib/backup_paradise/constants/constants.rb +162 -0
  18. data/lib/backup_paradise/gui/glimmer/libui/backup_for_ingrid/backup_for_ingrid.rb +87 -0
  19. data/lib/backup_paradise/gui/gtk2/OLD_backup.rb +165 -0
  20. data/lib/backup_paradise/gui/libui/backup_for_ingrid/backup_for_ingrid.rb +99 -0
  21. data/lib/backup_paradise/gui/shared_code/simple_backup_widget/simple_backup_widget_module.rb +0 -0
  22. data/lib/backup_paradise/gui/tk/backup.rb +108 -0
  23. data/lib/backup_paradise/gui/universal_widgets/simple_backup_widget/simple_backup_widget.rb +921 -0
  24. data/lib/backup_paradise/images/BACKUP_IMAGE.png +0 -0
  25. data/lib/backup_paradise/images/right_arrow.png +0 -0
  26. data/lib/backup_paradise/project/project.rb +40 -0
  27. data/lib/backup_paradise/requires/require_the_backup_paradise_project.rb +18 -0
  28. data/lib/backup_paradise/requires/require_yaml.rb +7 -0
  29. data/lib/backup_paradise/tab/tab.rb +87 -0
  30. data/lib/backup_paradise/toplevel_methods/cliner.rb +16 -0
  31. data/lib/backup_paradise/toplevel_methods/config.rb +86 -0
  32. data/lib/backup_paradise/toplevel_methods/create_and_remove.rb +63 -0
  33. data/lib/backup_paradise/toplevel_methods/e.rb +16 -0
  34. data/lib/backup_paradise/toplevel_methods/esystem.rb +19 -0
  35. data/lib/backup_paradise/toplevel_methods/files_and_directories.rb +181 -0
  36. data/lib/backup_paradise/toplevel_methods/help.rb +93 -0
  37. data/lib/backup_paradise/toplevel_methods/misc.rb +153 -0
  38. data/lib/backup_paradise/toplevel_methods/mountpoint.rb +188 -0
  39. data/lib/backup_paradise/toplevel_methods/opnn.rb +27 -0
  40. data/lib/backup_paradise/utility_scripts/backup/backup.rb +1942 -0
  41. data/lib/backup_paradise/version/version.rb +19 -0
  42. data/lib/backup_paradise/windows/README.md +1 -0
  43. data/lib/backup_paradise/windows/windows.rb +101 -0
  44. data/lib/backup_paradise/www/backup.cgi +63 -0
  45. data/lib/backup_paradise/yaml/config.yml +82 -0
  46. data/lib/backup_paradise.rb +5 -0
  47. data/test/testing_toplevel_functionality.rb +11 -0
  48. metadata +192 -0
@@ -0,0 +1,1942 @@
1
+ #!/usr/bin/ruby -w
2
+ # Encoding: UTF-8
3
+ # frozen_string_literal: true
4
+ # =========================================================================== #
5
+ # === BackupParadise::Backup
6
+ #
7
+ # This is the main class that will be used for making a backup, usually
8
+ # onto an external USB device, but optionally also to another (second)
9
+ # harddisc (HDD).
10
+ #
11
+ # Note that this class will still store some information on the toplevel
12
+ # namespace where we will backup to.
13
+ #
14
+ # For a listing of specific options have a look at the file "help.rb",
15
+ # or do "rbackup help" from the commandline.
16
+ #
17
+ # Usage example:
18
+ #
19
+ # BackupParadise::Backup.new(ARGV)
20
+ #
21
+ # =========================================================================== #
22
+ # require 'backup_paradise/utility_scripts/backup/backup.rb'
23
+ # BackupParadise::Backup.new(hash)
24
+ # =========================================================================== #
25
+ require 'backup_paradise/base/base.rb'
26
+
27
+ module BackupParadise
28
+
29
+ class Backup < ::BackupParadise::Base # === BackupParadise::Backup
30
+
31
+ require 'backup_paradise/toplevel_methods/config.rb'
32
+ require 'backup_paradise/toplevel_methods/help.rb'
33
+ require 'backup_paradise/toplevel_methods/mountpoint.rb'
34
+ require 'backup_paradise/version/version.rb'
35
+
36
+ # ========================================================================= #
37
+ # === NAMESPACE
38
+ # ========================================================================= #
39
+ NAMESPACE = inspect
40
+
41
+ # ========================================================================= #
42
+ # === MINIMAL_FILESIZE
43
+ # ========================================================================= #
44
+ MINIMAL_FILESIZE = 5 * (1000 ** 3) # 5 * 1024 * 1024 * 1024
45
+
46
+ # ========================================================================= #
47
+ # === FILE_BACKUP_LOG
48
+ #
49
+ # Denote where to keep the backup.log file, if we log that is.
50
+ # ========================================================================= #
51
+ if File.directory? '/home/Temp/'
52
+ FILE_BACKUP_LOG = '/home/Temp/backup.log'
53
+ else
54
+ FILE_BACKUP_LOG = '/tmp/backup.log'
55
+ end
56
+
57
+ # ========================================================================= #
58
+ # === TRY_TO_SHOW_BACKUP_COMPLETE_MESSAGE_VIA_LIBUI
59
+ #
60
+ # If the following constant is true then this class will try to make
61
+ # use of libui and the libui_paradise gem to show a little libui
62
+ # message box (a window) about how the backup action is now
63
+ # complete.
64
+ # ========================================================================= #
65
+ TRY_TO_SHOW_BACKUP_COMPLETE_MESSAGE_VIA_LIBUI = true
66
+
67
+ # ========================================================================= #
68
+ # === initialize
69
+ #
70
+ # Invocation example:
71
+ #
72
+ # x = BackupParadise::Backup.new(nil, :do_not_run_yet)
73
+ #
74
+ # ========================================================================= #
75
+ def initialize(
76
+ commandline_arguments = nil,
77
+ run_already = true,
78
+ &block
79
+ )
80
+ register_sigint
81
+ reset
82
+ if commandline_arguments
83
+ if commandline_arguments.is_a?(Symbol)
84
+ case commandline_arguments
85
+ # =================================================================== #
86
+ # === :do_not_run_yet
87
+ # =================================================================== #
88
+ when :do_not_run_yet
89
+ run_already = false
90
+ end
91
+ else
92
+ set_commandline_arguments(
93
+ commandline_arguments
94
+ )
95
+ end
96
+ end
97
+ case run_already
98
+ # ======================================================================= #
99
+ # === :do_not_run_yet
100
+ # ======================================================================= #
101
+ when :do_not_run_yet
102
+ run_already = false
103
+ end
104
+ # ======================================================================= #
105
+ # === Handle blocks given next
106
+ # ======================================================================= #
107
+ if block_given?
108
+ yielded = yield
109
+ case yielded
110
+ # ===================================================================== #
111
+ # === :do_not_run_yet
112
+ # ===================================================================== #
113
+ when :do_not_run_yet
114
+ run_already = false
115
+ # ===================================================================== #
116
+ # === :we_are_on_windows
117
+ # ===================================================================== #
118
+ when :we_are_on_windows
119
+ @internal_hash[:are_we_on_windows] = true
120
+ end
121
+ end
122
+ run if run_already
123
+ end
124
+
125
+ # ========================================================================= #
126
+ # === reset (reset tag)
127
+ # ========================================================================= #
128
+ def reset
129
+ super()
130
+ # ======================================================================= #
131
+ # === @internal_hash
132
+ # ======================================================================= #
133
+ @internal_hash = {}
134
+ # ======================================================================= #
135
+ # === :mountpoint
136
+ # ======================================================================= #
137
+ @internal_hash[:mountpoint] = nil
138
+ # ======================================================================= #
139
+ # === :simplify_the_directory_layout
140
+ #
141
+ # If the following variable is set to true then this means that the
142
+ # target directory will be slightly simplified. There will not be
143
+ # any ':' characters; these will become '_' characters.
144
+ #
145
+ # This was necessary because windows NTFS seems to struggle with
146
+ # ':' characters.
147
+ # ======================================================================= #
148
+ @internal_hash[:simplify_the_directory_layout] = true
149
+ # ======================================================================= #
150
+ # === :perform_backup
151
+ #
152
+ # The next variable determines whether we will perform a backup
153
+ # job or not. By default this will be false - it will be set
154
+ # to true through the menu() interface, via its else clause.
155
+ # ======================================================================= #
156
+ @internal_hash[:perform_backup] = true
157
+ # ======================================================================= #
158
+ # === :are_we_on_windows
159
+ #
160
+ # This can be used to overrule any other windows-specific checks.
161
+ # ======================================================================= #
162
+ @internal_hash[:are_we_on_windows] = nil
163
+ # ======================================================================= #
164
+ # === :date
165
+ # ======================================================================= #
166
+ @internal_hash[:date] = dd_mm_yyyy
167
+ # ======================================================================= #
168
+ # === :show_popup_notification
169
+ # ======================================================================= #
170
+ @internal_hash[:show_popup_notification] =
171
+ BackupParadise.show_popup_notification?
172
+ # ======================================================================= #
173
+ # === :last_backup_directory
174
+ # ======================================================================= #
175
+ @internal_hash[:last_backup_directory] = nil
176
+ # ======================================================================= #
177
+ # === :array_store_times
178
+ #
179
+ # The next Array will keep track of how long it took to backup
180
+ # the data.
181
+ # ======================================================================= #
182
+ @internal_hash[:array_store_times] = []
183
+ # ======================================================================= #
184
+ # === :use_this_as_timestamp
185
+ #
186
+ # The next variable will keep the timestamp as-is.
187
+ #
188
+ # This may include ':' characters, which Windows NTFS does not seem
189
+ # to like. Thus, since as of September 2020, a slightly simpler
190
+ # variant is used here.
191
+ # ======================================================================= #
192
+ determine_the_current_timestamp
193
+ # ======================================================================= #
194
+ # === :backup_these_directories
195
+ #
196
+ # Determine the directories that we wish to back up.
197
+ # ======================================================================= #
198
+ @internal_hash[:backup_these_directories] = all_important_directories?
199
+ end
200
+
201
+ # ========================================================================= #
202
+ # === start_the_gtk3_bindings
203
+ #
204
+ # To invoke this method, try:
205
+ #
206
+ # rbackup --gui
207
+ # rbackup --gtk
208
+ #
209
+ # ========================================================================= #
210
+ def start_the_gtk3_bindings
211
+ require 'backup_paradise/gui/gtk3/simple_backup_widget/simple_backup_widget.rb'
212
+ BackupParadise::GUI::Gtk::SimpleBackupWidget.run
213
+ end
214
+
215
+ # ========================================================================= #
216
+ # === default_tab_title
217
+ # ========================================================================= #
218
+ def default_tab_title
219
+ tab_title('Backup is complete!')
220
+ end
221
+
222
+ # ========================================================================= #
223
+ # === backup_which_directories?
224
+ # ========================================================================= #
225
+ def backup_which_directories?
226
+ @internal_hash[:backup_these_directories]
227
+ end
228
+
229
+ # ========================================================================= #
230
+ # === return_this_absolute_directory
231
+ # ========================================================================= #
232
+ def return_this_absolute_directory(i)
233
+ i = case i
234
+ # ======================================================================= #
235
+ # === DATA_DIRECTORY
236
+ # ======================================================================= #
237
+ when 'DATA_DIRECTORY'
238
+ DATA_DIRECTORY
239
+ # ======================================================================= #
240
+ # === SRC_DIRECTORY
241
+ # ======================================================================= #
242
+ when 'SRC_DIRECTORY',
243
+ 'SOURCE_DIRECTORY'
244
+ SOURCE_DIRECTORY
245
+ # ======================================================================= #
246
+ # === STUDIUM_DIRECTORY
247
+ # ======================================================================= #
248
+ when 'STUDIUM_DIRECTORY'
249
+ STUDIUM_DIRECTORY
250
+ else
251
+ i
252
+ end
253
+ i
254
+ end
255
+
256
+ # ========================================================================= #
257
+ # === return_the_songs_directory
258
+ # ========================================================================= #
259
+ def return_the_songs_directory
260
+ DIRECTORY_CONTAINING_ALL_SONGS
261
+ end
262
+
263
+ # ========================================================================= #
264
+ # === show_help
265
+ # ========================================================================= #
266
+ def show_help
267
+ BackupParadise.show_help
268
+ end; alias display_help show_help # === display_help
269
+
270
+ # ========================================================================= #
271
+ # === simplify_the_directory_layout?
272
+ # ========================================================================= #
273
+ def simplify_the_directory_layout?
274
+ @internal_hash[:simplify_the_directory_layout]
275
+ end
276
+
277
+ # ========================================================================= #
278
+ # === set_commandline_arguments
279
+ # ========================================================================= #
280
+ def set_commandline_arguments(i = ARGV)
281
+ @commandline_arguments = i
282
+ end
283
+
284
+ # ========================================================================= #
285
+ # === commandline_arguments?
286
+ # ========================================================================= #
287
+ def commandline_arguments?
288
+ @commandline_arguments
289
+ end
290
+
291
+ # ========================================================================= #
292
+ # === first_argument?
293
+ # ========================================================================= #
294
+ def first_argument?
295
+ @commandline_arguments.first
296
+ end; alias first? first_argument? # === first?
297
+
298
+ # ========================================================================= #
299
+ # === determine_whether_the_target_harddisc_is_a_ntfs_system
300
+ # ========================================================================= #
301
+ def determine_whether_the_target_harddisc_is_a_ntfs_system
302
+ if is_target_harddisc_a_ntfs_system?
303
+ do_use_simplified_directory
304
+ end
305
+ end
306
+
307
+ # ========================================================================= #
308
+ # === return_the_assumed_mountpoint_from_this_input
309
+ # ========================================================================= #
310
+ def return_the_assumed_mountpoint_from_this_input(i)
311
+ BackupParadise.return_the_assumed_mountpoint_from_this_input(i)
312
+ end
313
+
314
+ # ========================================================================= #
315
+ # === set_mountpoint
316
+ # ========================================================================= #
317
+ def set_mountpoint(i)
318
+ i = i.dup
319
+ if BackupParadise.is_this_a_shortcut?(i)
320
+ i = return_the_assumed_mountpoint_from_this_input(i)
321
+ end
322
+ i = i.dup if i.frozen?
323
+ i << '/' unless i.end_with? '/'
324
+ @internal_hash[:mountpoint] = i
325
+ # ======================================================================= #
326
+ # Sync it back to the toplevel as well:
327
+ # ======================================================================= #
328
+ determine_the_target_mountpoint(@internal_hash[:mountpoint])
329
+ determine_where_to_backup_to_exactly
330
+ end; alias set_backup_to_this_target set_mountpoint # === set_backup_to_this_target
331
+ alias set_target_mountpoint set_mountpoint # === set_target_mountpoint
332
+
333
+ # ========================================================================= #
334
+ # === determine_the_current_timestamp
335
+ # ========================================================================= #
336
+ def determine_the_current_timestamp
337
+ if @internal_hash[:simplify_the_directory_layout]
338
+ @internal_hash[:use_this_as_timestamp] =
339
+ "#{date?}-#{current_time.tr(':','_')}"
340
+ else
341
+ @internal_hash[:use_this_as_timestamp] =
342
+ "#{date?}-#{current_time}"
343
+ end
344
+ end
345
+
346
+ # ========================================================================= #
347
+ # === date?
348
+ # ========================================================================= #
349
+ def date?
350
+ @internal_hash[:date]
351
+ end
352
+
353
+ # ========================================================================= #
354
+ # === use_this_as_timestamp?
355
+ # ========================================================================= #
356
+ def use_this_as_timestamp?
357
+ @internal_hash[:use_this_as_timestamp]
358
+ end
359
+
360
+ # ========================================================================= #
361
+ # === sanitize_the_commandline_arguments
362
+ #
363
+ # This method will try to make sense of the passed arguments.
364
+ # ========================================================================= #
365
+ def sanitize_the_commandline_arguments(
366
+ hash = commandline_arguments?
367
+ )
368
+ copy = hash.dup
369
+ # ======================================================================= #
370
+ # === :commandline_arguments
371
+ # ======================================================================= #
372
+ if hash.is_a?(Hash) and hash.has_key?(:commandline_arguments)
373
+ hash[:commandline_arguments].each {|entry|
374
+ if BackupParadise.is_this_a_shortcut?(entry)
375
+ copy[:backup_to_this_target] =
376
+ BackupParadise.return_the_assumed_mountpoint_from_this_input(entry)
377
+ copy[:commandline_arguments].reject! {|inner_entry|
378
+ inner_entry == entry
379
+ }
380
+ end
381
+ }
382
+ set_commandline_arguments(copy)
383
+ end
384
+ end
385
+
386
+ # ========================================================================= #
387
+ # === can_not_backup_this_directory_as_it_does_not_exist
388
+ # ========================================================================= #
389
+ def can_not_backup_this_directory_as_it_does_not_exist(i)
390
+ opne "Can not backup the directory at #{sdir(i)}"
391
+ opne 'as it does not exist.'
392
+ end
393
+
394
+ # ========================================================================= #
395
+ # === try_to_unmount_the_device
396
+ #
397
+ # This method can be used to automatically unmount the target device
398
+ # again.
399
+ # ========================================================================= #
400
+ def try_to_unmount_the_device
401
+ this_is_the_mounted_device = backup_to_this_directory?
402
+ # ======================================================================= #
403
+ # Change directory to another directory where we can safely
404
+ # umount the directory.
405
+ # ======================================================================= #
406
+ if has_superuser_abilities?
407
+ if BackupParadise.target_mountpoint?.include?('HDD1')
408
+ # =================================================================== #
409
+ # Unmount harddiscs quickly.
410
+ # =================================================================== #
411
+ unmount :hdd # Since as of 17.06.2008 we will unmount the harddisc as well.
412
+ end
413
+ if File.directory? '/Depot/j/'
414
+ cd '/Depot/j/'
415
+ elsif File.directory? '/tmp'
416
+ cd '/tmp'
417
+ elsif File.directory? '/home/Temp'
418
+ cd '/home/Temp'
419
+ else
420
+ cd '/'
421
+ end
422
+ opne "Next unmounting the device at "\
423
+ "`#{sfancy(this_is_the_mounted_device)}`."
424
+ system "umount #{this_is_the_mounted_device}"
425
+ end
426
+ end
427
+
428
+ # ========================================================================= #
429
+ # === consider_renaming_all_old_last_backup_directories
430
+ #
431
+ # This will rename all "last_directory*" directory entries to their
432
+ # corresponding equivalent without the leading 'last_' string.
433
+ # ========================================================================= #
434
+ def consider_renaming_all_old_last_backup_directories
435
+ # ======================================================================= #
436
+ # First grab all possible entries, and check that these are all existing
437
+ # directories. If there is at the least one entry we will continue to
438
+ # operate on it.
439
+ # ======================================================================= #
440
+ all_possible_entries = Dir["#{mount_target?}last_backup-*"].select {|entry|
441
+ File.directory?(entry)
442
+ }
443
+ if all_possible_entries.size > 0
444
+ # ===================================================================== #
445
+ # Batch-rename these directories in that case:
446
+ # ===================================================================== #
447
+ all_possible_entries.each {|this_directory|
448
+ new_name_of_the_new_target_directory = this_directory.sub(/^last_/,'')
449
+ opne "#{rev}Now renaming `#{sdir(this_directory)}#{rev}` "\
450
+ "to `#{sdir(new_name_of_the_new_target_directory)}#{rev}`."
451
+ rename(this_directory, new_name_of_the_new_target_directory)
452
+ }
453
+ end
454
+ end
455
+
456
+ # ========================================================================= #
457
+ # === verbose_create_a_directory_at_this_position
458
+ #
459
+ # The first argument to this method should be the target directory,
460
+ # a path, that is where you wish to create that directory.
461
+ #
462
+ # The second argument to this method, which is optional, denotes the
463
+ # permission that is to be used.
464
+ # ========================================================================= #
465
+ def verbose_create_a_directory_at_this_position(
466
+ this_position, use_this_permission = 0754
467
+ )
468
+ e "Creating a directory at `#{sdir(this_position)}` next."
469
+ mkdir(this_position, use_this_permission)
470
+ end
471
+
472
+ # ========================================================================= #
473
+ # === show_the_logfile
474
+ #
475
+ # To invoke this method from the commandline, try:
476
+ #
477
+ # advanced_backup --logfile?
478
+ #
479
+ # ========================================================================= #
480
+ def show_the_logfile
481
+ _ = FILE_BACKUP_LOG
482
+ if File.exist? _
483
+ opne "Now reading the dataset from the file `#{sfile(_)}`:"
484
+ e
485
+ File.readlines(_).each {|line|
486
+ e orangered(" #{line.chomp}")
487
+ }
488
+ e
489
+ else
490
+ opne no_file_exists_at(_)
491
+ end
492
+ end
493
+
494
+ # ========================================================================= #
495
+ # === show_popup_notification?
496
+ # ========================================================================= #
497
+ def show_popup_notification?
498
+ @internal_hash[:show_popup_notification]
499
+ end
500
+
501
+ # ========================================================================= #
502
+ # === do_show_popup
503
+ # ========================================================================= #
504
+ def do_show_popup
505
+ @internal_hash[:show_popup_notification] = true
506
+ end; alias show_popup do_show_popup # === show_popup
507
+
508
+ # ========================================================================= #
509
+ # === determine_where_to_backup_to_exactly
510
+ #
511
+ # This is automatically called whenever set_mountpoint() is called.
512
+ # ========================================================================= #
513
+ def determine_where_to_backup_to_exactly(
514
+ i = mountpoint?
515
+ )
516
+ backup_to_this_target = i
517
+ @backup_to_this_target = backup_to_this_target.dup
518
+ @backup_to_this_target << "/backup-#{return_current_date_and_time}/"
519
+ @backup_to_this_target = @backup_to_this_target.squeeze('/')
520
+ @backup_to_this_target.tr!(':','_') if simplify_the_directory_layout?
521
+ set_last_backup_directory(@backup_to_this_target)
522
+ end
523
+
524
+ # ========================================================================= #
525
+ # === mountpoint?
526
+ # ========================================================================= #
527
+ def mountpoint?
528
+ @internal_hash[:mountpoint]
529
+ end; alias mounted_at? mountpoint? # === mounted_at?
530
+ alias target_base_directory? mountpoint? # === target_base_directory?
531
+
532
+ # ========================================================================= #
533
+ # === opnn
534
+ # ========================================================================= #
535
+ def opnn(i = NAMESPACE)
536
+ if i.is_a? String
537
+ i = { namespace: i }
538
+ end
539
+ super(i)
540
+ end
541
+
542
+ # ========================================================================= #
543
+ # === backup_the_audio_directory_then_exit
544
+ #
545
+ # Backup the audio directory, then exit the program.
546
+ # ========================================================================= #
547
+ def backup_the_audio_directory_then_exit
548
+ backup_the_audio_directory
549
+ exit_program
550
+ end
551
+
552
+ # ========================================================================= #
553
+ # === do_use_simplified_directory
554
+ #
555
+ # The old code used to be like this:
556
+ #
557
+ # set_last_backup_directory(mount_point?+'last_backup')
558
+ #
559
+ # ========================================================================= #
560
+ def do_use_simplified_directory
561
+ @internal_hash[:simplify_the_directory_layout] = true
562
+ determine_the_current_timestamp # Must sync it back again.
563
+ end
564
+
565
+ # ========================================================================= #
566
+ # === create_file_keeping_track_of_when_the_last_backup_happened
567
+ #
568
+ # This method will store date-information into a file, when the last
569
+ # backup happened.
570
+ #
571
+ # It is normally found in a place such as:
572
+ #
573
+ # /home/x/data/LAST_BACKUP.md
574
+ #
575
+ # Since Dec 2012, we will also append the date to the name of said file.
576
+ # ========================================================================= #
577
+ def create_file_keeping_track_of_when_the_last_backup_happened(
578
+ use_this_as_timestamp = use_this_as_timestamp?
579
+ )
580
+ base_target = "#{data_directory?}LAST_BACKUP"
581
+ target = "#{base_target}_#{date?}.md" # Append the date here.
582
+ e N+'Storing '+sfile(use_this_as_timestamp)+rev+
583
+ ' into '+sfile(target)+rev+' to note'
584
+ e "#{rev}down when the last backup was performed."
585
+ write_what_into(use_this_as_timestamp, target)
586
+ # ======================================================================= #
587
+ # Next, obtain an array with potential similar names. We will have
588
+ # to delete stray entries so as to not clutter our original home
589
+ # directory there.
590
+ # ======================================================================= #
591
+ array_all_last_backup_files = Dir["#{base_target}*"]
592
+ if array_all_last_backup_files.size > 1
593
+ array_all_last_backup_files = array_all_last_backup_files.sort_by {|d|
594
+ d.split('.').reverse
595
+ } # Keep it sorted.
596
+ e N+'We found more than one entry in '+
597
+ sdir(File.dirname(base_target)+'/')+
598
+ rev+
599
+ ', thus removing'
600
+ e "#{rev}the extra-entries next."
601
+ array_all_last_backup_files[0..-2].each {|my_file|
602
+ e "#{rev}Removing `#{sfile(my_file)}#{rev}` next."
603
+ remove_file(my_file)
604
+ }
605
+ end
606
+ end; alias store_when_was_the_last_backup create_file_keeping_track_of_when_the_last_backup_happened # === store_when_was_the_last_backup
607
+
608
+ # ========================================================================= #
609
+ # === show_available_mountpoints
610
+ #
611
+ # This helper-method can show the available mountpoints, at the least
612
+ # on a linux system.
613
+ #
614
+ # To invoke this, try:
615
+ #
616
+ # rbackup --mountpoints
617
+ #
618
+ # ========================================================================= #
619
+ def show_available_mountpoints
620
+ begin
621
+ require 'mountpoints'
622
+ rescue LoadError; end
623
+ if Mountpoints.is_any_mountpoint_available?
624
+ opne 'The available (and mounted) USB devices are:'
625
+ e
626
+ Mountpoints[].each {|this_usb_device|
627
+ e " #{sfancy(this_usb_device)}"
628
+ }
629
+ e
630
+ else
631
+ opne 'No external USB devices appear to be mounted.'
632
+ end
633
+ end
634
+
635
+ # ========================================================================= #
636
+ # === show_available_mountpoints_then_exit
637
+ # ========================================================================= #
638
+ def show_available_mountpoints_then_exit
639
+ show_available_mountpoints
640
+ exit_program
641
+ end
642
+
643
+ # ========================================================================= #
644
+ # === report_time_difference
645
+ #
646
+ # This method will report to the user how long it took this class
647
+ # to backup the system, e. g. 30 minutes or something like that.
648
+ # ========================================================================= #
649
+ def report_time_difference
650
+ if @internal_hash[:array_store_times].size > 1
651
+ start_time = @internal_hash[:array_store_times][-2]
652
+ end_time = @internal_hash[:array_store_times].last
653
+ time_difference = end_time - start_time # This will result in a Float.
654
+ if time_difference.respond_to? :round
655
+ time_difference = time_difference.round(3)
656
+ end
657
+ n_minutes = (time_difference.to_f / 60.0).round(2).to_s
658
+ opne "#{tomato('Time required')} #{rev}for this backup-operation: "\
659
+ "#{sfancy(time_difference.to_s)}"\
660
+ " #{rev}seconds (#{royalblue(n_minutes)} #{rev}minutes)."
661
+ consider_creating_a_log_file(time_difference)
662
+ end
663
+ end
664
+
665
+ # ========================================================================= #
666
+ # === show_welcome_message
667
+ # ========================================================================= #
668
+ def show_welcome_message
669
+ print_rev
670
+ cliner
671
+ e "#{rev}Welcome to the #{lightcoral('BackupParadise')} #{rev}project!"
672
+ report_todays_date
673
+ cliner
674
+ e "#{rev}Starting to backup into the target at `#{sdir(main_target?)}#{rev}`."
675
+ cliner
676
+ end
677
+
678
+ # ========================================================================= #
679
+ # === consider_removing_all_but_one_log_file
680
+ # ========================================================================= #
681
+ def consider_removing_all_but_one_log_file
682
+ log_files = return_all_log_files
683
+ if log_files.size > 1
684
+ opne 'More than one log file has been found. We will delete'
685
+ opne 'all but one next.'
686
+ log_files.pop
687
+ delete_files(log_files, :be_verbose)
688
+ end
689
+ end
690
+
691
+ # ========================================================================= #
692
+ # === return_all_log_files
693
+ # ========================================================================= #
694
+ def return_all_log_files(
695
+ from_where = mounted_at?
696
+ )
697
+ Dir["#{from_where}log_last_backup_*"].select {|entry|
698
+ File.file? entry # We only want files.
699
+ }
700
+ end
701
+
702
+ # ========================================================================= #
703
+ # === popup_notification
704
+ #
705
+ # Use this method to send a graphical popup to the user. Only invoke
706
+ # it when we set @show_popup_notification to true.
707
+ # ========================================================================= #
708
+ def popup_notification(
709
+ what = :backup_complete
710
+ )
711
+ case what
712
+ when :backup_complete
713
+ esystem 'xmessage -center Backup finished!'
714
+ end
715
+ end
716
+
717
+ # ========================================================================= #
718
+ # === determine_the_starting_time
719
+ # ========================================================================= #
720
+ def determine_the_starting_time
721
+ @internal_hash[:array_store_times] << Time.now
722
+ end; alias determine_starting_time determine_the_starting_time # === determine_starting_time
723
+
724
+ # ========================================================================= #
725
+ # === determine_end_time
726
+ # ========================================================================= #
727
+ def determine_end_time
728
+ @internal_hash[:array_store_times] << Time.now
729
+ end
730
+
731
+ # ========================================================================= #
732
+ # === backup_the_programs_directory
733
+ #
734
+ # This method can be used to backup the /Programs directory.
735
+ # ========================================================================= #
736
+ def backup_the_programs_directory(
737
+ target_directory = PROGRAMS_DIRECTORY
738
+ )
739
+ if File.directory? target_directory
740
+ cliner
741
+ e 'Now backing up the Programs/ directory from '+
742
+ sfancy(target_directory)+' into '+
743
+ sfile(main_target?+File.basename(target_directory))
744
+ cliner
745
+ report_total_size_of(target_directory)
746
+ if target_hdd_does_not_have_enough_space_left?
747
+ opne "We have to skip backing up #{sdir(target_directory)}"
748
+ opne 'as it does not have enough space left (Threshold: '+
749
+ MINIMAL_FILESIZE+' bytes)'
750
+ else
751
+ backup_this_directory_if_it_exists(
752
+ target_directory, :default, :do_not_continue
753
+ )
754
+ end
755
+ else
756
+ can_not_backup_this_directory_as_it_does_not_exist(target_directory)
757
+ end
758
+ end
759
+
760
+ # ========================================================================= #
761
+ # === return_default_target_directory_from_this_input
762
+ # ========================================================================= #
763
+ def return_default_target_directory_from_this_input(i)
764
+ rds(
765
+ main_target?+
766
+ File.basename(i)+
767
+ '/'
768
+ )
769
+ end
770
+
771
+ # ========================================================================= #
772
+ # === determine_the_target_mountpoint
773
+ #
774
+ # This method will determine the target base mountpoint that
775
+ # is to be used.
776
+ # ========================================================================= #
777
+ def determine_the_target_mountpoint(
778
+ i = '/Mount/USB1/'
779
+ )
780
+ BackupParadise.target_mountpoint = i
781
+ end
782
+
783
+ # ========================================================================= #
784
+ # === create_the_directory_containing_the_last_backup
785
+ # ========================================================================= #
786
+ def create_the_directory_containing_the_last_backup
787
+ target = "#{main_target?}backup-#{use_this_as_timestamp?}"
788
+ # ======================================================================= #
789
+ # Next, create the last_backup directory:
790
+ # ======================================================================= #
791
+ begin
792
+ mkdir(target, 0755)
793
+ rescue Errno::EINVAL
794
+ target.tr!(':','_')
795
+ mkdir(target, 0755)
796
+ end
797
+ @internal_hash[:last_backup_directory] = rds(target+'/')
798
+ opne "Creating a directory at "\
799
+ "`#{sdir(@internal_hash[:last_backup_directory])}`."
800
+ end
801
+
802
+ # ========================================================================= #
803
+ # === create_a_symlink_pointing_to_that_directory_that_was_just_created
804
+ #
805
+ # This method will create a symlink to the last_backup/ directory.
806
+ #
807
+ # This is synonymous to the following ruby code:
808
+ #
809
+ # File.symlink('last_backup-13.08.2018-22:12:26/','last_backup')
810
+ #
811
+ # ========================================================================= #
812
+ def create_a_symlink_pointing_to_that_directory_that_was_just_created
813
+ cd_to_the_mounted_device
814
+ create_a_symlink_here = "#{backup_to_this_directory?}last_backup"
815
+ from_this_target = File.basename(@internal_hash[:last_backup_directory])
816
+ from_this_target.chop! if from_this_target.end_with? '/'
817
+ # ========================================================================= #
818
+ # First, delete the old symlink if it exists. The method delete_symlink()
819
+ # will do that check for us.
820
+ # ========================================================================= #
821
+ delete_symlink(create_a_symlink_here)
822
+ # ========================================================================= #
823
+ # The next action can fail on e. g. vfat filesystems, with the error
824
+ # being Errno::EPERM. Hence we must rescue here.
825
+ # ========================================================================= #
826
+ begin
827
+ do_symlink(from_this_target, create_a_symlink_here)
828
+ if File.exist? create_a_symlink_here
829
+ points_towards = File.readlink(create_a_symlink_here)
830
+ opne rev+'Next setting a symlink at `'+sfancy(create_a_symlink_here)+
831
+ rev+'` pointing'
832
+ opne "#{rev}towards `#{sfile(points_towards)}#{rev}`."
833
+ else
834
+ opne no_file_exists_at(create_a_symlink_here)
835
+ end
836
+ rescue Errno::EPERM
837
+ end
838
+ end; alias create_symlink_to_last_backup_directory create_a_symlink_pointing_to_that_directory_that_was_just_created # === create_symlink_to_last_backup_directory
839
+
840
+ # ========================================================================= #
841
+ # === do_sync
842
+ #
843
+ # The do_sync() method, also aliased towards synchronize(), will sync
844
+ # the data onto USB items, by using the sync command.
845
+ # ========================================================================= #
846
+ def do_sync
847
+ opne 'Starting to '+steelblue('sync data')+' ...'
848
+ system 'sync' # Be silent since May 2014.
849
+ opne "> Syncing finished. (At: "\
850
+ "#{rosybrown(return_current_date_and_time.to_s)})"
851
+ end; alias synchronize do_sync # === synchronize
852
+
853
+ # ========================================================================= #
854
+ # === backup_this_directory
855
+ #
856
+ # This method will quickly backup a given directory.
857
+ #
858
+ # The second argument will be the target-directory onto which
859
+ # we will copy our files.
860
+ # ========================================================================= #
861
+ def backup_this_directory(
862
+ i,
863
+ copy_to_this_target_directory = nil,
864
+ shall_we_sync = true
865
+ )
866
+ case shall_we_sync
867
+ when :do_not_sync
868
+ shall_we_sync = false
869
+ end
870
+ case copy_to_this_target_directory
871
+ when nil,
872
+ :default
873
+ copy_to_this_target_directory = return_default_target_directory_from_this_input(i)
874
+ end
875
+ unless File.directory? copy_to_this_target_directory
876
+ mkdir(copy_to_this_target_directory)
877
+ end
878
+ cd copy_to_this_target_directory
879
+ opne rev+'Now copying '+sdir(i)+
880
+ rev+' to '+sdir(copy_to_this_target_directory)+
881
+ rev+'.'
882
+ if File.directory?(i)
883
+ i << '*'
884
+ end
885
+ cpr(
886
+ i, copy_to_this_target_directory
887
+ )
888
+ do_sync if shall_we_sync
889
+ end
890
+
891
+ # ========================================================================= #
892
+ # === backup_the_system_directory
893
+ #
894
+ # This method can be used to backup the "/System/Settings/" directory,
895
+ # as it may be found in GoboLinux.
896
+ # ========================================================================= #
897
+ def backup_the_system_directory(
898
+ target_directory = SYSTEM_SETTINGS_DIRECTORY
899
+ )
900
+ if File.directory? target_directory
901
+ cliner
902
+ e rev+'Now backing up the system-settings directory from '+
903
+ sfancy(target_directory)+
904
+ rev+' into '+
905
+ sfile(
906
+ main_target?+File.basename(target_directory)
907
+ )
908
+ cliner
909
+ report_total_size_of(target_directory)
910
+ cpr(
911
+ target_directory,
912
+ backup_to_this_target?
913
+ )
914
+ else
915
+ can_not_backup_this_directory_as_it_does_not_exist(target_directory)
916
+ end
917
+ end; alias backup_system_directory backup_the_system_directory # === backup_system_directory
918
+
919
+ # ========================================================================= #
920
+ # === backup_to_this_target?
921
+ # ========================================================================= #
922
+ def backup_to_this_target?
923
+ @backup_to_this_target
924
+ end
925
+
926
+ # ========================================================================= #
927
+ # === backup_the_data_directory_then_exit
928
+ #
929
+ # Backup only Data directory.
930
+ # ========================================================================= #
931
+ def backup_the_data_directory_then_exit
932
+ backup_data_directory
933
+ exit_program
934
+ end; alias backup_data_directory_then_exit backup_the_data_directory_then_exit # === backup_data_directory_then_exit
935
+
936
+ # ========================================================================= #
937
+ # === backup_the_data_directory (data tag)
938
+ #
939
+ # This method will backup the DATA directory, e. g. the one that is
940
+ # at "/home/x/data/" on my home system.
941
+ # ========================================================================= #
942
+ def backup_the_data_directory(
943
+ target_directory = DATA_DIRECTORY
944
+ )
945
+ if File.directory? target_directory
946
+ mountpoint_target = main_target?+File.basename(target_directory)
947
+ print rev
948
+ cliner
949
+ e "#{rev}Now backing up the DATA directory from "\
950
+ "#{sfancy(target_directory)} into "\
951
+ "#{sfile(mountpoint_target)}."
952
+ cliner
953
+ report_total_size_of(target_directory)
954
+ unless File.directory? mountpoint_target
955
+ create_directory(mountpoint_target, 0755)
956
+ end
957
+ mkdir(backup_to_this_target?+File.basename(target_directory))
958
+ cpr(
959
+ target_directory,
960
+ backup_to_this_target?
961
+ )
962
+ else
963
+ can_not_backup_this_directory_as_it_does_not_exist(target_directory)
964
+ end
965
+ end; alias backup_only_data_directory backup_the_data_directory # === backup_only_data_directory
966
+ alias backup_data_directory backup_the_data_directory # === backup_data_directory
967
+
968
+ # ========================================================================= #
969
+ # === ensure_trailing_backslash_for
970
+ # ========================================================================= #
971
+ def ensure_trailing_backslash_for(i)
972
+ i = i.dup
973
+ i << '/' unless i.end_with? '/'
974
+ return i
975
+ end
976
+
977
+ # ========================================================================= #
978
+ # === backup_the_studium_directory
979
+ # ========================================================================= #
980
+ def backup_the_studium_directory(
981
+ target_directory = STUDIUM_DIRECTORY
982
+ )
983
+ target_directory = ensure_trailing_backslash_for(target_directory)
984
+ if File.directory? target_directory
985
+ tab_title('Backing up the '+target_directory+' directory.')
986
+ cliner
987
+ e 'Now backing up the studium/ directory from '+
988
+ sfancy(target_directory)+' into '+
989
+ sfile(main_target?+File.basename(target_directory))
990
+ cliner
991
+ report_total_size_of(target_directory)
992
+ mkdir(backup_to_this_target?+File.basename(target_directory))
993
+ cpr(
994
+ target_directory,
995
+ backup_to_this_target?
996
+ )
997
+ else
998
+ can_not_backup_this_directory_as_it_does_not_exist(target_directory)
999
+ end
1000
+ end
1001
+
1002
+ # ========================================================================= #
1003
+ # === backup_the_video_directory
1004
+ # ========================================================================= #
1005
+ def backup_the_video_directory(
1006
+ target_directory = VIDEO_DIRECTORY
1007
+ )
1008
+ target_directory = ensure_trailing_backslash_for(target_directory)
1009
+ if File.directory? target_directory
1010
+ cliner
1011
+ e 'Now backing up the Video directory from '+
1012
+ sfancy(target_directory)+' into '+
1013
+ sfile(main_target?+File.basename(target_directory))
1014
+ cliner
1015
+ tab_title('Backing up the directory '+target_directory+' next.')
1016
+ report_total_size_of(target_directory)
1017
+ set_backup_to_this_target(target_base_directory?)
1018
+ mkdir(
1019
+ target_base_directory?+File.basename(target_directory)
1020
+ )
1021
+ cpr(
1022
+ target_directory,
1023
+ target_base_directory?
1024
+ )
1025
+ show_all_is_done_message
1026
+ default_tab_title
1027
+ else
1028
+ can_not_backup_this_directory_as_it_does_not_exist(target_directory)
1029
+ end
1030
+ end
1031
+
1032
+ # ========================================================================= #
1033
+ # === BackupParadise::Backup[]
1034
+ # ========================================================================= #
1035
+ def self.[](i = '')
1036
+ new(i)
1037
+ end
1038
+
1039
+ # ========================================================================= #
1040
+ # === try_to_backup_the_autogenerated_directory
1041
+ # ========================================================================= #
1042
+ def try_to_backup_the_autogenerated_directory(
1043
+ i = AUTOGENERATED_DIRECTORY
1044
+ )
1045
+ i = ensure_trailing_backslash_for(i)
1046
+ if File.directory? i
1047
+ opne 'Now trying to backup the AUTOGENERATED '\
1048
+ 'directory at `'+sdir(i)+'`.'
1049
+ new_target = mountpoint?.squeeze('/')
1050
+ n_gigabytes = BackupParadise.size_in_gigabytes?(i).to_s
1051
+ opne 'This directory has a total of '+
1052
+ sfancy(n_files_in?(i).to_s)+rev+
1053
+ ' entries (Total size: '+n_gigabytes+' GB).'
1054
+ unless File.directory? new_target
1055
+ verbose_create_a_directory_at_this_position(new_target)
1056
+ end
1057
+ tab_title('Backing up the AUTOGENERATED directory.')
1058
+ cpr(i, new_target)
1059
+ else
1060
+ can_not_backup_this_directory_as_it_does_not_exist(i)
1061
+ end
1062
+ end; alias backup_autogenerated_directory try_to_backup_the_autogenerated_directory # === backup_autogenerated_directory
1063
+ alias backup_the_autogenerated_directory try_to_backup_the_autogenerated_directory # === backup_the_autogenerated_directory
1064
+
1065
+ # ========================================================================= #
1066
+ # === backup_into_the_default_chroot_directory (chroot tag)
1067
+ # ========================================================================= #
1068
+ def backup_into_the_default_chroot_directory(
1069
+ i = :chroot
1070
+ )
1071
+ e
1072
+ e "#{rev}Setting the target to #{sdir(i)} next."
1073
+ e
1074
+ set_target_mountpoint(i) # Set to the above Chroot target. We could also use :chroot.
1075
+ set_main_target(
1076
+ "#{main_target?.dup}#{home_dir_of_user_x?.dup}"
1077
+ )
1078
+ # ======================================================================= #
1079
+ # Must copy the autogenerated directory first:
1080
+ # ======================================================================= #
1081
+ try_to_backup_the_autogenerated_directory
1082
+ all_important_directories?.each {|this_directory|
1083
+ tab_title 'Now backing up the '+this_directory+' directory ...'
1084
+ new_target = main_target?+File.basename(this_directory)
1085
+ mkdir(new_target)
1086
+ cpr(this_directory, main_target?)
1087
+ }
1088
+ all_done_message
1089
+ end
1090
+
1091
+ # ========================================================================= #
1092
+ # === backup_src_directory (src tag)
1093
+ #
1094
+ # This method will backup the SRC/ directory, aka "/home/x/src/". It
1095
+ # is evidently geared towards the system at my home setup.
1096
+ #
1097
+ # To invoke this method from the commandline, try:
1098
+ #
1099
+ # rbackup --src-dir
1100
+ #
1101
+ # ========================================================================= #
1102
+ def backup_the_source_directory(
1103
+ target_directory = SOURCE_DIRECTORY
1104
+ )
1105
+ target_directory = ensure_trailing_backslash_for(target_directory)
1106
+ if File.directory? target_directory
1107
+ tab_title('Backing up the '+target_directory+' directory.')
1108
+ cliner
1109
+ e 'Now backing up the '+sdir('src/')+' directory from '+
1110
+ sfancy(target_directory)+' into '+
1111
+ sfile(main_target?+File.basename(target_directory))
1112
+ cliner
1113
+ report_total_size_of(target_directory)
1114
+ mkdir(backup_to_this_target?+File.basename(target_directory))
1115
+ cpr(
1116
+ target_directory,
1117
+ backup_to_this_target?
1118
+ )
1119
+ else
1120
+ can_not_backup_this_directory_as_it_does_not_exist(target_directory)
1121
+ end
1122
+ end
1123
+
1124
+ # ========================================================================= #
1125
+ # === backup_the_books_directory (data tag)
1126
+ #
1127
+ # This method will backup the BOOKS directory, e. g. the one that is
1128
+ # at "/home/x/books/" on my home system.
1129
+ # ========================================================================= #
1130
+ def backup_the_books_directory(
1131
+ target_directory = BOOKS_DIRECTORY
1132
+ )
1133
+ target_directory = ensure_trailing_backslash_for(target_directory)
1134
+ if File.directory? target_directory
1135
+ tab_title('Backing up the '+target_directory+' directory.')
1136
+ cliner
1137
+ e 'Now backing up the books/ directory from '+
1138
+ sfancy(target_directory)+' into '+
1139
+ sfile(main_target?+File.basename(target_directory))
1140
+ cliner
1141
+ report_total_size_of(target_directory)
1142
+ unless File.directory? backup_to_this_target?+File.basename(target_directory)
1143
+ opnn; verbose_create_a_directory_at_this_position(
1144
+ backup_to_this_target?+File.basename(target_directory),
1145
+ 0755
1146
+ )
1147
+ end
1148
+ cpr(
1149
+ target_directory,
1150
+ backup_to_this_target?
1151
+ )
1152
+ rename_tab('.')
1153
+ else
1154
+ can_not_backup_this_directory_as_it_does_not_exist(target_directory)
1155
+ end
1156
+ end; alias backup_only_books_directory backup_the_books_directory # === backup_only_books_directory
1157
+ alias backup_books_directory backup_the_books_directory # === backup_books_directory
1158
+
1159
+ # ========================================================================= #
1160
+ # === do_not_perform_the_regular_backup_routine
1161
+ # ========================================================================= #
1162
+ def do_not_perform_the_regular_backup_routine
1163
+ @internal_hash[:perform_backup] = false
1164
+ end
1165
+
1166
+ # ========================================================================= #
1167
+ # === perform_the_regular_backup_routine?
1168
+ # ========================================================================= #
1169
+ def perform_the_regular_backup_routine?
1170
+ @internal_hash[:perform_backup]
1171
+ end
1172
+
1173
+ # ========================================================================= #
1174
+ # === report_todays_date
1175
+ # ========================================================================= #
1176
+ def report_todays_date
1177
+ e "Today is the #{sfancy(date?)}."
1178
+ end
1179
+
1180
+ # ========================================================================= #
1181
+ # === create_the_log_last_backup_file (log tag)
1182
+ #
1183
+ # We also have to remove all prior log files should they exist.
1184
+ # ========================================================================= #
1185
+ def create_the_log_last_backup_file
1186
+ _ = return_all_log_files
1187
+ target = main_target?+'log_last_backup_'+use_this_as_timestamp?
1188
+ what = dd_mm_yyyy
1189
+ opne "Keeping a backup file (a log) at"
1190
+ opne "`#{sfile(target)}`."
1191
+ write_what_into(what, target)
1192
+ unless _.empty?
1193
+ # ===================================================================== #
1194
+ # Remove all old log files next.
1195
+ # ===================================================================== #
1196
+ remove_these_files(_)
1197
+ end
1198
+ end; alias create_log_file create_the_log_last_backup_file # === create_log_file
1199
+
1200
+ # ========================================================================= #
1201
+ # === last_backup_directory?
1202
+ # ========================================================================= #
1203
+ def last_backup_directory?
1204
+ @internal_hash[:last_backup_directory]
1205
+ end
1206
+
1207
+ # ========================================================================= #
1208
+ # === set_last_backup_directory
1209
+ # ========================================================================= #
1210
+ def set_last_backup_directory(i)
1211
+ @internal_hash[:last_backup_directory] = i
1212
+ end
1213
+
1214
+ # ========================================================================= #
1215
+ # === consider_creating_a_log_file
1216
+ #
1217
+ # This method will create a .log file.
1218
+ #
1219
+ # It accepts an argument, which should be an Integer or Float, denoting,
1220
+ # in seconds, how long it took to make a backup.
1221
+ # ========================================================================= #
1222
+ def consider_creating_a_log_file(
1223
+ n_seconds
1224
+ )
1225
+ if File.directory? '/Depot/Temp/'
1226
+ n_minutes = (n_seconds.to_f / 60).round(1).to_s
1227
+ # ===================================================================== #
1228
+ # Make the seconds a bit prettier next, via trailing '0'.
1229
+ # ===================================================================== #
1230
+ n_seconds = '%.3f' % n_seconds
1231
+ what = "#{return_full_date}: Backing up the system took #{n_seconds} "\
1232
+ "seconds (#{n_minutes} minutes).\n"
1233
+ into = FILE_BACKUP_LOG
1234
+ opne "Storing the time it took to backup "\
1235
+ "into the file `#{sfile(into)}`."
1236
+ append_what_into(what, into)
1237
+ end
1238
+ end
1239
+
1240
+ # ========================================================================= #
1241
+ # === backup_the_audio_directory (audio tag, audio dir tag)
1242
+ #
1243
+ # This method can be used to backup my audio directory, which normally
1244
+ # resides at "/home/x/songs/".
1245
+ #
1246
+ # Two arguments can be supplied to this method:
1247
+ #
1248
+ # (1) The first argument specifies which directory is used as the
1249
+ # input directory, where the songs that are to be copied
1250
+ # should reside.
1251
+ #
1252
+ # (2) If the second argument is true then only those audio files
1253
+ # that are missing will be copied.
1254
+ #
1255
+ # ========================================================================= #
1256
+ def backup_the_audio_directory(
1257
+ i = DIRECTORY_CONTAINING_ALL_SONGS,
1258
+ copy_only_missing_audio_files = true
1259
+ )
1260
+ if File.directory? i
1261
+ copied_n_files = 0
1262
+ print rev
1263
+ cliner
1264
+ new_target = mountpoint?.squeeze('/')
1265
+ opne "Now trying to backup the Audio directory "\
1266
+ "at `#{sdir(i)}`."
1267
+ colourized_target = sdir("#{new_target}#{File.basename(i)}/")
1268
+ opne "The target for this will be at "\
1269
+ "`#{colourized_target}`."
1270
+ n_gigabytes = BackupParadise.size_in_gigabytes?(i).to_s
1271
+ opne 'This directory has a total of '+
1272
+ sfancy(n_files_in?(i).to_s)+rev+
1273
+ ' entries '\
1274
+ '(Total size: '+n_gigabytes+' GB).'
1275
+ cliner
1276
+ unless File.directory? "#{new_target}#{File.basename(i)}/"
1277
+ opnn; verbose_create_a_directory_at_this_position(
1278
+ "#{new_target}#{File.basename(i)}/"
1279
+ )
1280
+ end
1281
+ tab_title('Backing up the main audio directory.')
1282
+ # ===================================================================== #
1283
+ # Else we will copy only the audio files that are missing. In order
1284
+ # to do so we have to obtain all audio-files - we will simply
1285
+ # pick all files, anyway. We will keep these entries sorted, too.
1286
+ # ===================================================================== #
1287
+ these_audio_files_may_be_copied = Dir[
1288
+ rds("#{i.delete('*')}/*")
1289
+ ].sort
1290
+ if copy_only_missing_audio_files
1291
+ these_audio_files_may_be_copied.each {|this_file|
1292
+ totally_new_target =
1293
+ "#{new_target}#{File.basename(i)}/#{File.basename(this_file)}"
1294
+ # ================================================================= #
1295
+ # We check whether the target-file exists. Only if it does not
1296
+ # exist will it be copied.
1297
+ # ================================================================= #
1298
+ unless File.exist? totally_new_target
1299
+ copied_n_files += 1
1300
+ # =============================================================== #
1301
+ # Pad the display.
1302
+ # =============================================================== #
1303
+ padded_file = this_file.ljust(40)
1304
+ padded_target = totally_new_target.ljust(40)
1305
+ e "Copying `#{sfile(padded_file)}` to"
1306
+ e " `#{sfile(padded_target)}`."
1307
+ copy_this_file(this_file, totally_new_target)
1308
+ end
1309
+ }
1310
+ # =================================================================== #
1311
+ # Ok, now, if we removed a file from /Depot/Audio, then the Audio/
1312
+ # directory at the mounted USB device may still have such a file.
1313
+ # So we will warn the user about this.
1314
+ # =================================================================== #
1315
+ target = "#{new_target}#{File.basename(i)}/" # This will be something like "/Mount/USB1/songs/"
1316
+ unless these_audio_files_may_be_copied.size == Dir["#{target}*"].size
1317
+ opne 'It seems as if we have an unequal amount of Audio files in '
1318
+ opne 'the two directories.'
1319
+ opne 'This usually means that the original directory '+
1320
+ sdir(i)+' has some files'
1321
+ opne 'deleted, but the target directory at '+sdir(target)+' does not.'
1322
+ opne rev+'The old directory has '+simp(i.size.to_s)+rev+' entries.'
1323
+ end
1324
+ else
1325
+ cpr(i, new_target)
1326
+ end
1327
+ _ = "#{new_target}#{File.basename(i)}/"
1328
+ if copied_n_files == 0
1329
+ opne "No file was copied into the directory #{sdir(_)}."
1330
+ opne 'This may indicate that the target audio-directory already'
1331
+ opne 'contains all necessary audio-files.'
1332
+ else
1333
+ opne "Finished backing up the directory "\
1334
+ "#{sdir(i.delete('*'))} into "\
1335
+ "#{sdir(_)}."
1336
+ end
1337
+ default_tab_title
1338
+ else
1339
+ can_not_backup_this_directory_as_it_does_not_exist(i)
1340
+ end
1341
+ end; alias try_to_backup_the_audio_directory backup_the_audio_directory # === alias try_to_backup_the_audio_directory
1342
+ alias backup_audio_directory backup_the_audio_directory # === backup_audio_directory
1343
+
1344
+ # ========================================================================= #
1345
+ # === unmount
1346
+ #
1347
+ # Use this to unmount something. Right now, we unmount only the HDD.
1348
+ # ========================================================================= #
1349
+ def unmount(
1350
+ what = :hdd
1351
+ )
1352
+ case what.to_sym
1353
+ when :hdd
1354
+ system "umount -l #{ENV['FIRST_HD']}"
1355
+ end
1356
+ end
1357
+
1358
+ # ========================================================================= #
1359
+ # === show_backup_complete_message
1360
+ #
1361
+ # This variant will show that the backup has been complete on the
1362
+ # commandline. Since September 2022 there is also a backup-complete
1363
+ # message for LibuiParadise.
1364
+ # ========================================================================= #
1365
+ def show_backup_complete_message
1366
+ e "#{BackupParadise.steelblue('Backup complete!')}#{rev}" # The old colour was cyan, up until 2021.
1367
+ if TRY_TO_SHOW_BACKUP_COMPLETE_MESSAGE_VIA_LIBUI
1368
+ try_to_show_backup_complete_message_via_libui
1369
+ end
1370
+ end; alias all_done show_backup_complete_message # === all_done
1371
+ alias show_all_is_done_message show_backup_complete_message # === show_all_is_done_message
1372
+ alias all_done_message show_backup_complete_message # === all_done_message
1373
+
1374
+ # ========================================================================= #
1375
+ # === try_to_show_backup_complete_message_via_libui
1376
+ #
1377
+ # This method will describe the libui-widget that we will use for
1378
+ # notifying the user.
1379
+ # ========================================================================= #
1380
+ def try_to_show_backup_complete_message_via_libui
1381
+ begin
1382
+ require 'libui_paradise'
1383
+ text = LibuiParadise.text('Backup complete!')
1384
+ ::LibuiParadise.run_in_the_background
1385
+ LibuiParadise.generic_window(
1386
+ text, :create_a_quit_button
1387
+ ) {{
1388
+ width: 420,
1389
+ height: 120,
1390
+ title: 'Backup is complete now!'
1391
+ }}
1392
+ rescue LoadError; end
1393
+ end
1394
+
1395
+ # ========================================================================= #
1396
+ # === menu (menu tag)
1397
+ # ========================================================================= #
1398
+ def menu(
1399
+ i = commandline_arguments?
1400
+ )
1401
+ return if i.nil?
1402
+ # ======================================================================= #
1403
+ # === Handle Hashes
1404
+ #
1405
+ # Note that this is the default entry point.
1406
+ #
1407
+ # An example for how this may be used is given next:
1408
+ #
1409
+ # BackupParadise::Actions.backup(
1410
+ # backup_these_directories: i,
1411
+ # where_to: to
1412
+ # )
1413
+ #
1414
+ # ======================================================================= #
1415
+ if i.is_a? Hash
1416
+ # ===================================================================== #
1417
+ # === :backup_to_this_target
1418
+ #
1419
+ # The next check must come early, on top.
1420
+ # ===================================================================== #
1421
+ # ===================================================================== #
1422
+ # === :where_to
1423
+ # ===================================================================== #
1424
+ if i.has_key? :where_to
1425
+ set_backup_to_this_target(i[:where_to])
1426
+ elsif i.has_key? :backup_to_this_target
1427
+ set_backup_to_this_target(i[:backup_to_this_target])
1428
+ end
1429
+ # ===================================================================== #
1430
+ # === :commandline_arguments
1431
+ # ===================================================================== #
1432
+ if i.has_key? :commandline_arguments
1433
+ menu(i[:commandline_arguments])
1434
+ # ===================================================================== #
1435
+ # === :backup_these_directories
1436
+ # ===================================================================== #
1437
+ elsif i.has_key? :backup_these_directories
1438
+ menu(i[:backup_these_directories])
1439
+ end
1440
+ # ======================================================================= #
1441
+ # === Handle Arrays
1442
+ # ======================================================================= #
1443
+ elsif i.is_a? Array
1444
+ i.each {|entry| menu(entry) }
1445
+ else
1446
+ case i # case tag
1447
+ # ===================================================================== #
1448
+ # === rbackup --audio-dir
1449
+ #
1450
+ # This entry point can be used to specifically backup the
1451
+ # audio-directory - that is, the local directory that
1452
+ # contains all songs.
1453
+ #
1454
+ # Usage example:
1455
+ #
1456
+ # rbackup --audio-dir
1457
+ #
1458
+ # A more advanced invocation example is:
1459
+ #
1460
+ # rbackup --backup-to=/opt/ --audio-dir
1461
+ #
1462
+ # ===================================================================== #
1463
+ when /^-?-?audio(-| |_)?dir$/i,
1464
+ /^-?-?audio$/i,
1465
+ /^-?-?aud$/i,
1466
+ /^-?-?audi$/i,
1467
+ /^-?-?aonly$/i,
1468
+ /^-?-?audio(-| |_)?only$/i
1469
+ determine_whether_the_target_harddisc_is_a_ntfs_system
1470
+ backup_the_audio_directory
1471
+ do_not_perform_the_regular_backup_routine
1472
+ # ===================================================================== #
1473
+ # === rbackup --libui
1474
+ # ===================================================================== #
1475
+ when /^-?-?lib-?ui$/i,
1476
+ /^-?-?gui2$/i
1477
+ require 'backup_paradise/gui/libui/backup_for_ingrid/backup_for_ingrid.rb'
1478
+ BackupParadise::GUI::LibUI::BackupForIngrid.new
1479
+ exit
1480
+ # ===================================================================== #
1481
+ # === rbackup --gui
1482
+ #
1483
+ # Alternatively use rbackup --gtk3.
1484
+ # ===================================================================== #
1485
+ when /^-?-?gui$/i,
1486
+ /^-?-?gtk3$/i,
1487
+ /^-?-?gtk$/i,
1488
+ /^-?-?gui1$/i
1489
+ start_the_gtk3_bindings
1490
+ do_not_perform_the_regular_backup_routine
1491
+ # ===================================================================== #
1492
+ # === rbackup --version?
1493
+ # ===================================================================== #
1494
+ when /^-?-?version\??$/i
1495
+ e BackupParadise::VERSION
1496
+ do_not_perform_the_regular_backup_routine
1497
+ # ===================================================================== #
1498
+ # === rbackup --are-we-on-windows?
1499
+ # ===================================================================== #
1500
+ when /^-?-?are(-| |_)?we(-| |_)?on(-| |_)?windows\??$/i
1501
+ e rev+'Are we on windows? '+
1502
+ steelblue(are_we_on_windows?.to_s)
1503
+ do_not_perform_the_regular_backup_routine
1504
+ # ===================================================================== #
1505
+ # === rbackup --help
1506
+ #
1507
+ # The user can use this entry point to obtain helpful information in
1508
+ # how to use this class, on the commandline.
1509
+ # ===================================================================== #
1510
+ when /help/i,
1511
+ /^-?-?show(-| |_)?help$/i,
1512
+ 'hel',
1513
+ 'he','h','?','*'
1514
+ show_help
1515
+ do_not_perform_the_regular_backup_routine
1516
+ # ===================================================================== #
1517
+ # === rbackup --video-dir
1518
+ # ===================================================================== #
1519
+ when /^-?-?video(-| |_)?dir$/i,
1520
+ /^-?-?video(-| |_)?directory$/i,
1521
+ /^-?-?video$/i
1522
+ backup_the_video_directory
1523
+ do_not_perform_the_regular_backup_routine
1524
+ # ===================================================================== #
1525
+ # === rbackup --books
1526
+ #
1527
+ # This entry point allows the user to backup the /home/x/books/
1528
+ # directory.
1529
+ # ===================================================================== #
1530
+ when /^-?-?books$/i,
1531
+ /^-?-?books(-| |_)?directory$/i
1532
+ backup_the_books_directory
1533
+ do_not_perform_the_regular_backup_routine
1534
+ # ===================================================================== #
1535
+ # === rbackup --source-dir
1536
+ # === rbackup --source-directory
1537
+ # === rbackup --source
1538
+ # === rbackup --src-dir
1539
+ # === rbackup --src
1540
+ #
1541
+ # This entry point allows the user to backup the /home/x/src/
1542
+ # directory.
1543
+ # ===================================================================== #
1544
+ when /^-?-?source(-| |_)?dir$/i,
1545
+ /^-?-?source(-| |_)?directory$/i,
1546
+ /^-?-?source$/i,
1547
+ /^-?-?src(-| |_)?dir$/i,
1548
+ /^-?-?src$/i
1549
+ backup_the_source_directory
1550
+ do_not_perform_the_regular_backup_routine
1551
+ # ===================================================================== #
1552
+ # === Backup all relevant entries to the chroot-directory
1553
+ #
1554
+ # This entry point is mostly used for my local Chroot directory. We
1555
+ # will quickly backup the important files to that directory, which
1556
+ # then allows us to cd into a better chroot-environment.
1557
+ #
1558
+ # Invocation examples:
1559
+ #
1560
+ # rbackup --chroot
1561
+ # rbackup --to-chroot
1562
+ #
1563
+ # ===================================================================== #
1564
+ when /^-?-?chroot$/i,
1565
+ /^-?-?to(-| |_)?chroot$/i,
1566
+ /^-?-?into(-| |_)?chroot$/i
1567
+ backup_into_the_default_chroot_directory
1568
+ do_not_perform_the_regular_backup_routine
1569
+ # ===================================================================== #
1570
+ # === rbackup --studium-dir
1571
+ # === rbackup --studium-directory
1572
+ # === rbackup --studium
1573
+ #
1574
+ # This entry point allows the user to backup the /home/x/studium/
1575
+ # directory, by making use of the constant STUDIUM_DIRECTORY.
1576
+ # ===================================================================== #
1577
+ when /^-?-?studium(-| |_)?dir$/i,
1578
+ /^-?-?studium(-| |_)?directory$/i,
1579
+ /^-?-?studium$/i
1580
+ backup_the_studium_directory
1581
+ do_not_perform_the_regular_backup_routine
1582
+ # ===================================================================== #
1583
+ # === rbackup --data-dir
1584
+ # ===================================================================== #
1585
+ when /^-?-?data(-| |_)?dir$/i,
1586
+ /^-?-?data(-| |_)?directory$/i,
1587
+ /^-?-?data$/i,
1588
+ /^-?-?ONLY(-| |_)?DATA$/i,
1589
+ /^-?-?DATA(-| |_)?ONLY$/i,
1590
+ /^-?-?donly$/i
1591
+ backup_the_data_directory_then_exit
1592
+ # ===================================================================== #
1593
+ # === rbackup --system-dir
1594
+ # ===================================================================== #
1595
+ when /^-?-?system(-| |_)?dir$/i,
1596
+ /^-?-?system(-| |_)?directory$/i,
1597
+ /^-?-?system$/i
1598
+ backup_the_system_directory
1599
+ do_not_perform_the_regular_backup_routine
1600
+ # ===================================================================== #
1601
+ # === rbackup --programs-dir
1602
+ #
1603
+ # This entry point can be used to backup /home/Programs/ specifically.
1604
+ # ===================================================================== #
1605
+ when /^-?-?programs(-| |_)?dir$/i,
1606
+ /^-?-?programs$/i
1607
+ backup_the_programs_directory
1608
+ do_not_perform_the_regular_backup_routine
1609
+ # ===================================================================== #
1610
+ # === rbackup default
1611
+ # ===================================================================== #
1612
+ when 'default' # Default entry point is for /Mount/USB1 aka :usb1.
1613
+ set_target_mountpoint(:usb1)
1614
+ # ===================================================================== #
1615
+ # === rbackup --mountpoints
1616
+ # ===================================================================== #
1617
+ when /^-?-?mountpoints/
1618
+ show_available_mountpoints_then_exit
1619
+ # ===================================================================== #
1620
+ # === rbackup --logfile
1621
+ # ===================================================================== #
1622
+ when /^-?-?logfile\??$/i
1623
+ show_the_logfile
1624
+ do_not_perform_the_regular_backup_routine
1625
+ # ===================================================================== #
1626
+ # === rbackup --show-file-size-of-popular_directories
1627
+ # === rbackup --overview
1628
+ # ===================================================================== #
1629
+ when /^-?-?show(-| |_)?file(-| |_)?size(-| |_)?of(-| |_)?popular(-| |_)?directories$/i,
1630
+ /^-?-?overview$/i
1631
+ use_this_array = [
1632
+ return_the_songs_directory,
1633
+ PROGRAMS_DIRECTORY,
1634
+ VIDEO_DIRECTORY,
1635
+ STUDIUM_DIRECTORY,
1636
+ DATA_DIRECTORY,
1637
+ SOURCE_DIRECTORY
1638
+ ].map {|entry|
1639
+ return_this_absolute_directory(entry)
1640
+ }
1641
+ use_this_array.each {|this_entry|
1642
+ report_file_size_of(this_entry)
1643
+ }
1644
+ do_not_perform_the_regular_backup_routine
1645
+ # ===================================================================== #
1646
+ # === rbackup --use-this-as-target-for-backup=/opt/
1647
+ # === rbackup --use-this-as-target=/opt/
1648
+ # === rbackup --backup-to=/opt/
1649
+ #
1650
+ # This entry point allows the user to specify another target to
1651
+ # be used from the commandline.
1652
+ # ===================================================================== #
1653
+ when /^-?-?backup(-| |_)?to=(.+)$/i,
1654
+ /^-?-?use(-| |_)?this(-| |_)?as(-| |_)?target=(.+)$/i,
1655
+ /^-?-?use(-| |_)?this(-| |_)?as(-| |_)?target(-| |_)?for(-| |_)?backup=(.+)$/i
1656
+ _ = $2.to_s.dup
1657
+ _ = $4.to_s.dup if $4
1658
+ _ = $6.to_s.dup if $6
1659
+ opne 'The target device will be at '+sfancy(_)+'.'
1660
+ set_target_device(_)
1661
+ # ===================================================================== #
1662
+ # === Use a shorter name for the backup-directory
1663
+ #
1664
+ # This entry point has been created to allow simpler backup onto
1665
+ # NTFS devices. I ran into a problem with a too-long, and special
1666
+ # name for a directory.
1667
+ #
1668
+ # Usage example:
1669
+ #
1670
+ # rbackup --use-shorter-name
1671
+ # rbackup tousb1 --use-shorter-name
1672
+ #
1673
+ # ===================================================================== #
1674
+ when /^-?-?use(-| |_)?shorter(-| |_)?name$/i,
1675
+ /^-?-?windows$/i,
1676
+ /^-?-?sane-symlink$/i
1677
+ do_use_simplified_directory
1678
+ # ===================================================================== #
1679
+ # === rbackup --pwd
1680
+ # ===================================================================== #
1681
+ when /^-?-?pwd$/i
1682
+ current_directory = (Dir.pwd+'/').squeeze('/')
1683
+ set_target_mountpoint(current_directory)
1684
+ # ===================================================================== #
1685
+ # === rbackup --autogenerated
1686
+ # ===================================================================== #
1687
+ when /^-?-?autogen$/,
1688
+ 'agen',
1689
+ 'autog',
1690
+ /^-?-?autogenerated$/i
1691
+ determine_whether_the_target_harddisc_is_a_ntfs_system
1692
+ try_to_backup_the_autogenerated_directory
1693
+ do_not_perform_the_regular_backup_routine
1694
+ else # else tag
1695
+ # =================================================================== #
1696
+ # === Backup an existing directory
1697
+ #
1698
+ # This entry point allows us to quickly backup an existing
1699
+ # directory.
1700
+ #
1701
+ # Usage example:
1702
+ #
1703
+ # rbackup /home/x/data/rpg/
1704
+ #
1705
+ # =================================================================== #
1706
+ if File.directory?(i)
1707
+ i = File.absolute_path(i)
1708
+ i << '/' unless i.end_with? '/'
1709
+ new_target = mountpoint?.squeeze('/')
1710
+ cpr(i, new_target)
1711
+ all_done_message
1712
+ do_not_perform_the_regular_backup_routine
1713
+ # =================================================================== #
1714
+ # === Backup individual .h files quickly
1715
+ #
1716
+ # This is a short circuit action here - we just backup an existing
1717
+ # .h file quickly.
1718
+ #
1719
+ # Invocation example:
1720
+ #
1721
+ # rbackup /usr/include/xvid.h
1722
+ #
1723
+ # =================================================================== #
1724
+ elsif File.exist?(i) and i.end_with?('.h')
1725
+ base_directory = '/BACKUP/include/'
1726
+ verbose_create_a_directory_at_this_position(base_directory)
1727
+ target = "#{base_directory}#{File.basename(i)}"
1728
+ opne "#{rev}Backing up towards `#{sfile(target)}#{rev}` (a mere copy operation)."
1729
+ copy_file(i, target)
1730
+ do_not_perform_the_regular_backup_routine
1731
+ else
1732
+ if i and i.start_with?('--')
1733
+ e "Option #{i} was not found. Exiting now."
1734
+ exit
1735
+ end
1736
+ end
1737
+ end
1738
+ end
1739
+ end
1740
+
1741
+ # ========================================================================= #
1742
+ # === is_the_harddisc_properly_mounted?
1743
+ # ========================================================================= #
1744
+ def is_the_harddisc_properly_mounted?
1745
+ result_of_df_T = `df -T`
1746
+ return result_of_df_T.include? '/Mount/HDD'
1747
+ end
1748
+
1749
+ # ========================================================================= #
1750
+ # === are_we_on_windows?
1751
+ # ========================================================================= #
1752
+ def are_we_on_windows?
1753
+ @internal_hash[:are_we_on_windows]
1754
+ end
1755
+
1756
+ # ========================================================================= #
1757
+ # === do_perform_the_backup_tasks (all tag)
1758
+ #
1759
+ # This method is the main powerhouse of this class. It connects all the
1760
+ # various steps together, one after the other.
1761
+ # ========================================================================= #
1762
+ def do_perform_the_backup_tasks
1763
+ backup_to_this_target = backup_to_this_target?
1764
+ determine_the_starting_time
1765
+ show_welcome_message
1766
+ create_file_keeping_track_of_when_the_last_backup_happened
1767
+ determine_whether_the_target_harddisc_is_a_ntfs_system
1768
+ if is_on_roebe? and are_we_trying_to_backup_to_a_local_harddisc?
1769
+ # ===================================================================== #
1770
+ # So in this case we want to backup to a local harddisc, such
1771
+ # as /Mount/HDD1. In this case we must find out whether the
1772
+ # harddisc is already mounted or not. If not then we will
1773
+ # mount it here.
1774
+ # ===================================================================== #
1775
+ if is_the_harddisc_properly_mounted? # In this case assume all is already mounted.
1776
+ # =================================================================== #
1777
+ # All is fine in this case - we do not have to do anything. At the
1778
+ # least we assume this is the case.
1779
+ # =================================================================== #
1780
+ else
1781
+ # =================================================================== #
1782
+ # Here we must mount it still. For now this uses a hardcoded approach.
1783
+ # =================================================================== #
1784
+ target = mountpoint?
1785
+ e "Mounting #{steelblue('/dev/sdb3')}#{rev} "\
1786
+ "towards #{steelblue(target)}#{rev}."
1787
+ esystem('mount /dev/sdb3 '+target)
1788
+ end
1789
+ end
1790
+ tab_title 'Backing up some data next, onto '+backup_to_this_target.to_s+' ...'
1791
+ cd last_backup_directory?
1792
+ # ======================================================================= #
1793
+ # Remove some log-files next, if necessary.
1794
+ # ======================================================================= #
1795
+ consider_removing_all_but_one_log_file
1796
+ # ======================================================================= #
1797
+ # The next method will rename entries such as:
1798
+ #
1799
+ # "last_backup-13.10.2018-21:07:20/"
1800
+ #
1801
+ # to
1802
+ #
1803
+ # "backup-13.10.2018-21:07:20/"
1804
+ #
1805
+ # specifically.
1806
+ #
1807
+ # This is necessary so that we can only have one such directory
1808
+ # name, after we are done with this method here.
1809
+ # ======================================================================= #
1810
+ consider_renaming_all_old_last_backup_directories
1811
+ # ======================================================================= #
1812
+ # We will also create a log file, to denote when we started to
1813
+ # do this current backup-operation.
1814
+ # ======================================================================= #
1815
+ create_the_log_last_backup_file
1816
+ create_the_directory_containing_the_last_backup
1817
+ create_a_symlink_pointing_to_that_directory_that_was_just_created
1818
+ # ======================================================================= #
1819
+ # === Back up the AUTOGENERATED directory
1820
+ #
1821
+ # We will next attempt to backup the directory at /AUTOGENERATED/.
1822
+ # This must come before we create a new directory at the mounted
1823
+ # USB device, simply because we may not copy anything at all,
1824
+ # or some error may happen that causes an interrupt.
1825
+ # ======================================================================= #
1826
+ try_to_backup_the_autogenerated_directory
1827
+ # ======================================================================= #
1828
+ # === Back up the audio directory as well
1829
+ # ======================================================================= #
1830
+ try_to_backup_the_audio_directory
1831
+ unless File.directory? backup_to_this_target
1832
+ FileUtils.mkdir_p(backup_to_this_target)
1833
+ end
1834
+ # ======================================================================= #
1835
+ # Next, iterate over the directories that we wish to backup.
1836
+ # ======================================================================= #
1837
+ backup_which_directories?.each {|this_directory|
1838
+ this_directory = ensure_trailing_backslash_for(this_directory)
1839
+ tab_title("Backing up #{this_directory}.")
1840
+ this_directory = this_directory.dup if this_directory.frozen?
1841
+ # ===================================================================== #
1842
+ # Ensure that we have a trailing '/' character here.
1843
+ # ===================================================================== #
1844
+ this_directory << '/' unless this_directory.end_with?('/')
1845
+ e "#{rev}Now backing up the directory #{sdir(this_directory)}"+
1846
+ ' onto '+
1847
+ steelblue(
1848
+ backup_to_this_target+
1849
+ File.basename(this_directory)
1850
+ )+'.'
1851
+ cpr(this_directory, backup_to_this_target)
1852
+ }
1853
+ # ======================================================================= #
1854
+ # === Delete all symlinks from the target, if we are using a
1855
+ # NTFS system as our target-device
1856
+ # ======================================================================= #
1857
+ if is_target_harddisc_a_ntfs_system?
1858
+ all_symlinks = return_all_symlinks_from_this_directory(backup_to_this_target)
1859
+ unless all_symlinks.empty?
1860
+ e "#{rev}As we are using a NTFS system, we will next remove all "+
1861
+ "#{royalblue(all_symlinks.size.to_s)} symlinks"
1862
+ e "#{rev}found at the following target: #{sdir(backup_to_this_target)}"
1863
+ e
1864
+ e steelblue('Specifically:')
1865
+ e
1866
+ e all_symlinks.join(', ').strip.chop
1867
+ e
1868
+ end
1869
+ all_symlinks.each {|this_symlink|
1870
+ remove_this_symlink(this_symlink)
1871
+ }
1872
+ end
1873
+ popup_notification(:backup_complete) if show_popup_notification?
1874
+ do_sync # Synchronize the USB devices here, before we determine the end time.
1875
+ determine_end_time
1876
+ report_time_difference
1877
+ try_to_unmount_the_device
1878
+ show_backup_complete_message
1879
+ tab_title('Backup is complete!')
1880
+ # or: tab_title ''
1881
+ end; alias start_backup do_perform_the_backup_tasks # === start_backup
1882
+ alias backup_everything do_perform_the_backup_tasks # === backup_everything
1883
+ alias do_backup do_perform_the_backup_tasks # === do_backup
1884
+
1885
+ # ========================================================================= #
1886
+ # === is_target_harddisc_a_ntfs_system?
1887
+ #
1888
+ # This method will return a boolean - true or false.
1889
+ #
1890
+ # It will return true if the target harddisc is a NTFS system, and
1891
+ # false otherwise.
1892
+ # ========================================================================= #
1893
+ def is_target_harddisc_a_ntfs_system?
1894
+ return_value = false
1895
+ _ = '/Mount'
1896
+ if mount_target?.include? _
1897
+ # ===================================================================== #
1898
+ # Next, determine what is mounted.
1899
+ # ===================================================================== #
1900
+ these_may_be_mounted = `df -T -ah`.split(N).select {|line| line.include? _ }
1901
+ if these_may_be_mounted and these_may_be_mounted.first and
1902
+ these_may_be_mounted.first.include?('fuseblk') # This may mean a NTFS system.
1903
+ # =================================================================== #
1904
+ # However had, in August of 2023 it was realiased that multiple
1905
+ # filesystems may be mounted, so the above assumption was a bit
1906
+ # too simple.
1907
+ # =================================================================== #
1908
+ return_value = true unless are_we_trying_to_backup_to_a_local_harddisc?
1909
+ end
1910
+ end
1911
+ return return_value
1912
+ end
1913
+
1914
+ # ========================================================================= #
1915
+ # === are_we_trying_to_backup_to_a_local_harddisc?
1916
+ # ========================================================================= #
1917
+ def are_we_trying_to_backup_to_a_local_harddisc?
1918
+ case mountpoint?
1919
+ when /HDD/ # e g. @mountpoint="/Mount/HDD1/"
1920
+ true
1921
+ else
1922
+ false
1923
+ end
1924
+ end
1925
+
1926
+ # ========================================================================= #
1927
+ # === run (run tag)
1928
+ # ========================================================================= #
1929
+ def run
1930
+ sanitize_the_commandline_arguments
1931
+ menu
1932
+ do_perform_the_backup_tasks if perform_the_regular_backup_routine?
1933
+ end
1934
+
1935
+ end; end
1936
+
1937
+ if __FILE__ == $PROGRAM_NAME
1938
+ BackupParadise::Backup.new(ARGV)
1939
+ end # rbackup
1940
+ # rbackup --help
1941
+ # rbackup --data_only
1942
+ # rbackup data_only