backup_paradise 1.3.5

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