def do_list(fields, data, opts): from calibre.utils.terminal import geometry, ColoredStream separator = ' ' widths = list(map(lambda x: 0, fields)) for i in data: for j, field in enumerate(fields): widths[j] = max(widths[j], max(len(field), len(unicode_type(i[field])))) screen_width = geometry()[0] if not screen_width: screen_width = 80 field_width = screen_width // len(fields) base_widths = list(map(lambda x: min(x + 1, field_width), widths)) while sum(base_widths) < screen_width: adjusted = False for i in range(len(widths)): if base_widths[i] < widths[i]: base_widths[i] += min( screen_width - sum(base_widths), widths[i] - base_widths[i] ) adjusted = True break if not adjusted: break widths = list(base_widths) titles = map( lambda x, y: '%-*s%s' % (x - len(separator), y, separator), widths, fields ) with ColoredStream(sys.stdout, fg='green'): prints(''.join(titles)) wrappers = list(map(lambda x: TextWrapper(x - 1), widths)) for record in data: text = [ wrappers[i].wrap(unicode_type(record[field])) for i, field in enumerate(fields) ] lines = max(map(len, text)) for l in range(lines): for i, field in enumerate(text): ft = text[i][l] if l < len(text[i]) else '' filler = '%*s' % (widths[i] - len(ft) - 1, '') print(ft.encode('utf-8') + filler.encode('utf-8'), end=separator) print()
def do_list(fields, data, opts): from calibre.utils.terminal import geometry, ColoredStream separator = ' ' widths = list(map(lambda x: 0, fields)) for i in data: for j, field in enumerate(fields): widths[j] = max(widths[j], max(len(field), len(unicode_type(i[field])))) screen_width = geometry()[0] if not screen_width: screen_width = 80 field_width = screen_width // len(fields) base_widths = map(lambda x: min(x + 1, field_width), widths) while sum(base_widths) < screen_width: adjusted = False for i in range(len(widths)): if base_widths[i] < widths[i]: base_widths[i] += min( screen_width - sum(base_widths), widths[i] - base_widths[i] ) adjusted = True break if not adjusted: break widths = list(base_widths) titles = map( lambda x, y: '%-*s%s' % (x - len(separator), y, separator), widths, fields ) with ColoredStream(sys.stdout, fg='green'): prints(''.join(titles)) wrappers = map(lambda x: TextWrapper(x - 1), widths) for record in data: text = [ wrappers[i].wrap(unicode_type(record[field])) for i, field in enumerate(fields) ] lines = max(map(len, text)) for l in range(lines): for i, field in enumerate(text): ft = text[i][l] if l < len(text[i]) else '' filler = '%*s' % (widths[i] - len(ft) - 1, '') print(ft.encode('utf-8') + filler.encode('utf-8'), end=separator) print()
def main(): from calibre.utils.terminal import geometry cols = geometry()[0] parser = OptionParser( usage="usage: %prog [options] command args\n\ncommand " + "is one of: info, books, df, ls, cp, mkdir, touch, cat, rm, eject, test_file\n\n" + "For help on a particular command: %prog command", version=__appname__ + " version: " + __version__) parser.add_option( "--log-packets", help="print out packet stream to stdout. " + "The numbers in the left column are byte offsets that allow the packet size to be read off easily.", dest="log_packets", action="store_true", default=False) parser.remove_option("-h") parser.disable_interspersed_args() # Allow unrecognized options options, args = parser.parse_args() if len(args) < 1: parser.print_help() return 1 command = args[0] args = args[1:] dev = None scanner = DeviceScanner() scanner.scan() connected_devices = [] for d in device_plugins(): try: d.startup() except: print('Startup failed for device plugin: %s' % d) if d.MANAGES_DEVICE_PRESENCE: cd = d.detect_managed_devices(scanner.devices) if cd is not None: connected_devices.append((cd, d)) dev = d break continue ok, det = scanner.is_device_connected(d) if ok: dev = d dev.reset(log_packets=options.log_packets, detected_device=det) connected_devices.append((det, dev)) if dev is None: print('Unable to find a connected ebook reader.', file=sys.stderr) shutdown_plugins() return 1 for det, d in connected_devices: try: d.open(det, None) except: continue else: dev = d d.specialize_global_preferences(device_prefs) break try: if command == "df": total = dev.total_space(end_session=False) free = dev.free_space() where = ("Memory", "Card A", "Card B") print("Filesystem\tSize \tUsed \tAvail \tUse%") for i in range(3): 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]), unicode_type(0 if total[i] == 0 else int(100 * (total[i] - free[i]) / (total[i] * 1.))) + "%")) elif command == 'eject': dev.eject() elif command == "books": print("Books in main memory:") for book in dev.books(): print(book) print("\nBooks on storage carda:") for book in dev.books(oncard='carda'): print(book) print("\nBooks on storage cardb:") for book in dev.books(oncard='cardb'): print(book) elif command == "mkdir": parser = OptionParser( usage= "usage: %prog mkdir [options] path\nCreate a folder on the device\n\npath must begin with / or card:/" ) if len(args) != 1: parser.print_help() sys.exit(1) dev.mkdir(args[0]) elif command == "ls": parser = OptionParser( usage= "usage: %prog ls [options] path\nList files on the device\n\npath must begin with / or card:/" ) 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.", # noqa dest="ll", action="store_true", default=False) parser.add_option( "-R", help= "Recursively list subfolders encountered. /dev and /proc are omitted", dest="recurse", action="store_true", default=False) parser.remove_option("-h") parser.add_option("-h", "--human-readable", help="show sizes in human readable format", dest="hrs", action="store_true", default=False) options, args = parser.parse_args(args) if len(args) != 1: parser.print_help() return 1 print(ls(dev, args[0], recurse=options.recurse, ll=options.ll, human_readable_size=options.hrs, cols=cols), end=' ') elif command == "info": info(dev) elif command == "cp": usage="usage: %prog cp [options] source destination\nCopy files to/from the device\n\n"+\ "One of source or destination must be a path on the device. \n\nDevice paths have the form\n"+\ "dev:mountpoint/my/path\n"+\ "where mountpoint is one of / or carda: or cardb:/\n\n"+\ "source must point to a file for which you have read permissions\n"+\ "destination must point to a file or folder for which you have write permissions" parser = OptionParser(usage=usage) parser.add_option( '-f', '--force', dest='force', action='store_true', default=False, help='Overwrite the destination file if it exists already.') options, args = parser.parse_args(args) if len(args) != 2: parser.print_help() return 1 if args[0].startswith("dev:"): outfile = args[1] path = args[0][4:] if path.endswith("/"): path = path[:-1] if os.path.isdir(outfile): outfile = os.path.join(outfile, path[path.rfind("/") + 1:]) try: outfile = lopen(outfile, "wb") except IOError as e: print(e, file=sys.stderr) parser.print_help() return 1 dev.get_file(path, outfile) fsync(outfile) outfile.close() elif args[1].startswith("dev:"): try: infile = lopen(args[0], "rb") except IOError as e: print(e, file=sys.stderr) parser.print_help() return 1 dev.put_file(infile, args[1][4:], replace_file=options.force) infile.close() else: parser.print_help() return 1 elif command == "cat": outfile = sys.stdout 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:/" ) options, args = parser.parse_args(args) if len(args) != 1: parser.print_help() return 1 if args[0].endswith("/"): path = args[0][:-1] else: path = args[0] outfile = sys.stdout dev.get_file(path, outfile) elif command == "rm": parser = OptionParser( usage= "usage: %prog rm path\nDelete files from the device\n\npath should point to a file or empty folder on the device " + "and must begin with / or card:/\n\n" + "rm will DELETE the file. Be very CAREFUL") options, args = parser.parse_args(args) if len(args) != 1: parser.print_help() return 1 dev.rm(args[0]) elif command == "touch": 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 "Unfortunately, I cant figure out how to update file times on the device, so if path already exists, touch does nothing" ) options, args = parser.parse_args(args) if len(args) != 1: parser.print_help() return 1 dev.touch(args[0]) elif command == 'test_file': parser = OptionParser(usage=( "usage: %prog test_file path\n" 'Open device, copy file specified by path to device and ' 'then eject device.')) options, args = parser.parse_args(args) if len(args) != 1: parser.print_help() return 1 path = args[0] from calibre.ebooks.metadata.meta import get_metadata mi = get_metadata(lopen(path, 'rb'), path.rpartition('.')[-1].lower()) print( dev.upload_books([args[0]], [os.path.basename(args[0])], end_session=False, metadata=[mi])) dev.eject() else: parser.print_help() if getattr(dev, 'handle', False): dev.close() return 1 except DeviceLocked: print("The device is locked. Use the --unlock option", file=sys.stderr) except (ArgumentError, DeviceError) as e: print(e, file=sys.stderr) return 1 finally: shutdown_plugins() return 0
def do_list(dbctx, fields, afields, sort_by, ascending, search_text, line_width, separator, prefix, limit, for_machine=False): if sort_by is None: ascending = True ans = dbctx.run('list', fields, sort_by, ascending, search_text, limit) try: book_ids, data, metadata = ans['book_ids'], ans['data'], ans[ 'metadata'] except TypeError: raise SystemExit(ans) fields = list(ans['fields']) try: fields.remove('id') except ValueError: pass fields = ['id'] + fields stringify(data, metadata, for_machine) if for_machine: raw = json.dumps(list(as_machine_data(book_ids, data, metadata)), indent=2, sort_keys=True) if not isinstance(raw, bytes): raw = raw.encode('utf-8') getattr(sys.stdout, 'buffer', sys.stdout).write(raw) return from calibre.utils.terminal import ColoredStream, geometry output_table = prepare_output_table(fields, book_ids, data, metadata) widths = list(map(lambda x: 0, fields)) for record in output_table: for j in range(len(fields)): widths[j] = max(widths[j], str_width(record[j])) screen_width = geometry()[0] if line_width < 0 else line_width if not screen_width: screen_width = 80 field_width = screen_width // len(fields) base_widths = list(map(lambda x: min(x + 1, field_width), widths)) while sum(base_widths) < screen_width: adjusted = False for i in range(len(widths)): if base_widths[i] < widths[i]: base_widths[i] += min(screen_width - sum(base_widths), widths[i] - base_widths[i]) adjusted = True break if not adjusted: break widths = list(base_widths) titles = map(lambda x, y: '%-*s%s' % (x - len(separator), y, separator), widths, fields) with ColoredStream(sys.stdout, fg='green'): prints(''.join(titles)) wrappers = [ TextWrapper(x - 1).wrap if x > 1 else lambda y: y for x in widths ] for record in output_table: text = [wrappers[i](record[i]) for i, field in enumerate(fields)] lines = max(map(len, text)) for l in range(lines): for i, field in enumerate(text): ft = text[i][l] if l < len(text[i]) else u'' sys.stdout.write(ft.encode('utf-8')) if i < len(text) - 1: filler = (u'%*s' % (widths[i] - str_width(ft) - 1, u'')) sys.stdout.write((filler + separator).encode('utf-8')) print()
def do_list( dbctx, fields, afields, sort_by, ascending, search_text, line_width, separator, prefix, limit, for_machine=False ): if sort_by is None: ascending = True ans = dbctx.run('list', fields, sort_by, ascending, search_text, limit) try: book_ids, data, metadata = ans['book_ids'], ans['data'], ans['metadata'] except TypeError: raise SystemExit(ans) fields = list(ans['fields']) try: fields.remove('id') except ValueError: pass fields = ['id'] + fields stringify(data, metadata, for_machine) if for_machine: raw = json.dumps( list(as_machine_data(book_ids, data, metadata)), indent=2, sort_keys=True ) if not isinstance(raw, bytes): raw = raw.encode('utf-8') getattr(sys.stdout, 'buffer', sys.stdout).write(raw) return from calibre.utils.terminal import ColoredStream, geometry output_table = prepare_output_table(fields, book_ids, data, metadata) widths = list(map(lambda x: 0, fields)) for record in output_table: for j in range(len(fields)): widths[j] = max(widths[j], str_width(record[j])) screen_width = geometry()[0] if line_width < 0 else line_width if not screen_width: screen_width = 80 field_width = screen_width // len(fields) base_widths = map(lambda x: min(x + 1, field_width), widths) while sum(base_widths) < screen_width: adjusted = False for i in range(len(widths)): if base_widths[i] < widths[i]: base_widths[i] += min( screen_width - sum(base_widths), widths[i] - base_widths[i] ) adjusted = True break if not adjusted: break widths = list(base_widths) titles = map( lambda x, y: '%-*s%s' % (x - len(separator), y, separator), widths, fields ) with ColoredStream(sys.stdout, fg='green'): prints(''.join(titles)) wrappers = [TextWrapper(x - 1).wrap if x > 1 else lambda y: y for x in widths] for record in output_table: text = [ wrappers[i](record[i]) for i, field in enumerate(fields) ] lines = max(map(len, text)) for l in range(lines): for i, field in enumerate(text): ft = text[i][l] if l < len(text[i]) else u'' sys.stdout.write(ft.encode('utf-8')) if i < len(text) - 1: filler = (u'%*s' % (widths[i] - str_width(ft) - 1, u'')) sys.stdout.write((filler + separator).encode('utf-8')) print()
def main(): from calibre.utils.terminal import geometry cols = geometry()[0] parser = OptionParser(usage="usage: %prog [options] command args\n\ncommand "+ "is one of: info, books, df, ls, cp, mkdir, touch, cat, rm, eject, test_file\n\n"+ "For help on a particular command: %prog command", version=__appname__+" version: " + __version__) parser.add_option("--log-packets", help="print out packet stream to stdout. "+\ "The numbers in the left column are byte offsets that allow the packet size to be read off easily.", dest="log_packets", action="store_true", default=False) parser.remove_option("-h") parser.disable_interspersed_args() # Allow unrecognized options options, args = parser.parse_args() if len(args) < 1: parser.print_help() return 1 command = args[0] args = args[1:] dev = None scanner = DeviceScanner() scanner.scan() connected_devices = [] for d in device_plugins(): try: d.startup() except: print ('Startup failed for device plugin: %s'%d) if d.MANAGES_DEVICE_PRESENCE: cd = d.detect_managed_devices(scanner.devices) if cd is not None: connected_devices.append((cd, d)) dev = d break continue ok, det = scanner.is_device_connected(d) if ok: dev = d dev.reset(log_packets=options.log_packets, detected_device=det) connected_devices.append((det, dev)) if dev is None: print >>sys.stderr, 'Unable to find a connected ebook reader.' shutdown_plugins() return 1 for det, d in connected_devices: try: d.open(det, None) except: continue else: dev = d d.specialize_global_preferences(device_prefs) break try: if command == "df": total = dev.total_space(end_session=False) free = dev.free_space() where = ("Memory", "Card A", "Card B") print "Filesystem\tSize \tUsed \tAvail \tUse%" for i in range(3): 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]),\ str(0 if total[i]==0 else int(100*(total[i]-free[i])/(total[i]*1.)))+"%") elif command == 'eject': dev.eject() elif command == "books": print "Books in main memory:" for book in dev.books(): print book print "\nBooks on storage carda:" for book in dev.books(oncard='carda'): print book print "\nBooks on storage cardb:" for book in dev.books(oncard='cardb'): print book elif command == "mkdir": parser = OptionParser(usage="usage: %prog mkdir [options] path\nCreate a directory on the device\n\npath must begin with / or card:/") if len(args) != 1: parser.print_help() sys.exit(1) dev.mkdir(args[0]) elif command == "ls": parser = OptionParser(usage="usage: %prog ls [options] path\nList files on the device\n\npath must begin with / or card:/") 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) parser.add_option("-R", help="Recursively list subdirectories encountered. /dev and /proc are omitted", dest="recurse", action="store_true", default=False) parser.remove_option("-h") parser.add_option("-h", "--human-readable", help="show sizes in human readable format", dest="hrs", action="store_true", default=False) options, args = parser.parse_args(args) if len(args) != 1: parser.print_help() return 1 print ls(dev, args[0], recurse=options.recurse, ll=options.ll, human_readable_size=options.hrs, cols=cols), elif command == "info": info(dev) elif command == "cp": usage="usage: %prog cp [options] source destination\nCopy files to/from the device\n\n"+\ "One of source or destination must be a path on the device. \n\nDevice paths have the form\n"+\ "dev:mountpoint/my/path\n"+\ "where mountpoint is one of / or card:/\n\n"+\ "source must point to a file for which you have read permissions\n"+\ "destination must point to a file or directory for which you have write permissions" parser = OptionParser(usage=usage) parser.add_option('-f', '--force', dest='force', action='store_true', default=False, help='Overwrite the destination file if it exists already.') options, args = parser.parse_args(args) if len(args) != 2: parser.print_help() return 1 if args[0].startswith("dev:"): outfile = args[1] path = args[0][7:] if path.endswith("/"): path = path[:-1] if os.path.isdir(outfile): outfile = os.path.join(outfile, path[path.rfind("/")+1:]) try: outfile = open(outfile, "wb") except IOError as e: print >> sys.stderr, e parser.print_help() return 1 dev.get_file(path, outfile) outfile.close() elif args[1].startswith("dev:"): try: infile = open(args[0], "rb") except IOError as e: print >> sys.stderr, e parser.print_help() return 1 try: dev.put_file(infile, args[1][7:]) except PathError as err: if options.force and 'exists' in str(err): dev.del_file(err.path, False) dev.put_file(infile, args[1][7:]) else: raise infile.close() else: parser.print_help() return 1 elif command == "cat": outfile = sys.stdout 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:/") options, args = parser.parse_args(args) if len(args) != 1: parser.print_help() return 1 if args[0].endswith("/"): path = args[0][:-1] else: path = args[0] outfile = sys.stdout dev.get_file(path, outfile) elif command == "rm": 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 "+\ "and must begin with / or card:/\n\n"+\ "rm will DELETE the file. Be very CAREFUL") options, args = parser.parse_args(args) if len(args) != 1: parser.print_help() return 1 dev.rm(args[0]) elif command == "touch": 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"+ "Unfortunately, I cant figure out how to update file times on the device, so if path already exists, touch does nothing" ) options, args = parser.parse_args(args) if len(args) != 1: parser.print_help() return 1 dev.touch(args[0]) elif command == 'test_file': parser = OptionParser(usage=("usage: %prog test_file path\n" 'Open device, copy file specified by path to device and ' 'then eject device.')) options, args = parser.parse_args(args) if len(args) != 1: parser.print_help() return 1 path = args[0] from calibre.ebooks.metadata.meta import get_metadata mi = get_metadata(open(path, 'rb'), path.rpartition('.')[-1].lower()) print dev.upload_books([args[0]], [os.path.basename(args[0])], end_session=False, metadata=[mi]) dev.eject() else: parser.print_help() if getattr(dev, 'handle', False): dev.close() return 1 except DeviceLocked: print >> sys.stderr, "The device is locked. Use the --unlock option" except (ArgumentError, DeviceError) as e: print >>sys.stderr, e return 1 finally: shutdown_plugins() return 0