1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 """Parse command line, check for consistency, and set globals"""
23
24 from copy import copy
25 import optparse
26 import os
27 import re
28 import sys
29 import socket
30
31 try:
32 from hashlib import md5
33 except ImportError:
34 from md5 import new as md5
35
36 from duplicity import backend
37 from duplicity import dup_time
38 from duplicity import globals
39 from duplicity import gpg
40 from duplicity import log
41 from duplicity import path
42 from duplicity import selection
43
44
45 select_opts = []
46 select_files = []
47
48 full_backup = None
49 list_current = None
50 collection_status = None
51 cleanup = None
52 verify = None
53
54 commands = ["cleanup",
55 "collection-status",
56 "full",
57 "incremental",
58 "list-current-files",
59 "remove-older-than",
60 "remove-all-but-n-full",
61 "remove-all-inc-of-but-n-full",
62 "restore",
63 "verify",
64 ]
65
67 print >>sys.stderr, _("Warning: Option %s is pending deprecation "
68 "and will be removed in a future release.\n"
69 "Use of default filenames is strongly suggested.") % opt
70
71
73 return os.path.expanduser(os.path.expandvars(filename))
74
75
77 """
78 Return expanded version of archdir joined with backname.
79 """
80 assert globals.backup_name is not None, \
81 "expand_archive_dir() called prior to globals.backup_name being set"
82
83 return expand_fn(os.path.join(archdir, backname))
84
85
87 """
88 @param backend_url: URL to backend.
89 @returns A default backup name (string).
90 """
91
92
93
94
95
96
97
98
99
100
101
102 burlhash = md5()
103 burlhash.update(backend_url)
104 return burlhash.hexdigest()
105
108
114
116 fail = False
117
118 value = value.lower()
119 if value in ['e', 'error']:
120 verb = log.ERROR
121 elif value in ['w', 'warning']:
122 verb = log.WARNING
123 elif value in ['n', 'notice']:
124 verb = log.NOTICE
125 elif value in ['i', 'info']:
126 verb = log.INFO
127 elif value in ['d', 'debug']:
128 verb = log.DEBUG
129 else:
130 try:
131 verb = int(value)
132 if verb < 0 or verb > 9:
133 fail = True
134 except ValueError:
135 fail = True
136
137 if fail:
138
139
140
141 raise optparse.OptionValueError("Verbosity must be one of: digit [0-9], character [ewnid], "
142 "or word ['error', 'warning', 'notice', 'info', 'debug']. "
143 "The default is 4 (Notice). It is strongly recommended "
144 "that verbosity level is set at 2 (Warning) or higher.")
145
146 return verb
147
148
150 TYPES = optparse.Option.TYPES + ("file", "time", "verbosity",)
151 TYPE_CHECKER = copy(optparse.Option.TYPE_CHECKER)
152 TYPE_CHECKER["file"] = check_file
153 TYPE_CHECKER["time"] = check_time
154 TYPE_CHECKER["verbosity"] = check_verbosity
155
156 ACTIONS = optparse.Option.ACTIONS + ("extend",)
157 STORE_ACTIONS = optparse.Option.STORE_ACTIONS + ("extend",)
158 TYPED_ACTIONS = optparse.Option.TYPED_ACTIONS + ("extend",)
159 ALWAYS_TYPED_ACTIONS = optparse.Option.ALWAYS_TYPED_ACTIONS + ("extend",)
160
161 - def take_action(self, action, dest, opt, value, values, parser):
162 if action == "extend":
163 if not value:
164 return
165 if hasattr(values, dest) and getattr(values, dest):
166 setattr(values, dest, getattr(values, dest) + ' ' + value)
167 else:
168 setattr(values, dest, value)
169 else:
170 optparse.Option.take_action(
171 self, action, dest, opt, value, values, parser)
172
173 """
174 Fix:
175 File "/usr/lib/pythonX.X/optparse.py", line XXXX, in print_help
176 file.write(self.format_help().encode(encoding, "replace"))
177 UnicodeDecodeError: 'ascii' codec can't decode byte 0xXX in position XXXX:
178 See:
179 http://bugs.python.org/issue2931
180 http://mail.python.org/pipermail/python-dev/2006-May/065458.html
181 """
184 """
185 try to get the encoding or switch to UTF-8
186 which is default encoding in python3 and most recent unixes
187 """
188 encoding = getattr(file, "encoding", "UTF-8")
189 return encoding
190
192 """
193 overwrite method with proper utf-8 decoding
194 """
195 if file is None:
196 file = sys.stdout
197 encoding = self._get_encoding(file)
198 file.write(self.format_help().decode('utf-8').encode(encoding, "replace"))
199
200
212
213 def set_log_fd(fd):
214 if fd < 1:
215 raise optparse.OptionValueError("log-fd must be greater than zero.")
216 log.add_fd(fd)
217
218 def set_time_sep(sep, opt):
219 if sep == '-':
220 raise optparse.OptionValueError("Dash ('-') not valid for time-separator.")
221 globals.time_separator = sep
222 old_fn_deprecation(opt)
223
224 def add_selection(o, s, v, p):
225 select_opts.append((s, v))
226
227 def add_filelist(o, s, v, p):
228 filename = v
229 select_opts.append((s, filename))
230 try:
231 select_files.append(open(filename, "r"))
232 except IOError:
233 log.FatalError(_("Error opening file %s") % filename,
234 log.ErrorCode.cant_open_filelist)
235
236 def print_ver(o, s, v, p):
237 print "duplicity %s" % (globals.version)
238 sys.exit(0)
239
240 def add_rename(o, s, v, p):
241 globals.rename[os.path.normcase(os.path.normpath(v[0]))] = v[1]
242
243 parser = OPHelpFix( option_class=DupOption, usage=usage() )
244
245
246
247 parser.add_option("--allow-source-mismatch", action="store_true")
248
249
250
251
252
253
254 parser.add_option("--archive-dir", type="file", metavar=_("path"))
255
256
257
258 parser.add_option("--asynchronous-upload", action="store_const", const=1,
259 dest="async_concurrency")
260
261
262 parser.add_option("--config-dir", type="file", metavar=_("path"),
263 help=optparse.SUPPRESS_HELP)
264
265
266 parser.add_option("--current-time", type="int",
267 dest="current_time", help=optparse.SUPPRESS_HELP)
268
269
270 parser.add_option("--dry-run", action="store_true")
271
272
273
274 parser.add_option("--encrypt-key", type="string", metavar=_("gpg-key-id"),
275 dest="", action="callback",
276 callback=lambda o, s, v, p: globals.gpg_profile.recipients.append(v))
277
278
279 parser.add_option("--encrypt-secret-keyring", type="string", metavar=_("path"))
280
281 parser.add_option("--encrypt-sign-key", type="string", metavar=_("gpg-key-id"),
282 dest="", action="callback",
283 callback=lambda o, s, v, p: ( globals.gpg_profile.recipients.append(v), set_sign_key(v)) )
284
285
286
287
288
289 parser.add_option("--exclude", action="callback", metavar=_("shell_pattern"),
290 dest="", type="string", callback=add_selection)
291
292 parser.add_option("--exclude-device-files", action="callback",
293 dest="", callback=add_selection)
294
295 parser.add_option("--exclude-filelist", type="file", metavar=_("filename"),
296 dest="", action="callback", callback=add_filelist)
297
298 parser.add_option("--exclude-filelist-stdin", action="callback", dest="",
299 callback=lambda o, s, v, p: (select_opts.append(("--exclude-filelist", "standard input")),
300 select_files.append(sys.stdin)))
301
302 parser.add_option("--exclude-globbing-filelist", type="file", metavar=_("filename"),
303 dest="", action="callback", callback=add_filelist)
304
305
306
307 parser.add_option("--exclude-if-present", metavar=_("filename"), dest="",
308 type="file", action="callback", callback=add_selection)
309
310 parser.add_option("--exclude-other-filesystems", action="callback",
311 dest="", callback=add_selection)
312
313
314 parser.add_option("--exclude-regexp", metavar=_("regular_expression"),
315 dest="", type="string", action="callback", callback=add_selection)
316
317
318 parser.add_option("--extra-clean", action="store_true")
319
320
321 parser.add_option("--fail-on-volume", type="int",
322 help=optparse.SUPPRESS_HELP)
323
324
325 parser.add_option("--skip-volume", type="int",
326 help=optparse.SUPPRESS_HELP)
327
328
329
330
331
332 parser.add_option("--file-to-restore", "-r", action="callback", type="file",
333 metavar=_("path"), dest="restore_dir",
334 callback=lambda o, s, v, p: setattr(p.values, "restore_dir", v.rstrip('/')))
335
336
337 parser.add_option("--force", action="store_true")
338
339
340 parser.add_option("--ftp-passive", action="store_const", const="passive", dest="ftp_connection")
341 parser.add_option("--ftp-regular", action="store_const", const="regular", dest="ftp_connection")
342
343
344
345 parser.add_option("--full-if-older-than", type="time", dest="full_force_time", metavar=_("time"))
346
347 parser.add_option("--gio", action="callback", callback=use_gio)
348
349 parser.add_option("--gpg-options", action="extend", metavar=_("options"))
350
351
352
353
354
355 parser.add_option("--ignore-errors", action="callback",
356 dest="ignore_errors",
357 callback=lambda o, s, v, p: (log.Warn(
358 _("Running in 'ignore errors' mode due to %s; please "
359 "re-consider if this was not intended") % s),
360 setattr(p.values, "ignore errors", True)))
361
362
363
364
365 parser.add_option("--imap-full-address", action="store_true",
366 help=optparse.SUPPRESS_HELP)
367
368
369
370
371 parser.add_option("--imap-mailbox", metavar=_("imap_mailbox"))
372
373 parser.add_option("--include", action="callback", metavar=_("shell_pattern"),
374 dest="", type="string", callback=add_selection)
375 parser.add_option("--include-filelist", type="file", metavar=_("filename"),
376 dest="", action="callback", callback=add_filelist)
377 parser.add_option("--include-filelist-stdin", action="callback", dest="",
378 callback=lambda o, s, v, p: (select_opts.append(("--include-filelist", "standard input")),
379 select_files.append(sys.stdin)))
380 parser.add_option("--include-globbing-filelist", type="file", metavar=_("filename"),
381 dest="", action="callback", callback=add_filelist)
382 parser.add_option("--include-regexp", metavar=_("regular_expression"), dest="",
383 type="string", action="callback", callback=add_selection)
384
385 parser.add_option("--log-fd", type="int", metavar=_("file_descriptor"),
386 dest="", action="callback",
387 callback=lambda o, s, v, p: set_log_fd(v))
388
389
390
391 parser.add_option("--log-file", type="file", metavar=_("filename"),
392 dest="", action="callback",
393 callback=lambda o, s, v, p: log.add_file(v))
394
395
396 parser.add_option("--name", dest="backup_name", metavar=_("backup name"))
397
398
399 parser.add_option("--no-encryption", action="store_false", dest="encryption")
400
401
402 parser.add_option("--no-print-statistics", action="store_false", dest="print_statistics")
403
404
405
406 parser.add_option("--null-separator", action="store_true")
407
408
409
410
411
412 parser.add_option("--num-retries", type="int", metavar=_("number"))
413
414
415 parser.add_option("--numeric-owner", action="store_true")
416
417
418 parser.add_option("--old-filenames", action="callback",
419 dest="old_filenames",
420 callback=lambda o, s, v, p: (setattr(p.values, o.dest, True),
421 old_fn_deprecation(s)))
422
423
424 parser.add_option("--pydevd", action="store_true")
425
426
427 parser.add_option("--rename", type="file", action="callback", nargs=2,
428 callback=add_rename)
429
430
431
432
433
434
435 parser.add_option("--restore-time", "--time", "-t", type="time", metavar=_("time"))
436
437
438 parser.add_option("--rsync-options", action="extend", metavar=_("options"))
439
440
441
442 parser.add_option("--s3-european-buckets", action="store_true")
443
444
445 parser.add_option("--s3-use-rrs", action="store_true")
446
447
448
449
450 parser.add_option("--s3-use-new-style", action="store_true")
451
452
453
454 parser.add_option("--s3-unencrypted-connection", action="store_true")
455
456
457
458
459 parser.add_option("--s3-multipart-chunk-size", type="int", action="callback", metavar=_("number"),
460 callback=lambda o, s, v, p: setattr(p.values, "s3_multipart_chunk_size", v*1024*1024))
461
462
463
464 if sys.version_info[:2] >= (2,6):
465 parser.add_option("--s3-use-multiprocessing", action="store_true")
466
467
468
469 parser.add_option("--scp-command", metavar=_("command"))
470
471
472
473 parser.add_option("--sftp-command", metavar=_("command"))
474
475
476 parser.add_option("--short-filenames", action="callback",
477 dest="short_filenames",
478 callback=lambda o, s, v, p: (setattr(p.values, o.dest, True),
479 old_fn_deprecation(s)))
480
481
482
483 parser.add_option("--sign-key", type="string", metavar=_("gpg-key-id"),
484 dest="", action="callback",
485 callback=lambda o, s, v, p: set_sign_key(v))
486
487
488 parser.add_option("--ssh-askpass", action="store_true")
489
490
491 parser.add_option("--ssh-options", action="extend", metavar=_("options"))
492
493
494 parser.add_option("--tempdir", dest="temproot", type="file", metavar=_("path"))
495
496
497
498
499 parser.add_option("--timeout", type="int", metavar=_("seconds"))
500
501
502
503
504
505 parser.add_option("--time-separator", type="string", metavar=_("char"),
506 action="callback",
507 callback=lambda o, s, v, p: set_time_sep(v, s))
508
509
510 parser.add_option("--use-agent", action="store_true")
511
512 parser.add_option("--use-scp", action="store_true")
513
514 parser.add_option("--verbosity", "-v", type="verbosity", metavar="[0-9]",
515 dest="", action="callback",
516 callback=lambda o, s, v, p: log.setverbosity(v))
517
518 parser.add_option("-V", "--version", action="callback", callback=print_ver)
519
520
521
522
523
524 parser.add_option("--volsize", type="int", action="callback", metavar=_("number"),
525 callback=lambda o, s, v, p: setattr(p.values, "volsize", v*1024*1024))
526
527
528 (options, args) = parser.parse_args()
529
530
531
532
533
534 for f in filter(lambda x: x and not x.startswith("_"), dir(options)):
535 v = getattr(options, f)
536
537
538 if v is not None:
539 setattr(globals, f, v)
540
541 socket.setdefaulttimeout(globals.timeout)
542
543
544 cmd = ""
545 num_expect = 2
546
547
548 if args:
549 cmd = args.pop(0)
550 possible = [c for c in commands if c.startswith(cmd)]
551
552 if len(possible) > 1:
553 command_line_error("command '%s' not unique, could be %s" % (cmd, possible))
554
555 elif len(possible) == 1:
556 cmd = possible[0]
557
558 elif not possible:
559 args.insert(0, cmd)
560
561 if cmd == "cleanup":
562 cleanup = True
563 num_expect = 1
564 elif cmd == "collection-status":
565 collection_status = True
566 num_expect = 1
567 elif cmd == "full":
568 full_backup = True
569 num_expect = 2
570 elif cmd == "incremental":
571 globals.incremental = True
572 num_expect = 2
573 elif cmd == "list-current-files":
574 list_current = True
575 num_expect = 1
576 elif cmd == "remove-older-than":
577 try:
578 arg = args.pop(0)
579 except Exception:
580 command_line_error("Missing time string for remove-older-than")
581 globals.remove_time = dup_time.genstrtotime(arg)
582 num_expect = 1
583 elif cmd == "remove-all-but-n-full" or cmd == "remove-all-inc-of-but-n-full":
584 if cmd == "remove-all-but-n-full" :
585 globals.remove_all_but_n_full_mode = True
586 if cmd == "remove-all-inc-of-but-n-full" :
587 globals.remove_all_inc_of_but_n_full_mode = True
588 try:
589 arg = args.pop(0)
590 except Exception:
591 command_line_error("Missing count for " + cmd)
592 globals.keep_chains = int(arg)
593 if not globals.keep_chains > 0:
594 command_line_error(cmd + " count must be > 0")
595 num_expect = 1
596 elif cmd == "verify":
597 verify = True
598
599 if len(args) != num_expect:
600 command_line_error("Expected %d args, got %d" % (num_expect, len(args)))
601
602
603 for loc in range(len(args)):
604 if not '://' in args[loc]:
605 args[loc] = expand_fn(args[loc])
606
607
608
609
610
611 if len(args) < 1:
612 command_line_error("Too few arguments")
613 elif len(args) == 1:
614 backend_url = args[0]
615 elif len(args) == 2:
616 lpath, backend_url = args_to_path_backend(args[0], args[1])
617 else:
618 command_line_error("Too many arguments")
619
620 if globals.backup_name is None:
621 globals.backup_name = generate_default_backup_name(backend_url)
622
623
624 set_archive_dir(expand_archive_dir(globals.archive_dir,
625 globals.backup_name))
626
627 log.Info(_("Using archive dir: %s") % (globals.archive_dir.name,))
628 log.Info(_("Using backup name: %s") % (globals.backup_name,))
629
630 return args
631
632
634 """Indicate a command line error and exit"""
635 log.FatalError(_("Command line error: %s") % (message,) + "\n" +
636 _("Enter 'duplicity --help' for help screen."),
637 log.ErrorCode.command_line)
638
639
641 """Returns terse usage info. The code is broken down into pieces for ease of
642 translation maintenance. Any comments that look extraneous or redundant should
643 be assumed to be for the benefit of translators, since they can get each string
644 (paired with its preceding comment, if any) independently of the others."""
645
646 dict = {
647
648
649 'absolute_path' : _("absolute_path"),
650
651
652
653 'alias' : _("alias"),
654
655
656
657
658 'bucket_name' : _("bucket_name"),
659
660
661 'char' : _("char"),
662
663
664 'command' : _("command"),
665
666
667
668
669 'container_name' : _("container_name"),
670
671
672 'count' : _("count"),
673
674
675 'directory' : _("directory"),
676
677
678
679 'filename' : _("filename"),
680
681
682
683 'gpg_key_id' : _("gpg-key-id"),
684
685
686
687
688 'module' : _("module"),
689
690
691
692
693 'number' : _("number"),
694
695
696
697
698 'options' : _("options"),
699
700
701
702 'other_host' : _("other.host"),
703
704
705
706 'password' : _("password"),
707
708
709
710 'path' : _("path"),
711
712
713
714 'port' : _("port"),
715
716
717
718
719 'prefix' : _("prefix"),
720
721
722
723 'relative_path' : _("relative_path"),
724
725
726
727 'seconds' : _("seconds"),
728
729
730
731
732
733 'shell_pattern' : _("shell_pattern"),
734
735
736
737
738 'some_dir' : _("some_dir"),
739
740
741
742
743
744 'source_dir' : _("source_dir"),
745
746
747
748
749 'source_url' : _("source_url"),
750
751
752
753
754
755 'target_dir' : _("target_dir"),
756
757
758
759
760 'target_url' : _("target_url"),
761
762
763
764
765 'time' : _("time"),
766
767
768
769
770 'user' : _("user") }
771
772
773 msg = """
774 duplicity [full|incremental] [%(options)s] %(source_dir)s %(target_url)s
775 duplicity [restore] [%(options)s] %(source_url)s %(target_dir)s
776 duplicity verify [%(options)s] %(source_url)s %(target_dir)s
777 duplicity collection-status [%(options)s] %(target_url)s
778 duplicity list-current-files [%(options)s] %(target_url)s
779 duplicity cleanup [%(options)s] %(target_url)s
780 duplicity remove-older-than %(time)s [%(options)s] %(target_url)s
781 duplicity remove-all-but-n-full %(count)s [%(options)s] %(target_url)s
782 duplicity remove-all-inc-of-but-n-full %(count)s [%(options)s] %(target_url)s
783
784 """ % dict
785
786
787 msg = msg + _("Backends and their URL formats:") + """
788 cf+http://%(container_name)s
789 file:///%(some_dir)s
790 ftp://%(user)s[:%(password)s]@%(other_host)s[:%(port)s]/%(some_dir)s
791 ftps://%(user)s[:%(password)s]@%(other_host)s[:%(port)s]/%(some_dir)s
792 hsi://%(user)s[:%(password)s]@%(other_host)s[:%(port)s]/%(some_dir)s
793 imap://%(user)s[:%(password)s]@%(other_host)s[:%(port)s]/%(some_dir)s
794 rsync://%(user)s[:%(password)s]@%(other_host)s[:%(port)s]::/%(module)s/%(some_dir)s
795 rsync://%(user)s[:%(password)s]@%(other_host)s[:%(port)s]/%(relative_path)s
796 rsync://%(user)s[:%(password)s]@%(other_host)s[:%(port)s]//%(absolute_path)s
797 s3://%(other_host)s/%(bucket_name)s[/%(prefix)s]
798 s3+http://%(bucket_name)s[/%(prefix)s]
799 scp://%(user)s[:%(password)s]@%(other_host)s[:%(port)s]/%(some_dir)s
800 ssh://%(user)s[:%(password)s]@%(other_host)s[:%(port)s]/%(some_dir)s
801 tahoe://%(alias)s/%(directory)s
802 webdav://%(user)s[:%(password)s]@%(other_host)s/%(some_dir)s
803 webdavs://%(user)s[:%(password)s]@%(other_host)s/%(some_dir)s
804 gdocs://%(user)s[:%(password)s]@%(other_host)s/%(some_dir)s
805
806 """ % dict
807
808
809 msg = msg + _("Commands:") + """
810 cleanup <%(target_url)s>
811 collection-status <%(target_url)s>
812 full <%(source_dir)s> <%(target_url)s>
813 incr <%(source_dir)s> <%(target_url)s>
814 list-current-files <%(target_url)s>
815 restore <%(target_url)s> <%(source_dir)s>
816 remove-older-than <%(time)s> <%(target_url)s>
817 remove-all-but-n-full <%(count)s> <%(target_url)s>
818 remove-all-inc-of-but-n-full <%(count)s> <%(target_url)s>
819 verify <%(target_url)s> <%(source_dir)s>""" % dict
820
821 return msg
822
823
837
838
840 """Set globals.sign_key assuming proper key given"""
841 if not len(sign_key) == 8 or not re.search("^[0-9A-F]*$", sign_key):
842 log.FatalError(_("Sign key should be an 8 character hex string, like "
843 "'AA0E73D2'.\nReceived '%s' instead.") % (sign_key,),
844 log.ErrorCode.bad_sign_key)
845 globals.gpg_profile.sign_key = sign_key
846
847
854
855
857 """
858 Given exactly two arguments, arg1 and arg2, figure out which one
859 is the backend URL and which one is a local path, and return
860 (local, backend).
861 """
862 arg1_is_backend, arg2_is_backend = backend.is_backend_url(arg1), backend.is_backend_url(arg2)
863
864 if not arg1_is_backend and not arg2_is_backend:
865 command_line_error(
866 """One of the arguments must be an URL. Examples of URL strings are
867 "scp://user@host.net:1234/path" and "file:///usr/local". See the man
868 page for more information.""")
869 if arg1_is_backend and arg2_is_backend:
870 command_line_error("Two URLs specified. "
871 "One argument should be a path.")
872 if arg1_is_backend:
873 return (arg2, arg1)
874 elif arg2_is_backend:
875 return (arg1, arg2)
876 else:
877 raise AssertionError('should not be reached')
878
879
881 """Figure out which arg is url, set backend
882
883 Return value is pair (path_first, path) where is_first is true iff
884 path made from arg1.
885
886 """
887 path, bend = args_to_path_backend(arg1, arg2)
888
889 globals.backend = backend.get_backend(bend)
890
891 if path == arg2:
892 return (None, arg2)
893 else:
894 return (1, arg1)
895
896
918
919
921 """Final consistency check, see if something wrong with command line"""
922 global full_backup, select_opts, list_current
923 def assert_only_one(arglist):
924 """Raises error if two or more of the elements of arglist are true"""
925 n = 0
926 for m in arglist:
927 if m:
928 n+=1
929 assert n <= 1, "Invalid syntax, two conflicting modes specified"
930 if action in ["list-current", "collection-status",
931 "cleanup", "remove-old", "remove-all-but-n-full", "remove-all-inc-of-but-n-full"]:
932 assert_only_one([list_current, collection_status, cleanup,
933 globals.remove_time is not None])
934 elif action == "restore" or action == "verify":
935 if full_backup:
936 command_line_error("--full option cannot be used when "
937 "restoring or verifying")
938 elif globals.incremental:
939 command_line_error("--incremental option cannot be used when "
940 "restoring or verifying")
941 if select_opts and action == "restore":
942 log.Warn( _("Command line warning: %s") % _("Selection options --exclude/--include\n"
943 "currently work only when backing up,"
944 "not restoring.") )
945 else:
946 assert action == "inc" or action == "full"
947 if verify:
948 command_line_error("--verify option cannot be used "
949 "when backing up")
950 if globals.restore_dir:
951 command_line_error("restore option incompatible with %s backup"
952 % (action,))
953
954
956 """Process command line, set globals, return action
957
958 action will be "list-current", "collection-status", "cleanup",
959 "remove-old", "restore", "verify", "full", or "inc".
960
961 """
962 globals.gpg_profile = gpg.GPGProfile()
963
964 args = parse_cmdline_options(cmdline_list)
965
966
967 backend.import_backends()
968
969
970
971 assert len(args) >= 1 and len(args) <= 2, "arg count should have been checked already"
972
973 if len(args) == 1:
974 if list_current:
975 action = "list-current"
976 elif collection_status:
977 action = "collection-status"
978 elif cleanup:
979 action = "cleanup"
980 elif globals.remove_time is not None:
981 action = "remove-old"
982 elif globals.remove_all_but_n_full_mode:
983 action = "remove-all-but-n-full"
984 elif globals.remove_all_inc_of_but_n_full_mode:
985 action = "remove-all-inc-of-but-n-full"
986 else:
987 command_line_error("Too few arguments")
988 globals.backend = backend.get_backend(args[0])
989 if not globals.backend:
990 log.FatalError(_("""Bad URL '%s'.
991 Examples of URL strings are "scp://user@host.net:1234/path" and
992 "file:///usr/local". See the man page for more information.""") % (args[0],),
993 log.ErrorCode.bad_url)
994 elif len(args) == 2:
995
996 backup, local_pathname = set_backend(args[0], args[1])
997 if backup:
998 if full_backup:
999 action = "full"
1000 else:
1001 action = "inc"
1002 else:
1003 if verify:
1004 action = "verify"
1005 else:
1006 action = "restore"
1007
1008 process_local_dir(action, local_pathname)
1009 if action in ['full', 'inc', 'verify']:
1010 set_selection()
1011 elif len(args) > 2:
1012 raise AssertionError("this code should not be reachable")
1013
1014 check_consistency(action)
1015 log.Info(_("Main action: ") + action)
1016 return action
1017