~ubuntu-branches/debian/sid/calibre/sid

« back to all changes in this revision

Viewing changes to src/calibre/devices/cli.py

  • Committer: Package Import Robot
  • Author(s): Martin Pitt
  • Date: 2014-05-14 18:17:50 UTC
  • mfrom: (1.5.10)
  • Revision ID: package-import@ubuntu.com-20140514181750-xyrxqa47dbw0qfhu
Tags: 1.36.0+dfsg-1
* New upstream release:
  - Fixes editing of metadata (Closes: #741638)

Show diffs side-by-side

added added

removed removed

Lines of Context:
10
10
from optparse import OptionParser
11
11
 
12
12
from calibre import __version__, __appname__, human_readable, fsync
13
 
from calibre.devices.errors import PathError
14
13
from calibre.devices.errors import ArgumentError, DeviceError, DeviceLocked
15
14
from calibre.customize.ui import device_plugins
16
15
from calibre.devices.scanner import DeviceScanner
17
16
from calibre.utils.config import device_prefs
18
17
 
19
 
MINIMUM_COL_WIDTH = 12 #: Minimum width of columns in ls output
 
18
MINIMUM_COL_WIDTH = 12  # : Minimum width of columns in ls output
20
19
 
21
20
class FileFormatter(object):
 
21
 
22
22
    def __init__(self, file):
23
23
        self.is_dir      = file.is_dir
24
24
        self.is_readonly = file.is_readonly
33
33
        doc=""" The mode string for this file. There are only two modes read-only and read-write """
34
34
        def fget(self):
35
35
            mode, x = "-", "-"
36
 
            if self.is_dir: mode, x = "d", "x"
37
 
            if self.is_readonly: mode += "r-"+x+"r-"+x+"r-"+x
38
 
            else: mode += "rw"+x+"rw"+x+"rw"+x
 
36
            if self.is_dir:
 
37
                mode, x = "d", "x"
 
38
            if self.is_readonly:
 
39
                mode += "r-"+x+"r-"+x+"r-"+x
 
40
            else:
 
41
                mode += "rw"+x+"rw"+x+"rw"+x
39
42
            return mode
40
43
        return property(doc=doc, fget=fget)
41
44
 
49
52
            return name
50
53
        return property(doc=doc, fget=fget)
51
54
 
52
 
 
53
55
    @dynamic_property
54
56
    def name_in_color(self):
55
57
        doc=""" The name in ANSI text. Directories are blue, ebooks are green """
56
58
        def fget(self):
57
59
            cname = self.name
58
60
            blue, green, normal = "", "", ""
59
 
            if self.term: blue, green, normal = self.term.BLUE, self.term.GREEN, self.term.NORMAL
60
 
            if self.is_dir: cname = blue + self.name + normal
 
61
            if self.term:
 
62
                blue, green, normal = self.term.BLUE, self.term.GREEN, self.term.NORMAL
 
63
            if self.is_dir:
 
64
                cname = blue + self.name + normal
61
65
            else:
62
66
                ext = self.name[self.name.rfind("."):]
63
 
                if ext in (".pdf", ".rtf", ".lrf", ".lrx", ".txt"): cname = green + self.name + normal
 
67
                if ext in (".pdf", ".rtf", ".lrf", ".lrx", ".txt"):
 
68
                    cname = green + self.name + normal
64
69
            return cname
65
70
        return property(doc=doc, fget=fget)
66
71
 
93
98
    print "Mime type:       ", info[3]
94
99
 
95
100
def ls(dev, path, recurse=False, human_readable_size=False, ll=False, cols=0):
96
 
    def col_split(l, cols): # split list l into columns
 
101
    def col_split(l, cols):  # split list l into columns
97
102
        rows = len(l) / cols
98
103
        if len(l) % cols:
99
104
            rows += 1
102
107
            m.append(l[i::rows])
103
108
        return m
104
109
 
105
 
    def row_widths(table): # Calculate widths for each column in the row-wise table
 
110
    def row_widths(table):  # Calculate widths for each column in the row-wise table
106
111
        tcols = len(table[0])
107
 
        rowwidths = [ 0 for i in range(tcols) ]
 
112
        rowwidths = [0 for i in range(tcols)]
108
113
        for row in table:
109
114
            c = 0
110
115
            for item in row:
113
118
        return rowwidths
114
119
 
115
120
    output = StringIO.StringIO()
116
 
    if path.endswith("/") and len(path) > 1: path = path[:-1]
 
121
    if path.endswith("/") and len(path) > 1:
 
122
        path = path[:-1]
117
123
    dirs = dev.list(path, recurse)
118
124
    for dir in dirs:
119
 
        if recurse: print >>output, dir[0] + ":"
 
125
        if recurse:
 
126
            print >>output, dir[0] + ":"
120
127
        lsoutput, lscoloutput = [], []
121
128
        files = dir[1]
122
129
        maxlen = 0
123
 
        if ll: # Calculate column width for size column
 
130
        if ll:  # Calculate column width for size column
124
131
            for file in files:
125
132
                size = len(str(file.size))
126
133
                if human_readable_size:
127
134
                    file = FileFormatter(file)
128
135
                    size = len(file.human_readable_size)
129
 
                if size > maxlen: maxlen = size
 
136
                if size > maxlen:
 
137
                    maxlen = size
130
138
        for file in files:
131
139
            file = FileFormatter(file)
132
140
            name = file.name if ll else file.isdir_name
134
142
            lscoloutput.append(name)
135
143
            if ll:
136
144
                size = str(file.size)
137
 
                if human_readable_size: size = file.human_readable_size
 
145
                if human_readable_size:
 
146
                    size = file.human_readable_size
138
147
                print >>output, file.mode_string, ("%"+str(maxlen)+"s")%size, file.modification_time, name
139
148
        if not ll and len(lsoutput) > 0:
140
149
            trytable = []
148
157
                        if len(item) > colwidth - 1:
149
158
                            works, row_break = False, True
150
159
                            break
151
 
                    if row_break: break
152
 
                if works: break
 
160
                    if row_break:
 
161
                        break
 
162
                if works:
 
163
                    break
153
164
            rowwidths = row_widths(trytable)
154
165
            trytablecol = col_split(lscoloutput, len(trytable[0]))
155
166
            for r in range(len(trytable)):
176
187
    parser = OptionParser(usage="usage: %prog [options] command args\n\ncommand "+
177
188
            "is one of: info, books, df, ls, cp, mkdir, touch, cat, rm, eject, test_file\n\n"+
178
189
    "For help on a particular command: %prog command", version=__appname__+" version: " + __version__)
179
 
    parser.add_option("--log-packets", help="print out packet stream to stdout. "+\
 
190
    parser.add_option("--log-packets", help="print out packet stream to stdout. "+
180
191
                    "The numbers in the left column are byte offsets that allow the packet size to be read off easily.",
181
192
    dest="log_packets", action="store_true", default=False)
182
193
    parser.remove_option("-h")
183
 
    parser.disable_interspersed_args() # Allow unrecognized options
 
194
    parser.disable_interspersed_args()  # Allow unrecognized options
184
195
    options, args = parser.parse_args()
185
196
 
186
197
    if len(args) < 1:
227
238
            d.specialize_global_preferences(device_prefs)
228
239
            break
229
240
 
230
 
 
231
241
    try:
232
242
        if command == "df":
233
243
            total = dev.total_space(end_session=False)
235
245
            where = ("Memory", "Card A", "Card B")
236
246
            print "Filesystem\tSize \tUsed \tAvail \tUse%"
237
247
            for i in range(3):
238
 
                print "%-10s\t%s\t%s\t%s\t%s"%(where[i], human_readable(total[i]), human_readable(total[i]-free[i]), human_readable(free[i]),\
 
248
                print "%-10s\t%s\t%s\t%s\t%s"%(where[i], human_readable(total[i]), human_readable(total[i]-free[i]), human_readable(free[i]),
239
249
                                                                            str(0 if total[i]==0 else int(100*(total[i]-free[i])/(total[i]*1.)))+"%")
240
250
        elif command == 'eject':
241
251
            dev.eject()
244
254
            for book in dev.books():
245
255
                print book
246
256
            print "\nBooks on storage carda:"
247
 
            for book in dev.books(oncard='carda'): print book
 
257
            for book in dev.books(oncard='carda'):
 
258
                print book
248
259
            print "\nBooks on storage cardb:"
249
 
            for book in dev.books(oncard='cardb'): print book
 
260
            for book in dev.books(oncard='cardb'):
 
261
                print book
250
262
        elif command == "mkdir":
251
263
            parser = OptionParser(usage="usage: %prog mkdir [options] path\nCreate a directory on the device\n\npath must begin with / or card:/")
252
264
            if len(args) != 1:
255
267
            dev.mkdir(args[0])
256
268
        elif command == "ls":
257
269
            parser = OptionParser(usage="usage: %prog ls [options] path\nList files on the device\n\npath must begin with / or card:/")
258
 
            parser.add_option("-l", help="In addition to the name of each file, print the file type, permissions, and  timestamp  (the  modification time, in the local timezone). Times are local.", dest="ll", action="store_true", default=False)
259
 
            parser.add_option("-R", help="Recursively list subdirectories encountered. /dev and /proc are omitted", dest="recurse", action="store_true", default=False)
 
270
            parser.add_option(
 
271
                "-l", help="In addition to the name of each file, print the file type, permissions, and  timestamp  (the  modification time, in the local timezone). Times are local.",  # noqa
 
272
                              dest="ll", action="store_true", default=False)
 
273
            parser.add_option("-R", help="Recursively list subdirectories encountered. /dev and /proc are omitted",
 
274
                              dest="recurse", action="store_true", default=False)
260
275
            parser.remove_option("-h")
261
276
            parser.add_option("-h", "--human-readable", help="show sizes in human readable format", dest="hrs", action="store_true", default=False)
262
277
            options, args = parser.parse_args(args)
270
285
            usage="usage: %prog cp [options] source destination\nCopy files to/from the device\n\n"+\
271
286
            "One of source or destination must be a path on the device. \n\nDevice paths have the form\n"+\
272
287
            "dev:mountpoint/my/path\n"+\
273
 
            "where mountpoint is one of / or card:/\n\n"+\
 
288
            "where mountpoint is one of / or carda: or cardb:/\n\n"+\
274
289
            "source must point to a file for which you have read permissions\n"+\
275
290
            "destination must point to a file or directory for which you have write permissions"
276
291
            parser = OptionParser(usage=usage)
282
297
                return 1
283
298
            if args[0].startswith("dev:"):
284
299
                outfile = args[1]
285
 
                path = args[0][7:]
286
 
                if path.endswith("/"): path = path[:-1]
 
300
                path = args[0][4:]
 
301
                if path.endswith("/"):
 
302
                    path = path[:-1]
287
303
                if os.path.isdir(outfile):
288
304
                    outfile = os.path.join(outfile, path[path.rfind("/")+1:])
289
305
                try:
302
318
                    print >> sys.stderr, e
303
319
                    parser.print_help()
304
320
                    return 1
305
 
                try:
306
 
                    dev.put_file(infile, args[1][7:])
307
 
                except PathError as err:
308
 
                    if options.force and 'exists' in str(err):
309
 
                        dev.del_file(err.path, False)
310
 
                        dev.put_file(infile, args[1][7:])
311
 
                    else:
312
 
                        raise
 
321
                dev.put_file(infile, args[1][4:], replace_file=options.force)
313
322
                infile.close()
314
323
            else:
315
324
                parser.print_help()
316
325
                return 1
317
326
        elif command == "cat":
318
327
            outfile = sys.stdout
319
 
            parser = OptionParser(usage="usage: %prog cat path\nShow file on the device\n\npath should point to a file on the device and must begin with /,a:/ or b:/")
 
328
            parser = OptionParser(
 
329
                usage="usage: %prog cat path\nShow file on the device\n\npath should point to a file on the device and must begin with /,a:/ or b:/")
320
330
            options, args = parser.parse_args(args)
321
331
            if len(args) != 1:
322
332
                parser.print_help()
323
333
                return 1
324
 
            if args[0].endswith("/"): path = args[0][:-1]
325
 
            else: path = args[0]
 
334
            if args[0].endswith("/"):
 
335
                path = args[0][:-1]
 
336
            else:
 
337
                path = args[0]
326
338
            outfile = sys.stdout
327
339
            dev.get_file(path, outfile)
328
340
        elif command == "rm":
329
 
            parser = OptionParser(usage="usage: %prog rm path\nDelete files from the device\n\npath should point to a file or empty directory on the device "+\
330
 
                                  "and must begin with / or card:/\n\n"+\
 
341
            parser = OptionParser(usage="usage: %prog rm path\nDelete files from the device\n\npath should point to a file or empty directory on the device "+
 
342
                                  "and must begin with / or card:/\n\n"+
331
343
                                  "rm will DELETE the file. Be very CAREFUL")
332
344
            options, args = parser.parse_args(args)
333
345
            if len(args) != 1:
335
347
                return 1
336
348
            dev.rm(args[0])
337
349
        elif command == "touch":
338
 
            parser = OptionParser(usage="usage: %prog touch path\nCreate an empty file on the device\n\npath should point to a file on the device and must begin with /,a:/ or b:/\n\n"+
339
 
            "Unfortunately, I cant figure out how to update file times on the device, so if path already exists, touch does nothing" )
 
350
            parser = OptionParser(usage="usage: %prog touch path\nCreate an empty file on the device\n\npath should point to a file on the device and must begin with /,a:/ or b:/\n\n"+  # noqa
 
351
            "Unfortunately, I cant figure out how to update file times on the device, so if path already exists, touch does nothing")
340
352
            options, args = parser.parse_args(args)
341
353
            if len(args) != 1:
342
354
                parser.print_help()
358
370
            dev.eject()
359
371
        else:
360
372
            parser.print_help()
361
 
            if getattr(dev, 'handle', False): dev.close()
 
373
            if getattr(dev, 'handle', False):
 
374
                dev.close()
362
375
            return 1
363
376
    except DeviceLocked:
364
377
        print >> sys.stderr, "The device is locked. Use the --unlock option"