Sync to trunk.

This commit is contained in:
John Schember 2009-06-06 07:33:23 -04:00
commit 1e072040ba
9 changed files with 269 additions and 58 deletions

View File

@ -230,7 +230,7 @@ _check_symlinks_prescript()
all_functions = main_functions['console'] + main_functions['gui'] all_functions = main_functions['console'] + main_functions['gui']
print print
print 'Adding PoDoFo' print 'Adding PoDoFo'
pdf = glob.glob(os.path.expanduser('/Volumes/sw/podofo/*.dylib'))[0] pdf = glob.glob(os.path.expanduser('/Volumes/sw/podofo/libpodofo.0.7.00.dylib'))[0]
shutil.copyfile(pdf, os.path.join(frameworks_dir, os.path.basename(pdf))) shutil.copyfile(pdf, os.path.join(frameworks_dir, os.path.basename(pdf)))
@ -264,6 +264,14 @@ _check_symlinks_prescript()
if os.path.exists(dst): if os.path.exists(dst):
shutil.rmtree(dst) shutil.rmtree(dst)
shutil.copytree('/usr/local/etc/fonts', dst, symlinks=False) shutil.copytree('/usr/local/etc/fonts', dst, symlinks=False)
for x in os.listdir('/usr/local/etc/fonts'):
dst = os.path.join(frameworks_dir, x)
y = os.path.join('/usr/local/etc/fonts', x)
if os.path.isdir(dst):
if os.path.exists(dst): shutil.rmtree(dst)
shutil.copytree(y, dst)
else:
os.link(y, dst)
print print
print 'Adding IPython' print 'Adding IPython'

View File

@ -62,9 +62,9 @@ if __name__ == '__main__':
podofo_inc = '/usr/include/podofo' if islinux else \ podofo_inc = '/usr/include/podofo' if islinux else \
'C:\\podofo\\include\\podofo' if iswindows else \ 'C:\\podofo\\include\\podofo' if iswindows else \
'/Volumes/sw/podofo/include/podofo' '/usr/local/include/podofo'
podofo_lib = '/usr/lib' if islinux else r'C:\podofo' if iswindows else \ podofo_lib = '/usr/lib' if islinux else r'C:\podofo' if iswindows else \
'/Volumes/sw/podofo/lib' '/usr/local/lib'
podofo_inc = os.environ.get('PODOFO_INC_DIR', podofo_inc) podofo_inc = os.environ.get('PODOFO_INC_DIR', podofo_inc)
if os.path.exists(os.path.join(podofo_inc, 'podofo.h')): if os.path.exists(os.path.join(podofo_inc, 'podofo.h')):
optional.append(Extension('calibre.plugins.podofo', optional.append(Extension('calibre.plugins.podofo',

View File

@ -403,7 +403,8 @@ def fix_ids(main, carda, cardb):
for child in db.root_element.childNodes: for child in db.root_element.childNodes:
if child.nodeType == child.ELEMENT_NODE and child.hasAttribute('id'): if child.nodeType == child.ELEMENT_NODE and child.hasAttribute('id'):
id_map[child.getAttribute('id')] = str(cid) id_map[child.getAttribute('id')] = str(cid)
child.setAttribute("sourceid", '1') child.setAttribute("sourceid",
'0' if getattr(child, 'tagName', '').endswith('playlist') else '1')
child.setAttribute('id', str(cid)) child.setAttribute('id', str(cid))
cid += 1 cid += 1

View File

@ -7,14 +7,7 @@ intended to be subclassed with the relevant parts implemented for a particular
device. This class handles device detection. device. This class handles device detection.
''' '''
import glob import os, subprocess, time, re, sys, glob
import os
import re
import struct
import subprocess
import sys
import time
from itertools import repeat from itertools import repeat
from calibre.devices.interface import DevicePlugin from calibre.devices.interface import DevicePlugin
@ -499,29 +492,26 @@ class Device(DeviceConfig, DevicePlugin):
self.open_osx() self.open_osx()
def eject_windows(self): def eject_windows(self):
win32file = __import__('win32file', globals(), locals(), [], -1) from calibre.constants import plugins
win32con = __import__('win32con', globals(), locals(), [], -1) from threading import Thread
win32shell = __import__('win32com.shell.shell', globals(), locals(), [], -1) winutil, winutil_err = plugins['winutil']
win32shellcon = __import__('win32com.shell.shellcon', globals(), locals(), [], -1) drives = []
FSCTL_LOCK_VOLUME = 0x0090018
FSCTL_DISMOUNT_VOLUME = 0x00090020
IOCTL_STORAGE_MEDIA_REMOVAL = 0x002D4804
IOCTL_STORAGE_EJECT_MEDIA = 0x002D4808
for x in ('_main_prefix', '_card_a_prefix', '_card_b_prefix'): for x in ('_main_prefix', '_card_a_prefix', '_card_b_prefix'):
x = getattr(self, x, None) x = getattr(self, x, None)
if x is not None: if x is not None:
vol = win32file.CreateFile(x, win32con.GENERIC_READ | win32con.GENERIC_WRITE, win32con.FILE_SHARE_READ | win32con.FILE_SHARE_WRITE, None, win32con.OPEN_EXISTING, 0, None) drives.append(x[0].upper())
def do_it(drives):
for d in drives:
try: try:
win32file.DeviceIoControl(vol, FSCTL_LOCK_VOLUME, '', 0, None) winutil.eject_drive(d)
win32file.DeviceIoControl(vol, FSCTL_DISMOUNT_VOLUME, '', 0, None) except:
win32file.DeviceIoControl(vol, IOCTL_STORAGE_MEDIA_REMOVAL, struct.pack('B', 0), 0, None) pass
win32file.DeviceIoControl(vol, IOCTL_STORAGE_EJECT_MEDIA, '', 0, None)
time.sleep(2) t = Thread(target=do_it, args=[drives])
win32shell.SHChangeNotify(win32shellcon.SHCNE_DRIVEREMOVED, win32shellcon.SHCNF_PATH, x) t.daemon = True
finally: t.start()
win32file.CloseHandle(vol) self.__save_win_eject_thread = t
def eject_osx(self): def eject_osx(self):
for x in ('_main_prefix', '_card_a_prefix', '_card_b_prefix'): for x in ('_main_prefix', '_card_a_prefix', '_card_b_prefix'):

View File

@ -63,9 +63,12 @@ def roman(num):
def fmt_sidx(i, fmt='%.2f', use_roman=False): def fmt_sidx(i, fmt='%.2f', use_roman=False):
if i is None: if i is None:
i = 1 i = 1
if int(i) == i: if int(i) == float(i):
return roman(i) if use_roman else '%d'%i return roman(int(i)) if use_roman else '%d'%int(i)
try:
return fmt%i return fmt%i
except TypeError:
return fmt%float(i)
class Resource(object): class Resource(object):

View File

@ -77,6 +77,7 @@ class Query(object):
if verbose: if verbose:
print 'Query:', self.url print 'Query:', self.url
feed = etree.fromstring(browser.open(self.url).read()) feed = etree.fromstring(browser.open(self.url).read())
#print etree.tostring(feed, pretty_print=True)
total = int(total_results(feed)[0].text) total = int(total_results(feed)[0].text)
start = int(start_index(feed)[0].text) start = int(start_index(feed)[0].text)
entries = entry(feed) entries = entry(feed)
@ -104,12 +105,9 @@ class ResultList(list):
except: except:
report(verbose) report(verbose)
def get_title(self, entry): def get_title(self, entry):
candidates = [x.text for x in title(entry)] candidates = [x.text for x in title(entry)]
candidates.sort(cmp=lambda x,y: cmp(len(x), len(y)), reverse=True) return ': '.join(candidates)
return candidates[0]
def get_authors(self, entry): def get_authors(self, entry):
m = creator(entry) m = creator(entry)
@ -182,7 +180,7 @@ class ResultList(list):
self.get_identifiers(x, mi) self.get_identifiers(x, mi)
mi.tags = self.get_tags(x, verbose) mi.tags = self.get_tags(x, verbose)
mi.publisher = self.get_publisher(x, verbose) mi.publisher = self.get_publisher(x, verbose)
mi.timestamp = self.get_date(x, verbose) mi.pubdate = self.get_date(x, verbose)
mi.language = self.get_language(x, verbose) mi.language = self.get_language(x, verbose)
self.append(mi) self.append(mi)

View File

@ -7,14 +7,18 @@ __docformat__ = 'restructuredtext en'
HTTP server for remote access to the calibre database. HTTP server for remote access to the calibre database.
''' '''
import sys, textwrap, operator, os, re, logging import sys, textwrap, operator, os, re, logging, cStringIO
from itertools import repeat from itertools import repeat
from logging.handlers import RotatingFileHandler from logging.handlers import RotatingFileHandler
from datetime import datetime from datetime import datetime
from threading import Thread from threading import Thread
import cherrypy import cherrypy
from PyQt4.Qt import QImage, QApplication, QByteArray, Qt, QBuffer try:
from PIL import Image as PILImage
PILImage
except ImportError:
import Image as PILImage
from calibre.constants import __version__, __appname__ from calibre.constants import __version__, __appname__
from calibre.utils.genshi.template import MarkupTemplate from calibre.utils.genshi.template import MarkupTemplate
@ -195,25 +199,21 @@ class LibraryServer(object):
updated = datetime.utcfromtimestamp(os.stat(path).st_mtime) if path and os.access(path, os.R_OK) else build_time updated = datetime.utcfromtimestamp(os.stat(path).st_mtime) if path and os.access(path, os.R_OK) else build_time
cherrypy.response.headers['Last-Modified'] = self.last_modified(updated) cherrypy.response.headers['Last-Modified'] = self.last_modified(updated)
try: try:
if QApplication.instance() is None: f = cStringIO.StringIO(cover)
QApplication([]) try:
im = PILImage.open(f)
im = QImage() except IOError:
im.loadFromData(cover)
if im.isNull():
raise cherrypy.HTTPError(404, 'No valid cover found') raise cherrypy.HTTPError(404, 'No valid cover found')
width, height = im.width(), im.height() width, height = im.size
scaled, width, height = fit_image(width, height, scaled, width, height = fit_image(width, height,
60 if thumbnail else self.max_cover_width, 60 if thumbnail else self.max_cover_width,
80 if thumbnail else self.max_cover_height) 80 if thumbnail else self.max_cover_height)
if not scaled: if not scaled:
return cover return cover
im = im.scaled(width, height, Qt.KeepAspectRatio, Qt.SmoothTransformation) im = im.resize((int(width), int(height)), PILImage.ANTIALIAS)
ba = QByteArray() of = cStringIO.StringIO()
buf = QBuffer(ba) im.convert('RGB').save(of, 'JPEG')
buf.open(QBuffer.WriteOnly) return of.getvalue()
im.save(buf, 'PNG')
return str(ba.data())
except Exception, err: except Exception, err:
import traceback import traceback
traceback.print_exc() traceback.print_exc()
@ -294,7 +294,7 @@ class LibraryServer(object):
series = record[FIELD_MAP['series']] series = record[FIELD_MAP['series']]
if series: if series:
extra.append('SERIES: %s [%s]<br />'%(series, extra.append('SERIES: %s [%s]<br />'%(series,
fmt_sidx(record[FIELD_MAP['series_index']]))) fmt_sidx(float(record[FIELD_MAP['series_index']]))))
fmt = 'epub' if 'EPUB' in r else 'pdb' fmt = 'epub' if 'EPUB' in r else 'pdb'
mimetype = guess_type('dummy.'+fmt)[0] mimetype = guess_type('dummy.'+fmt)[0]
books.append(self.STANZA_ENTRY.generate( books.append(self.STANZA_ENTRY.generate(
@ -343,7 +343,7 @@ class LibraryServer(object):
for record in items[start:start+num]: for record in items[start:start+num]:
aus = record[2] if record[2] else __builtins__._('Unknown') aus = record[2] if record[2] else __builtins__._('Unknown')
authors = '|'.join([i.replace('|', ',') for i in aus.split(',')]) authors = '|'.join([i.replace('|', ',') for i in aus.split(',')])
r[10] = fmt_sidx(r[10]) record[10] = fmt_sidx(float(record[10]))
books.append(book.generate(r=record, authors=authors).render('xml').decode('utf-8')) books.append(book.generate(r=record, authors=authors).render('xml').decode('utf-8'))
updated = self.db.last_modified() updated = self.db.last_modified()

View File

@ -306,6 +306,213 @@ get_all_removable_disks(struct tagDrives *g_drives)
} }
static DEVINST
GetDrivesDevInstByDeviceNumber(long DeviceNumber,
UINT DriveType, char* szDosDeviceName)
{
GUID *guid;
HDEVINFO hDevInfo;
DWORD dwIndex, dwBytesReturned;
BOOL bRet, IsFloppy;
BYTE Buf[1024];
PSP_DEVICE_INTERFACE_DETAIL_DATA pspdidd;
long res;
HANDLE hDrive;
STORAGE_DEVICE_NUMBER sdn;
IsFloppy = (strstr(szDosDeviceName, "\\Floppy") != NULL); // is there a better way?
switch (DriveType) {
case DRIVE_REMOVABLE:
if ( IsFloppy ) {
guid = (GUID*)&GUID_DEVINTERFACE_FLOPPY;
} else {
guid = (GUID*)&GUID_DEVINTERFACE_DISK;
}
break;
case DRIVE_FIXED:
guid = (GUID*)&GUID_DEVINTERFACE_DISK;
break;
case DRIVE_CDROM:
guid = (GUID*)&GUID_DEVINTERFACE_CDROM;
break;
default:
PyErr_SetString(PyExc_ValueError, "Invalid drive type");
return 0;
}
// Get device interface info set handle
// for all devices attached to system
hDevInfo = SetupDiGetClassDevs(guid, NULL, NULL,
DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
if (hDevInfo == INVALID_HANDLE_VALUE) {
PyErr_SetString(PyExc_ValueError, "Invalid handle value");
return 0;
}
// Retrieve a context structure for a device interface
// of a device information set.
dwIndex = 0;
bRet = FALSE;
pspdidd =
(PSP_DEVICE_INTERFACE_DETAIL_DATA)Buf;
SP_DEVICE_INTERFACE_DATA spdid;
SP_DEVINFO_DATA spdd;
DWORD dwSize;
spdid.cbSize = sizeof(spdid);
while ( TRUE ) {
bRet = SetupDiEnumDeviceInterfaces(hDevInfo, NULL,
guid, dwIndex, &spdid);
if ( !bRet ) {
break;
}
dwSize = 0;
SetupDiGetDeviceInterfaceDetail(hDevInfo,
&spdid, NULL, 0, &dwSize, NULL);
if ( dwSize!=0 && dwSize<=sizeof(Buf) ) {
pspdidd->cbSize = sizeof(*pspdidd); // 5 Bytes!
ZeroMemory((PVOID)&spdd, sizeof(spdd));
spdd.cbSize = sizeof(spdd);
res =
SetupDiGetDeviceInterfaceDetail(hDevInfo, &
spdid, pspdidd,
dwSize, &dwSize,
&spdd);
if ( res ) {
hDrive = CreateFile(pspdidd->DevicePath,0,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL, OPEN_EXISTING, 0, NULL);
if ( hDrive != INVALID_HANDLE_VALUE ) {
dwBytesReturned = 0;
res = DeviceIoControl(hDrive,
IOCTL_STORAGE_GET_DEVICE_NUMBER,
NULL, 0, &sdn, sizeof(sdn),
&dwBytesReturned, NULL);
if ( res ) {
if ( DeviceNumber == (long)sdn.DeviceNumber ) {
CloseHandle(hDrive);
SetupDiDestroyDeviceInfoList(hDevInfo);
return spdd.DevInst;
}
}
CloseHandle(hDrive);
}
}
}
dwIndex++;
}
SetupDiDestroyDeviceInfoList(hDevInfo);
PyErr_SetString(PyExc_ValueError, "Invalid device number");
return 0;
}
static BOOL
eject_drive_letter(char DriveLetter) {
char szRootPath[4], szDevicePath[3], szVolumeAccessPath[7], szDosDeviceName[MAX_PATH];
long DeviceNumber, res, tries;
HANDLE hVolume;
STORAGE_DEVICE_NUMBER sdn;
DWORD dwBytesReturned;
DEVINST DevInst;
ULONG Status;
ULONG ProblemNumber;
PNP_VETO_TYPE VetoType;
WCHAR VetoNameW[MAX_PATH];
BOOL bSuccess;
DEVINST DevInstParent;
szRootPath[0] = DriveLetter; szRootPath[1] = ':'; szRootPath[2] = '\\'; szRootPath[3] = (char)0;
szDevicePath[0] = DriveLetter; szDevicePath[1] = ':'; szDevicePath[2] = (char)0;
szVolumeAccessPath[0] = '\\'; szVolumeAccessPath[1] = '\\'; szVolumeAccessPath[2] = '.';
szVolumeAccessPath[3] = '\\'; szVolumeAccessPath[4] = DriveLetter; szVolumeAccessPath[5] = ':';
szVolumeAccessPath[6] = (char)0;
DeviceNumber = -1;
hVolume = CreateFile(szVolumeAccessPath, 0,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL, OPEN_EXISTING, 0, NULL);
if (hVolume == INVALID_HANDLE_VALUE) {
PyErr_SetString(PyExc_ValueError, "Invalid handle value for drive letter");
return FALSE;
}
dwBytesReturned = 0;
res = DeviceIoControl(hVolume,
IOCTL_STORAGE_GET_DEVICE_NUMBER,
NULL, 0, &sdn, sizeof(sdn),
&dwBytesReturned, NULL);
if ( res ) {
DeviceNumber = sdn.DeviceNumber;
}
CloseHandle(hVolume);
if ( DeviceNumber == -1 ) {
PyErr_SetString(PyExc_ValueError, "Can't find drive number");
return FALSE;
}
res = QueryDosDevice(szDevicePath, szDosDeviceName, MAX_PATH);
if ( !res ) {
PyErr_SetString(PyExc_ValueError, "Can't find dos device");
return FALSE;
}
DevInst = GetDrivesDevInstByDeviceNumber(DeviceNumber,
DriveType, szDosDeviceName);
if (DevInst == 0) return FALSE;
DevInstParent = 0;
Status = 0;
ProblemNumber = 0;
PNP_VETO_TYPE VetoType;
bSuccess = FALSE;
res = CM_Get_Parent(&DevInstParent, DevInst, 0);
for ( tries = 0; tries < 3; tries++ ) {
VetoNameW[0] = 0;
res = CM_Request_Device_EjectW(DevInstParent,
&VetoType, VetoNameW, MAX_PATH, 0);
bSuccess = (res==CR_SUCCESS &&
VetoType==PNP_VetoTypeUnknown);
if ( bSuccess ) {
break;
}
Sleep(500); // required to give the next tries a chance!
}
if (!bSuccess) PyErr_SetString(PyExc_ValueError, "Failed to eject drive after three tries");
return bSuccess;
}
static PyObject *
winutil_eject_drive(PyObject *self, PyObject *args) {
char DriveLetter;
if (!PyArg_ParseTuple(args, "c", &DriveLetter)) return NULL;
if (!eject_drive_letter(DriveLetter)) return NULL;
Py_RETURN_NONE;
}
PSP_DEVICE_INTERFACE_DETAIL_DATA PSP_DEVICE_INTERFACE_DETAIL_DATA
get_device_grandparent(HDEVINFO hDevInfo, DWORD index, PWSTR buf, PWSTR volume_id, get_device_grandparent(HDEVINFO hDevInfo, DWORD index, PWSTR buf, PWSTR volume_id,
BOOL *iterate) { BOOL *iterate) {
@ -697,6 +904,10 @@ is not present, current time as returned by localtime() is used. format must\n\
be a unicode string. Returns unicode strings." be a unicode string. Returns unicode strings."
}, },
{"eject_drive", winutil_eject_drive, METH_VARARGS,
"eject_drive(drive_letter)\n\nEject a drive. Raises an exception on failure."
},
{NULL, NULL, 0, NULL} {NULL, NULL, 0, NULL}
}; };

View File

@ -548,7 +548,7 @@ class build_windows(VMInstaller):
class build_osx(VMInstaller): class build_osx(VMInstaller):
description = 'Build OS X app bundle' description = 'Build OS X app bundle'
VM = '/vmware/Mac OSX/Mac OSX.vmx' VM = '/mnt/backup/calibre_os_x/Mac OSX.vmx'
if not os.path.exists(VM): if not os.path.exists(VM):
VM = '/home/kovid/calibre_os_x/Mac OSX.vmx' VM = '/home/kovid/calibre_os_x/Mac OSX.vmx'