root/plugins/moto-sync/mototool

Revision 2704, 6.3 kB (checked in by abaumann, 1 year ago)

really abort if the user says to (oops!)
fixes #563

  • Property svn:executable set to *
Line 
1 #!/usr/bin/env python
2
3 """
4 Test/utility code for moto-sync plugin, independent of opensync
5 """
6
7 import sys, types, os.path, popen2
8 from optparse import OptionParser
9
10 try:
11     import motosync
12 except ImportError:
13     # motosync wasn't in our standard import path
14     # try looking in the opensync python plugin dir for it
15     child = popen2.Popen3('pkg-config opensync-1.0 --variable=libdir')
16     libdir = child.fromchild.readline().rstrip('\n')
17     if child.wait() != 0 or not os.path.isdir(libdir):
18         # no pkgconfig, try standard install path
19         libdir = '/usr/lib'
20         if not os.path.isdir(os.path.join(libdir, 'opensync')):
21             sys.stderr.write("Error: couldn't locate OpenSync library directory\n")
22             sys.exit(1)
23     sys.path.append(os.path.join(libdir, 'opensync', 'python-plugins'))
24     import motosync
25
26 DEFAULT_DEVICE = '/dev/ttyACM0'
27
28 def parse_args():
29     p = OptionParser(version=motosync.__revision__,
30                      description='moto-sync test utility')
31     p.add_option('-d', '--device', dest='device',
32                  help='device to access phone, defaults to %s' % DEFAULT_DEVICE)
33     p.add_option('-t', '--type', action='append', dest='objtype',
34                  choices=motosync.SUPPORTED_OBJTYPES,
35                  help='object type to access (defaults to all types)')
36     p.add_option('-f', '--file', dest='filename',
37                  help='name of backup/restore data file')
38     p.add_option('--backup', action='store_const', dest='mode', const='backup',
39                  help='backup entries from the phone to a file')
40     p.add_option('--restore', action='store_const', dest='mode', const='restore',
41                  help='restore a backup created with the --backup option')
42     p.add_option('--delete', action='store_const', dest='mode', const='delete',
43                  help='delete all entries on the phone')
44     p.set_defaults(device=DEFAULT_DEVICE, filename=None, mode=None, objtype=None)
45     options, args = p.parse_args()
46     if not options.mode:
47         p.error('one of the backup, restore, or delete actions is required')
48     if options.mode in ['backup', 'restore'] and not options.filename:
49         p.error('this action requires a --file argument')
50     return options
51
52 def prompt_user(options):
53     """Prompt the user if they are trying to write to the phone."""
54     if options.mode == 'delete' or options.mode == 'restore':
55         print ('WARNING: About to %s all %s entries on the phone!'
56                % (options.mode, ' & '.join(options.objtype)))
57         print 'Are you sure? [yn] ',
58         if sys.stdin.read(1).lower() != 'y':
59             print 'Operation aborted'
60             sys.exit(1)
61
62 def pack_backup(typestr, edata):
63     """pack event data into a single-line string to write to the backup file"""
64     strings = []
65     for val in edata:
66         if type(val) == types.IntType:
67             strings.append(str(val))
68         else:
69             if val == '':
70                 strings.append('')
71             else:
72                 s = val.encode('utf8')
73                 # escape \ to \\, " to \" and newline to \n
74                 s = s.replace('\\', '\\\\')
75                 s = s.replace('"', '\\"')
76                 s = s.replace('\n', '\\n')
77                 strings.append('"' + s + '"')
78     return ','.join([typestr] + strings) + '\n'
79
80 def unpack_backup(line):
81     """reverse the pack_backup function above"""
82     # FIXME: is the unescaping sane with arbitrary utf8 characters?
83     if line[-1] == '\n':
84         line = line[:-1]
85     parts = []
86     nextpart = ''
87     wasquote = False
88     inquote = False
89     inescape = False
90     for c in line:
91         if c == ',' and not inquote:
92             if not wasquote and len(parts) > 0 and nextpart != '':
93                 nextpart = int(nextpart)
94             if wasquote:
95                 nextpart = nextpart.decode('utf8')
96             parts.append(nextpart)
97             nextpart = ''
98             wasquote = False
99         elif c == '\\' and inquote and not inescape:
100             inescape = True
101         elif inquote and inescape:
102             inescape = False
103             if c == 'n':
104                 c = '\n'
105             else:
106                 assert(c == '"' or c == '\\')
107             nextpart = nextpart + c
108         elif c == '"':
109             wasquote = True
110             inquote = not inquote
111         else:
112             nextpart = nextpart + c
113     if wasquote or nextpart == '':
114         parts.append(nextpart.decode('utf8'))
115     else:
116         parts.append(int(nextpart))
117     return parts[0], parts[1:]
118
119 def main():
120     options = parse_args()
121     if not options.objtype:
122         options.objtype = motosync.SUPPORTED_OBJTYPES
123
124     prompt_user(options)
125     pc = motosync.PhoneComms(options.device)
126     pc.connect()
127
128     if options.mode == 'delete' or options.mode == 'restore':
129         if 'event' in options.objtype:
130             for (edata, _) in pc.read_events():
131                 pc.delete_event(edata[0])
132         if 'contact' in options.objtype:
133             pc.read_contact_params()
134             for edata in pc.read_contacts():
135                 pc.delete_contact(edata[0])
136
137     if options.mode == 'backup':
138         f = open(options.filename, 'w')
139         if 'event' in options.objtype:
140             for (edata, exceptions) in pc.read_events():
141                 f.write(pack_backup('E', edata))
142                 if exceptions != []:
143                     f.write(pack_backup('X', exceptions))
144         if 'contact' in options.objtype:
145             pc.read_contact_params()
146             for edata in pc.read_contacts():
147                 f.write(pack_backup('C', edata))
148         f.close()
149
150     if options.mode == 'restore':
151         events = []
152         contacts = []
153         f = open(options.filename, 'r')
154         for line in f.readlines():
155             typestr, edata = unpack_backup(line)
156             if typestr == 'E':
157                 events.append((edata, []))
158             elif typestr == 'X':
159                 events[-1] = (events[-1][0], edata)
160             elif typestr == 'C':
161                 contacts.append(edata)
162             else:
163                 assert(False, 'Unexpected type %s' % typestr)
164         f.close()
165
166         if 'event' in options.objtype:
167             for (e, x) in events:
168                 pc.write_event(e, x)
169         if 'contact' in options.objtype:
170             for e in contacts:
171                 pc.write_contact(e)
172
173     pc.disconnect()
174
175
176 if __name__ == "__main__":
177     main()
Note: See TracBrowser for help on using the browser.