1
# Copyright 2002 Ben Escoto
3
# This file is part of duplicity.
5
# duplicity is free software; you can redistribute it and/or modify it
6
# under the terms of the GNU General Public License as published by
7
# the Free Software Foundation, Inc., 675 Mass Ave, Cambridge MA
8
# 02139, USA; either version 2 of the License, or (at your option) any
9
# later version; incorporated herein by reference.
11
"""Parse command line, check for consistency, and set globals"""
13
import getopt, re, sys
14
import backends, globals, log, path, selection, gpg, dup_time
16
select_opts = [] # Will hold all the selection options
17
full_backup = None # Will be set to true if -f or --full option given
19
def parse_cmdline_options(arglist):
20
"""Parse argument list"""
21
global select_opts, full_backup
22
try: optlist, args = getopt.getopt(arglist, "firt:v:V",
23
["allow-source-mismatch", "archive-dir=", "current-time=",
24
"encrypt-key=", "exclude=", "exclude-device-files",
25
"exclude-filelist=", "exclude-filelist-stdin",
26
"exclude-other-filesystems", "exclude-regexp=",
27
"file-to-restore=", "full", "incremental", "include=",
28
"include-filelist=", "include-filelist-stdin",
29
"include-regexp=", "null-separator", "restore-dir=",
30
"restore-time=", "sign-key=", "verbosity="])
31
except getopt.error, e:
32
command_line_error("%s" % (str(e),))
34
for opt, arg in optlist:
35
if opt == "--allow-source-mismatch": globals.allow_source_mismatch = 1
36
elif opt == "--archive-dir": set_archive_dir(arg)
37
elif opt == "--current-time":
38
globals.current_time = get_int(arg, "current-time")
39
elif opt == "--encrypt-key":
40
globals.gpg_profile.recipients.append(arg)
41
elif (opt == "--exclude" or opt == "--exclude-regexp" or
42
opt == "--include" or opt == "--include-regexp"):
43
select_opts.append((opt, arg))
44
elif (opt == "--exclude-device-files" or
45
opt == "--exclude-other-filesystems"):
46
select_opts.append((opt, None))
47
elif opt == "--exclude-filelist" or opt == "--include-filelist":
48
select_opts.append((opt, (arg, open(arg, "rb"))))
49
elif (opt == "--exclude-filelist-stdin" or
50
opt == "--include-filelist-stdin"):
51
select_opts.append((opt, ("stdin", sys.stdin)))
52
elif opt == "-f" or opt == "--full": full_backup = 1
53
elif opt == "-i" or opt == "--incremental": globals.incremental = 1
54
elif opt == "-r" or opt == "--file-to-restore":
55
globals.restore_dir = arg
56
elif opt == "-t" or opt == "--restore-time":
57
globals.restore_time = dup_time.genstrtotime(arg)
58
elif opt == "--sign-key": set_sign_key(arg)
60
print "duplicity version", str(globals.version)
62
elif opt == "-v" or opt == "--verbosity": log.setverbosity(int(arg))
63
else: command_line_error("Unknown option %s" % opt)
67
def command_line_error(message):
68
"""Indicate a command line error and exit"""
69
sys.stderr.write("Command line error: %s\n" % (message,))
70
sys.stderr.write("See the duplicity manual page for instructions\n")
73
def get_int(int_string, description):
74
"""Require that int_string be an integer, return int value"""
75
try: return int(int_string)
76
except ValueError: log.FatalError("Received '%s' for %s, need integer" %
77
(int_string, description))
79
def set_archive_dir(dirstring):
80
"""Check archive dir and set global"""
81
archive_dir = path.Path(dirstring)
82
if not archive_dir.isdir():
83
log.FatalError("Specified archive directory '%s' does not exist "
84
" or is not a directory" % (archive_dir.name,))
85
globals.archive_dir = archive_dir
87
def set_sign_key(sign_key):
88
"""Set globals.sign_key assuming proper key given"""
89
if not len(sign_key) == 8 or not re.search("^[0-9A-F]*$", sign_key):
90
log.FatalError("Sign key should be an 8 character hex string, like "
91
"'AA0E73D2'.\nReceived '%s' instead." % (sign_key,))
92
globals.gpg_profile.sign_key = sign_key
95
"""Figure out the main action from the arguments"""
97
if len(args) < 3: command_line_error("Too few arguments")
99
if command != "restore" and len(args) < 4:
100
command_line_error("Too few arguments")
101
if len(args) > 4: command_line_error("Too many arguments")
103
if command == "inc" or command == "increment": command = "inc"
104
return command, args[1:]
107
"""Return selection iter starting at filename with arguments applied"""
109
sel = selection.Select(globals.local_path)
110
sel.ParseArgs(select_opts)
111
globals.select = sel.set_iter()
113
def set_backend(arg1, arg2):
114
"""Figure out which arg is url, set backend
116
Return value is pair (path_first, path) where is_first is true iff
120
backend1, backend2 = backends.get_backend(arg1), backends.get_backend(arg2)
121
if not backend1 and not backend2:
123
"""One of the arguments must be an URL. Examples of URL strings are
124
"scp://user@host.net:1234/path" and "file:///usr/local". See the man
125
page for more information.""")
126
if backend1 and backend2:
127
command_line_error("Two URLs specified. "
128
"One argument should be a path.")
130
globals.backend = backend1
133
globals.backend = backend2
136
def process_local_dir(action, local_pathname):
137
"""Check local directory, set globals.local_path"""
138
local_path = path.Path(path.Path(local_pathname).get_canonical())
139
if action == "restore":
140
if local_path.exists() and not local_path.isemptydir():
141
log.FatalError("Restore destination directory %s already "
142
"exists.\nWill not overwrite." % (local_pathname,))
144
assert action == "full" or action == "inc"
145
if not local_path.exists():
146
log.FatalError("Backup source directory %s does not exist."
147
% (local_path.name,))
148
globals.local_path = local_path
150
def check_consistency(action):
151
"""Final consistency check, see if something wrong with command line"""
152
global full_backup, select_opts
153
if action == "restore":
155
command_line_error("--full option cannot be used when restoring")
156
elif globals.incremental:
157
command_line_error("--incremental option cannot be used when "
160
command_line_error("Selection options --exclude/--include\n"
161
"currently work only when backing up, "
164
assert action == "inc" or action == "full"
165
if globals.restore_dir:
166
log.FatalError("--restore-dir option incompatible with %s backup"
169
def ProcessCommandLine(cmdline_list):
170
"""Process command line, set globals, return action
172
action will be "restore", "full", or "inc".
176
globals.gpg_profile = gpg.GPGProfile()
178
args = parse_cmdline_options(cmdline_list)
179
if len(args) < 2: command_line_error("Too few arguments")
180
elif len(args) > 2: command_line_error("Too many arguments")
182
backup, local_pathname = set_backend(args[0], args[1])
184
if full_backup: action = "full"
186
else: action = "restore"
188
process_local_dir(action, local_pathname)
189
if backup: set_selection()
190
check_consistency(action)