Module prs500
[hide private]
[frames] | no frames]

Source Code for Module prs500

  1  #!/usr/bin/env python 
  2  """ 
  3  Provides a command-line interface to the SONY Reader PRS-500. 
  4   
  5  For usage information run the script.  
  6  """ 
  7   
  8  import StringIO, sys, time, os 
  9  from optparse import OptionParser 
 10   
 11  from libprs500 import VERSION 
 12  from libprs500.communicate import PRS500Device 
 13  from libprs500.terminfo import TerminalController 
 14  from libprs500.errors import ArgumentError 
 15   
 16   
 17  MINIMUM_COL_WIDTH = 12 #: Minimum width of columns in ls output 
 18   
19 -def human_readable(size):
20 """ Convert a size in bytes into a human readle form """ 21 if size < 1024: divisor, suffix = 1, "" 22 elif size < 1024*1024: divisor, suffix = 1024., "K" 23 elif size < 1024*1024*1024: divisor, suffix = 1024*1024, "M" 24 elif size < 1024*1024*1024*1024: divisor, suffix = 1024*1024, "G" 25 size = str(size/divisor) 26 if size.find(".") > -1: size = size[:size.find(".")+2] 27 return size + suffix
28
29 -class FileFormatter(object):
30 - def __init__(self, file, term):
31 self.term = term 32 self.is_dir = file.is_dir 33 self.is_readonly = file.is_readonly 34 self.size = file.size 35 self.ctime = file.ctime 36 self.wtime = file.wtime 37 self.name = file.name 38 self.path = file.path
39 40 @apply
41 - def mode_string():
42 doc=""" The mode string for this file. There are only two modes read-only and read-write """ 43 def fget(self): 44 mode, x = "-", "-" 45 if self.is_dir: mode, x = "d", "x" 46 if self.is_readonly: mode += "r-"+x+"r-"+x+"r-"+x 47 else: mode += "rw"+x+"rw"+x+"rw"+x 48 return mode
49 return property(**locals()) 50 51 @apply
52 - def name_in_color():
53 doc=""" The name in ANSI text. Directories are blue, ebooks are green """ 54 def fget(self): 55 cname = self.name 56 blue, green, normal = "", "", "" 57 if self.term: blue, green, normal = self.term.BLUE, self.term.GREEN, self.term.NORMAL 58 if self.is_dir: cname = blue + self.name + normal 59 else: 60 ext = self.name[self.name.rfind("."):] 61 if ext in (".pdf", ".rtf", ".lrf", ".lrx", ".txt"): cname = green + self.name + normal 62 return cname
63 return property(**locals()) 64 65 @apply
66 - def human_readable_size():
67 doc=""" File size in human readable form """ 68 def fget(self): 69 human_readable(self.size)
70 return property(**locals()) 71 72 @apply
73 - def modification_time():
74 doc=""" Last modified time in the Linux ls -l format """ 75 def fget(self): 76 return time.strftime("%Y-%m-%d %H:%M", time.localtime(self.wtime))
77 return property(**locals()) 78 79 @apply
80 - def creation_time():
81 doc=""" Last modified time in the Linux ls -l format """ 82 def fget(self): 83 return time.strftime("%Y-%m-%d %H:%M", time.localtime(self.ctime))
84 return property(**locals()) 85
86 -def info(dev):
87 info = dev.get_device_information() 88 print "Device name: ", info[0] 89 print "Device version: ", info[1] 90 print "Software version:", info[2] 91 print "Mime type: ", info[3]
92
93 -def ls(dev, path, term, recurse=False, color=False, human_readable_size=False, ll=False, cols=0):
94 def col_split(l, cols): # split list l into columns 95 rows = len(l) / cols 96 if len(l) % cols: 97 rows += 1 98 m = [] 99 for i in range(rows): 100 m.append(l[i::rows]) 101 return m
102 103 def row_widths(table): # Calculate widths for each column in the row-wise table 104 tcols = len(table[0]) 105 rowwidths = [ 0 for i in range(tcols) ] 106 for row in table: 107 c = 0 108 for item in row: 109 rowwidths[c] = len(item) if len(item) > rowwidths[c] else rowwidths[c] 110 c += 1 111 return rowwidths 112 113 output = StringIO.StringIO() 114 if path.endswith("/"): path = path[:-1] 115 dirs = dev.list(path, recurse) 116 for dir in dirs: 117 if recurse: print >>output, dir[0] + ":" 118 lsoutput, lscoloutput = [], [] 119 files = dir[1] 120 maxlen = 0 121 if ll: # Calculate column width for size column 122 for file in files: 123 size = len(str(file.size)) 124 if human_readable_size: 125 file = FileFormatter(file, term) 126 size = len(file.human_readable_size) 127 if size > maxlen: maxlen = size 128 for file in files: 129 file = FileFormatter(file, term) 130 name = file.name 131 lsoutput.append(name) 132 if color: name = file.name_in_color 133 lscoloutput.append(name) 134 if ll: 135 size = str(file.size) 136 if human_readable_size: size = file.human_readable_size 137 print >>output, file.mode_string, ("%"+str(maxlen)+"s")%size, file.modification_time, name 138 if not ll and len(lsoutput) > 0: 139 trytable = [] 140 for colwidth in range(MINIMUM_COL_WIDTH, cols): 141 trycols = int(cols/colwidth) 142 trytable = col_split(lsoutput, trycols) 143 works = True 144 for row in trytable: 145 row_break = False 146 for item in row: 147 if len(item) > colwidth - 1: 148 works, row_break = False, True 149 break 150 if row_break: break 151 if works: break 152 rowwidths = row_widths(trytable) 153 trytablecol = col_split(lscoloutput, len(trytable[0])) 154 for r in range(len(trytable)): 155 for c in range(len(trytable[r])): 156 padding = rowwidths[c] - len(trytable[r][c]) 157 print >>output, trytablecol[r][c], "".ljust(padding), 158 print >>output 159 print >>output 160 listing = output.getvalue().rstrip()+ "\n" 161 output.close() 162 return listing 163
164 -def main():
165 term = TerminalController() 166 cols = term.COLS 167 168 parser = OptionParser(usage="usage: %prog [options] command args\n\ncommand is one of: info, df, ls, cp, mkdir, touch, cat or rm\n\n"+ 169 "For help on a particular command: %prog command", version="libprs500 version: " + VERSION) 170 parser.add_option("--log-packets", help="print out packet stream to stdout. "+\ 171 "The numbers in the left column are byte offsets that allow the packet size to be read off easily.", 172 dest="log_packets", action="store_true", default=False) 173 parser.remove_option("-h") 174 parser.disable_interspersed_args() # Allow unrecognized options 175 options, args = parser.parse_args() 176 177 if len(args) < 1: 178 parser.print_help() 179 sys.exit(1) 180 command = args[0] 181 args = args[1:] 182 dev = PRS500Device(log_packets=options.log_packets) 183 dev.open() 184 try: 185 if command == "df": 186 data = dev.available_space() 187 print "Filesystem\tSize \tUsed \tAvail \tUse%" 188 for datum in data: 189 total, free, used, percent = human_readable(datum[2]), human_readable(datum[1]), human_readable(datum[2]-datum[1]), \ 190 str(0 if datum[2]==0 else int(100*(datum[2]-datum[1])/(datum[2]*1.)))+"%" 191 print "%-10s\t%s\t%s\t%s\t%s"%(datum[0], total, used, free, percent) 192 elif command == "mkdir": 193 parser = OptionParser(usage="usage: %prog mkdir [options] path\n\npath must begin with /,a:/ or b:/") 194 if len(args) != 1: 195 parser.print_help() 196 sys.exit(1) 197 dev.mkdir(args[0]) 198 elif command == "ls": 199 parser = OptionParser(usage="usage: %prog ls [options] path\n\npath must begin with /,a:/ or b:/") 200 parser.add_option("--color", help="show ls output in color", dest="color", action="store_true", default=False) 201 parser.add_option("-l", help="In addition to the name of each file, print the file type, permissions, and timestamp (the modification time unless other times are selected). Times are local.", dest="ll", action="store_true", default=False) 202 parser.add_option("-R", help="Recursively list subdirectories encountered. /dev and /proc are omitted", dest="recurse", action="store_true", default=False) 203 parser.remove_option("-h") 204 parser.add_option("-h", "--human-readable", help="show sizes in human readable format", dest="hrs", action="store_true", default=False) 205 options, args = parser.parse_args(args) 206 if len(args) != 1: 207 parser.print_help() 208 sys.exit(1) 209 dev.open() 210 print ls(dev, args[0], term, color=options.color, recurse=options.recurse, ll=options.ll, human_readable_size=options.hrs, cols=cols), 211 elif command == "info": 212 info(dev) 213 elif command == "cp": 214 usage="usage: %prog cp [options] source destination\n\n"+\ 215 "One of source or destination must be a path on the device. Device paths have the form:\n"+\ 216 "device:mountpoint/my/path\n"+\ 217 "where mountpoint is one of /, a: or b:\n"+\ 218 "source must point to a file for which you have read permissions\n"+\ 219 "destination must point to a file or directory for which you have write permissions" 220 parser = OptionParser(usage=usage) 221 options, args = parser.parse_args(args) 222 if len(args) != 2: 223 parser.print_help() 224 sys.exit(1) 225 if args[0].startswith("device:"): 226 outfile = args[1] 227 path = args[0][7:] 228 if path.endswith("/"): path = path[:-1] 229 if os.path.isdir(outfile): 230 outfile = os.path.join(outfile, path[path.rfind("/")+1:]) 231 try: 232 outfile = open(outfile, "w") 233 except IOError, e: 234 print >> sys.stderr, e 235 parser.print_help() 236 sys.exit(1) 237 dev.get_file(path, outfile) 238 outfile.close() 239 elif args[1].startswith("device:"): 240 try: 241 infile = open(args[0], "r") 242 except IOError, e: 243 print >> sys.stderr, e 244 parser.print_help() 245 sys.exit(1) 246 dev.put_file(infile, args[1][7:]) 247 infile.close() 248 else: 249 parser.print_help() 250 sys.exit(1) 251 elif command == "cat": 252 outfile = sys.stdout 253 parser = OptionParser(usage="usage: %prog cat path\n\npath should point to a file on the device and must begin with /,a:/ or b:/") 254 options, args = parser.parse_args(args) 255 if len(args) != 1: 256 parser.print_help() 257 sys.exit(1) 258 if args[0].endswith("/"): path = args[0][:-1] 259 else: path = args[0] 260 outfile = sys.stdout 261 dev.get_file(path, outfile) 262 elif command == "rm": 263 parser = OptionParser(usage="usage: %prog rm path\n\npath should point to a file or empty directory on the device "+\ 264 "and must begin with /,a:/ or b:/\n\n"+\ 265 "rm will DELETE the file. Be very CAREFUL") 266 options, args = parser.parse_args(args) 267 if len(args) != 1: 268 parser.print_help() 269 sys.exit(1) 270 dev.rm(args[0]) 271 elif command == "touch": 272 parser = OptionParser(usage="usage: %prog touch path\n\npath should point to a file on the device and must begin with /,a:/ or b:/\n\n"+ 273 "Unfortunately, I cant figure out how to update file times on the device, so if path already exists, touch does nothing" ) 274 options, args = parser.parse_args(args) 275 if len(args) != 1: 276 parser.print_help() 277 sys.exit(1) 278 dev.touch(args[0]) 279 else: 280 parser.print_help() 281 if dev.handle: dev.close() 282 sys.exit(1) 283 except ArgumentError, e: 284 print >>sys.stderr, e 285 sys.exit(1) 286 finally: 287 if dev.handle: dev.close()
288 289 if __name__ == "__main__": 290 main() 291