From e236efdad508214b7502b218ea223103bf7284b9 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Mon, 4 Aug 2008 12:59:12 -0700 Subject: [PATCH] IGN:... --- installer/linux/freeze.py | 2 +- installer/windows/calibre/calibre.mpi | 139 +++++++++++++- setup.py | 226 +++++++++++++---------- src/calibre/debug.py | 17 +- src/calibre/devices/prs500/cli/main.py | 2 +- src/calibre/linux.py | 80 ++++---- src/calibre/manual/faq.rst | 2 +- src/calibre/manual/resources/logo.png | Bin 31560 -> 9261 bytes src/calibre/parallel.py | 246 +++++++++++++------------ upload.py | 43 ++--- 10 files changed, 466 insertions(+), 291 deletions(-) diff --git a/installer/linux/freeze.py b/installer/linux/freeze.py index 0203e7d0ae..f33b059903 100644 --- a/installer/linux/freeze.py +++ b/installer/linux/freeze.py @@ -21,7 +21,7 @@ DBUS = '/usr/lib/libdbus-1.so.3' LIBMNG = '/usr/lib/libmng.so.1' LIBZ = '/lib/libz.so.1' LIBBZ2 = '/lib/libbz2.so.1' -LIBUSB = '/lib/libusb.so' +LIBUSB = '/usr/lib/libusb.so' LIBPOPPLER = '/usr/lib/libpoppler.so.3' diff --git a/installer/windows/calibre/calibre.mpi b/installer/windows/calibre/calibre.mpi index 3dc587e603..35de36caab 100644 --- a/installer/windows/calibre/calibre.mpi +++ b/installer/windows/calibre/calibre.mpi @@ -213,7 +213,6 @@ File ::D9A3AF75-5939-CB51-9F33-5A048911103E -type dir -name etc -parent 6CCF3F71 File ::A628E495-239B-DAF4-D858-BCE36CB41E6E -type dir -name imageformats -parent 6CCF3F71-74BB-ED69-D0E6-9F12348ABDD3 File ::0A533DB2-D494-A9ED-1334-DECC357BD426 -type dir -name codecs -parent 6CCF3F71-74BB-ED69-D0E6-9F12348ABDD3 File ::0F47A44E-E347-1CD4-E89F-37B447C4A270 -type dir -name driver -parent 6CCF3F71-74BB-ED69-D0E6-9F12348ABDD3 -File ::19A416A8-8DDD-658B-A3D4-F89ABD02CFBB -type dir -name ImageMagick -parent 6CCF3F71-74BB-ED69-D0E6-9F12348ABDD3 File ::A146565C-D163-7F68-7C70-A6A336B32526 -type dir -name iconengines -parent 6CCF3F71-74BB-ED69-D0E6-9F12348ABDD3 File ::3245B06C-1C22-1A8A-5710-6D36651AAA70 -name etree.pyd -parent 6CCF3F71-74BB-ED69-D0E6-9F12348ABDD3 File ::B49A5610-13F6-FB5D-0673-DB47C6BB385D -name rtf-meta.exe.local -parent 6CCF3F71-74BB-ED69-D0E6-9F12348ABDD3 @@ -355,6 +354,144 @@ File ::293E6ABE-17C9-5E53-1B44-C27029C8C061 -name winutil.pyd -parent 36E8EEAC-F File ::A5737158-18DF-7F20-2BDF-2DF615663891 -name lzx.pyd -parent 36E8EEAC-F54D-5DE9-02D8-ECDFEBB4B5E2 File ::CA9E098C-2931-9781-1303-213C242F9A5E -name lit2oeb.exe -parent 6CCF3F71-74BB-ED69-D0E6-9F12348ABDD3 File ::16B5A447-066C-C93E-F63D-8BC0D57CA544 -name lit2oeb.exe.local -parent 6CCF3F71-74BB-ED69-D0E6-9F12348ABDD3 +File ::ABF342D2-82A9-2A20-BA97-54AD5BAF1A2A -name IM_MOD_RL_sfw_.dll -parent 6CCF3F71-74BB-ED69-D0E6-9F12348ABDD3 +File ::3877E295-C7EB-DF63-DA91-B9E2F9D8035A -name comic2lrf.exe.local -parent 6CCF3F71-74BB-ED69-D0E6-9F12348ABDD3 +File ::F47345A3-6CE0-4F5B-9CAE-3F4A18D4AA5A -name IM_MOD_RL_rle_.dll -parent 6CCF3F71-74BB-ED69-D0E6-9F12348ABDD3 +File ::3A211C93-1B8B-A8AA-E240-A3287974DAB4 -name IM_MOD_RL_tiff_.dll -parent 6CCF3F71-74BB-ED69-D0E6-9F12348ABDD3 +File ::F24F3123-05A3-B452-D12B-CE6C126501B1 -name CORE_RL_libxml_.dll -parent 6CCF3F71-74BB-ED69-D0E6-9F12348ABDD3 +File ::D7034E85-2733-DB61-DB49-C34B767B4B45 -name IM_MOD_RL_sun_.dll -parent 6CCF3F71-74BB-ED69-D0E6-9F12348ABDD3 +File ::21C1F4D3-487E-5FFF-C8CE-8E5FE779A786 -name IM_MOD_RL_msl_.dll -parent 6CCF3F71-74BB-ED69-D0E6-9F12348ABDD3 +File ::01EC7979-C9CB-696C-E8B3-F5945E1115BB -name IM_MOD_RL_jp2_.dll -parent 6CCF3F71-74BB-ED69-D0E6-9F12348ABDD3 +File ::0F86B693-D83A-DB03-8641-219FE766D980 -name CORE_RL_ttf_.dll -parent 6CCF3F71-74BB-ED69-D0E6-9F12348ABDD3 +File ::DDCAEB76-7AC4-CA1A-0742-34B556592D2A -name IM_MOD_RL_exr_.dll -parent 6CCF3F71-74BB-ED69-D0E6-9F12348ABDD3 +File ::4D274537-6B6D-63F2-2615-E0CD279880A3 -name CORE_RL_Magick++_.dll -parent 6CCF3F71-74BB-ED69-D0E6-9F12348ABDD3 +File ::A87CE00E-9F87-DBE3-DDA5-FC68D6D0731E -name IM_MOD_RL_dib_.dll -parent 6CCF3F71-74BB-ED69-D0E6-9F12348ABDD3 +File ::9114D530-B73B-CC7C-F6A6-655B7271AB35 -name IM_MOD_RL_preview_.dll -parent 6CCF3F71-74BB-ED69-D0E6-9F12348ABDD3 +File ::31EE0880-F1C8-94D6-4EDC-B09A576E0908 -name CORE_RL_magick_.dll -parent 6CCF3F71-74BB-ED69-D0E6-9F12348ABDD3 +File ::BEA2B769-1A54-4398-E8B4-5BE15637B705 -name IM_MOD_RL_svg_.dll -parent 6CCF3F71-74BB-ED69-D0E6-9F12348ABDD3 +File ::7E300AD4-7C03-5835-0DD6-E9FA8737585A -name IM_MOD_RL_mpeg_.dll -parent 6CCF3F71-74BB-ED69-D0E6-9F12348ABDD3 +File ::5E9901D8-BBB7-A17C-5A04-837C0ADF8CAE -name IM_MOD_RL_clipboard_.dll -parent 6CCF3F71-74BB-ED69-D0E6-9F12348ABDD3 +File ::F13497D2-87C0-243D-916A-0A160F1A1896 -name IM_MOD_RL_png_.dll -parent 6CCF3F71-74BB-ED69-D0E6-9F12348ABDD3 +File ::DBD1CF95-1B01-9F5C-66D9-C7B4E1B44CC7 -name CORE_RL_bzlib_.dll -parent 6CCF3F71-74BB-ED69-D0E6-9F12348ABDD3 +File ::149C038D-9CD6-20C5-49C3-FC6948D0709D -name IM_MOD_RL_wmf_.dll -parent 6CCF3F71-74BB-ED69-D0E6-9F12348ABDD3 +File ::F77F5E54-1D54-F7D3-9520-BB1811C11AA6 -name IM_MOD_RL_txt_.dll -parent 6CCF3F71-74BB-ED69-D0E6-9F12348ABDD3 +File ::3545B38D-1BDF-B355-F779-4D83F292E2B6 -name IM_MOD_RL_viff_.dll -parent 6CCF3F71-74BB-ED69-D0E6-9F12348ABDD3 +File ::6E33F2FD-17BB-F096-4551-0E3B22924A4D -name IM_MOD_RL_ps2_.dll -parent 6CCF3F71-74BB-ED69-D0E6-9F12348ABDD3 +File ::F4C810FF-4291-4491-0FA2-CFAD0BA690A9 -name type.xml -parent 6CCF3F71-74BB-ED69-D0E6-9F12348ABDD3 +File ::02A3CD7D-743C-FAA8-9C20-3E8E59B8C2C2 -name IM_MOD_RL_ps3_.dll -parent 6CCF3F71-74BB-ED69-D0E6-9F12348ABDD3 +File ::697020D6-C5DA-A7DC-9454-1F9523D7748D -name IM_MOD_RL_dot_.dll -parent 6CCF3F71-74BB-ED69-D0E6-9F12348ABDD3 +File ::E9D0609E-2D12-A8C0-9B47-D09CACB4A3AF -name IM_MOD_RL_xwd_.dll -parent 6CCF3F71-74BB-ED69-D0E6-9F12348ABDD3 +File ::F237A6C8-4037-B9E5-8D65-29A5A69CADFE -name IM_MOD_RL_fits_.dll -parent 6CCF3F71-74BB-ED69-D0E6-9F12348ABDD3 +File ::BDB45C50-E57A-357D-1D5A-392036227E6B -name IM_MOD_RL_histogram_.dll -parent 6CCF3F71-74BB-ED69-D0E6-9F12348ABDD3 +File ::5A6DBEB5-CD8A-4109-A04C-EF0436BC1CDC -name mfc71.dll -parent 6CCF3F71-74BB-ED69-D0E6-9F12348ABDD3 +File ::FCC2A44D-D2F9-74DC-0C27-86F094E2C3E9 -name IM_MOD_RL_pnm_.dll -parent 6CCF3F71-74BB-ED69-D0E6-9F12348ABDD3 +File ::8E71473E-34AE-B7A3-B506-8A6AA622DAD7 -name IM_MOD_RL_ipl_.dll -parent 6CCF3F71-74BB-ED69-D0E6-9F12348ABDD3 +File ::B680E84A-BA1C-5EA2-902E-095DD22A48F2 -name msvcp71.dll -parent 6CCF3F71-74BB-ED69-D0E6-9F12348ABDD3 +File ::6AF09D1D-8889-8A87-9FD4-1471DBB1354C -name IM_MOD_RL_rgb_.dll -parent 6CCF3F71-74BB-ED69-D0E6-9F12348ABDD3 +File ::941B86E2-428A-3F4A-EB34-CBDBDDAD648C -name IM_MOD_RL_xbm_.dll -parent 6CCF3F71-74BB-ED69-D0E6-9F12348ABDD3 +File ::1613269D-8A63-C843-E862-9B80CC17E60F -name IM_MOD_RL_otb_.dll -parent 6CCF3F71-74BB-ED69-D0E6-9F12348ABDD3 +File ::334E3925-703D-DDCA-A079-C53DB06AA069 -name IM_MOD_RL_avi_.dll -parent 6CCF3F71-74BB-ED69-D0E6-9F12348ABDD3 +File ::23549B03-F856-3B90-C9C5-3B64A5910C7B -name CORE_RL_lcms_.dll -parent 6CCF3F71-74BB-ED69-D0E6-9F12348ABDD3 +File ::0E3F5727-D99A-44CD-35E0-4FDFBB95FCBC -name IM_MOD_RL_xpm_.dll -parent 6CCF3F71-74BB-ED69-D0E6-9F12348ABDD3 +File ::955B5799-4DB3-F422-589A-CDC20A82B6CB -name IM_MOD_RL_xcf_.dll -parent 6CCF3F71-74BB-ED69-D0E6-9F12348ABDD3 +File ::D3AB494C-3218-0137-4399-3FB1662C05D3 -name IM_MOD_RL_emf_.dll -parent 6CCF3F71-74BB-ED69-D0E6-9F12348ABDD3 +File ::1DEF5AF0-2376-539B-2A61-35B6ADC2F4BA -name log.xml -parent 6CCF3F71-74BB-ED69-D0E6-9F12348ABDD3 +File ::D472B449-3644-C538-30EF-EC42E3B84C43 -name IM_MOD_RL_mtv_.dll -parent 6CCF3F71-74BB-ED69-D0E6-9F12348ABDD3 +File ::8B4E61F1-8FC2-7E65-4B94-3F19100DF58B -name CORE_RL_tiff_.dll -parent 6CCF3F71-74BB-ED69-D0E6-9F12348ABDD3 +File ::B747FE2A-0054-6815-40D0-74F89FC8C757 -name IM_MOD_RL_dps_.dll -parent 6CCF3F71-74BB-ED69-D0E6-9F12348ABDD3 +File ::8B1660CC-7A97-96A2-1280-34554028CB9F -name IM_MOD_RL_dcm_.dll -parent 6CCF3F71-74BB-ED69-D0E6-9F12348ABDD3 +File ::21B7EBEC-30C8-F2E8-9D73-E4E6965EA856 -name locale.xml -parent 6CCF3F71-74BB-ED69-D0E6-9F12348ABDD3 +File ::85087BFC-42D6-C583-586E-19CAD45E6A61 -name CORE_RL_wand_.dll -parent 6CCF3F71-74BB-ED69-D0E6-9F12348ABDD3 +File ::BE24EB64-E7BB-0E63-256E-DEDC2BBF1C2B -name IM_MOD_RL_ttf_.dll -parent 6CCF3F71-74BB-ED69-D0E6-9F12348ABDD3 +File ::7693E752-1A81-F6F3-C55D-9E8D94D6E4DC -name IM_MOD_RL_dpx_.dll -parent 6CCF3F71-74BB-ED69-D0E6-9F12348ABDD3 +File ::A1451D28-A06B-3F03-4DCA-884729C5A030 -name IM_MOD_RL_jpeg_.dll -parent 6CCF3F71-74BB-ED69-D0E6-9F12348ABDD3 +File ::3F0D8F7A-906F-8CAE-84D7-E3480A09D39D -name IM_MOD_RL_fax_.dll -parent 6CCF3F71-74BB-ED69-D0E6-9F12348ABDD3 +File ::CA8F1852-F5C1-86E8-31B9-8B1EFE837ADB -name IM_MOD_RL_avs_.dll -parent 6CCF3F71-74BB-ED69-D0E6-9F12348ABDD3 +File ::72370AAC-67CF-F570-2AA2-658E4C81C859 -name IM_MOD_RL_mvg_.dll -parent 6CCF3F71-74BB-ED69-D0E6-9F12348ABDD3 +File ::A8265A1E-E9B5-A38F-9ACF-99669CAE1E9F -name IM_MOD_RL_tga_.dll -parent 6CCF3F71-74BB-ED69-D0E6-9F12348ABDD3 +File ::A8A9A383-0364-515F-C1D8-F82C274D652B -name configure.xml -parent 6CCF3F71-74BB-ED69-D0E6-9F12348ABDD3 +File ::A2167661-AF2B-E15E-60DA-715F47E5AA30 -name IM_MOD_RL_uil_.dll -parent 6CCF3F71-74BB-ED69-D0E6-9F12348ABDD3 +File ::7608E2FF-1BF6-E18A-A884-244794BDA01B -name IM_MOD_RL_cut_.dll -parent 6CCF3F71-74BB-ED69-D0E6-9F12348ABDD3 +File ::772CA344-5EFD-78A0-3542-777F12356C8D -name Xext.dll -parent 6CCF3F71-74BB-ED69-D0E6-9F12348ABDD3 +File ::37F8D85E-4EE9-80E5-A4A2-8F30444AD5CC -name IM_MOD_RL_scr_.dll -parent 6CCF3F71-74BB-ED69-D0E6-9F12348ABDD3 +File ::973011B9-D193-6D64-D4EB-D82B0C730379 -name IM_MOD_RL_map_.dll -parent 6CCF3F71-74BB-ED69-D0E6-9F12348ABDD3 +File ::9B9F088C-A20A-0C19-EF7D-52908A020D36 -name thresholds.xml -parent 6CCF3F71-74BB-ED69-D0E6-9F12348ABDD3 +File ::831AAF1C-7CBE-CAD3-79A8-7430E8DE484E -name IM_MOD_RL_thumbnail_.dll -parent 6CCF3F71-74BB-ED69-D0E6-9F12348ABDD3 +File ::85236603-D71F-359C-B235-98C77809DDF1 -name IM_MOD_RL_mpc_.dll -parent 6CCF3F71-74BB-ED69-D0E6-9F12348ABDD3 +File ::94300805-117F-8337-A9BF-41E10D8AB437 -name IM_MOD_RL_cmyk_.dll -parent 6CCF3F71-74BB-ED69-D0E6-9F12348ABDD3 +File ::618A299D-4A28-E37A-D4BF-9209B594FAAF -name IM_MOD_RL_pcd_.dll -parent 6CCF3F71-74BB-ED69-D0E6-9F12348ABDD3 +File ::9F6572D8-6BE6-290B-D4A7-A0D4E4DBAC23 -name IM_MOD_RL_sct_.dll -parent 6CCF3F71-74BB-ED69-D0E6-9F12348ABDD3 +File ::942E63AC-F579-0D17-FF56-E2C8CC5DECA3 -name IM_MOD_RL_pict_.dll -parent 6CCF3F71-74BB-ED69-D0E6-9F12348ABDD3 +File ::F68DE3F9-742C-D8EE-B2FC-FF9B37EED8F3 -name IM_MOD_RL_gradient_.dll -parent 6CCF3F71-74BB-ED69-D0E6-9F12348ABDD3 +File ::C460E29B-38EE-6FC0-757B-69563EFC3225 -name IM_MOD_RL_icon_.dll -parent 6CCF3F71-74BB-ED69-D0E6-9F12348ABDD3 +File ::AE00BD3D-734C-78F6-9078-C04749F4652A -name X11.dll -parent 6CCF3F71-74BB-ED69-D0E6-9F12348ABDD3 +File ::B70ED455-A480-56E3-3BDE-E06CDDB62C04 -name IM_MOD_RL_jbig_.dll -parent 6CCF3F71-74BB-ED69-D0E6-9F12348ABDD3 +File ::CFFC9A5D-2902-FD37-DBD1-6800C7C0C1AE -name magic.xml -parent 6CCF3F71-74BB-ED69-D0E6-9F12348ABDD3 +File ::32DA3775-410C-0391-7ADB-B58028CC04E2 -name IM_MOD_RL_mat_.dll -parent 6CCF3F71-74BB-ED69-D0E6-9F12348ABDD3 +File ::AB64F079-1F8D-BE3A-731B-4B20ABD20289 -name IM_MOD_RL_meta_.dll -parent 6CCF3F71-74BB-ED69-D0E6-9F12348ABDD3 +File ::5A7F49E9-119A-FD9B-8186-0BE6B9DCF210 -name IM_MOD_RL_gray_.dll -parent 6CCF3F71-74BB-ED69-D0E6-9F12348ABDD3 +File ::D92B4157-F307-64A4-9AA5-C5AA1F138E1B -name IM_MOD_RL_pwp_.dll -parent 6CCF3F71-74BB-ED69-D0E6-9F12348ABDD3 +File ::BA631BF0-CB17-D0EC-FAA9-D7B426457DD3 -name IM_MOD_RL_fpx_.dll -parent 6CCF3F71-74BB-ED69-D0E6-9F12348ABDD3 +File ::9EA95108-72D5-13B5-2BD4-87CECED9B367 -name IM_MOD_RL_pcl_.dll -parent 6CCF3F71-74BB-ED69-D0E6-9F12348ABDD3 +File ::3111AC7E-2387-AD7D-253F-979195AC4EA1 -name english.xml -parent 6CCF3F71-74BB-ED69-D0E6-9F12348ABDD3 +File ::14C1E910-6F5D-9540-7430-6B0B92311EB2 -name IM_MOD_RL_wpg_.dll -parent 6CCF3F71-74BB-ED69-D0E6-9F12348ABDD3 +File ::5D7050F4-177A-03A2-3DD1-A7DFC968E4ED -name IM_MOD_RL_pdb_.dll -parent 6CCF3F71-74BB-ED69-D0E6-9F12348ABDD3 +File ::5BACE29D-FAFD-E673-16A9-D22DCE6E0655 -name IM_MOD_RL_label_.dll -parent 6CCF3F71-74BB-ED69-D0E6-9F12348ABDD3 +File ::25F84452-26F7-4305-B405-B1D0C7D072D2 -name IM_MOD_RL_clip_.dll -parent 6CCF3F71-74BB-ED69-D0E6-9F12348ABDD3 +File ::807E6FF7-2D61-F308-BA2A-BD07A213078A -name IM_MOD_RL_pix_.dll -parent 6CCF3F71-74BB-ED69-D0E6-9F12348ABDD3 +File ::1A951976-DBCC-9FAE-190C-B24BBA38A97A -name colors.xml -parent 6CCF3F71-74BB-ED69-D0E6-9F12348ABDD3 +File ::8608BB2C-6CDE-BBE7-39C6-DF83625D5BFB -name IM_MOD_RL_cin_.dll -parent 6CCF3F71-74BB-ED69-D0E6-9F12348ABDD3 +File ::CBE1DFDA-7E32-759F-346E-DD469B1CE1F0 -name IM_MOD_RL_bmp_.dll -parent 6CCF3F71-74BB-ED69-D0E6-9F12348ABDD3 +File ::7AD432A3-5146-4966-8C8E-85ACDCC8CA7A -name IM_MOD_RL_raw_.dll -parent 6CCF3F71-74BB-ED69-D0E6-9F12348ABDD3 +File ::9DC22033-0F40-26CC-9E09-959738F62855 -name IM_MOD_RL_cip_.dll -parent 6CCF3F71-74BB-ED69-D0E6-9F12348ABDD3 +File ::A8C777EC-AEAA-6B3F-22A6-CEC28A2E5058 -name IM_MOD_RL_pdf_.dll -parent 6CCF3F71-74BB-ED69-D0E6-9F12348ABDD3 +File ::ACA1A829-27AE-EFE7-4EDD-01D050A2E0A6 -name analyze.dll -parent 6CCF3F71-74BB-ED69-D0E6-9F12348ABDD3 +File ::C883300E-0C2A-EAF6-D72E-81E8B99535E1 -name IM_MOD_RL_mpr_.dll -parent 6CCF3F71-74BB-ED69-D0E6-9F12348ABDD3 +File ::A223D40F-EFC5-31E3-8E33-B90984080A3E -name CORE_RL_jpeg_.dll -parent 6CCF3F71-74BB-ED69-D0E6-9F12348ABDD3 +File ::DE197248-9758-A368-6058-B72C5169E0DD -name IM_MOD_RL_wbmp_.dll -parent 6CCF3F71-74BB-ED69-D0E6-9F12348ABDD3 +File ::FD15A9C0-5C14-11CA-AA27-D66D638E58FC -name IM_MOD_RL_stegano_.dll -parent 6CCF3F71-74BB-ED69-D0E6-9F12348ABDD3 +File ::6668D58B-E040-328B-4AF4-14C738C172BA -name CORE_RL_jp2_.dll -parent 6CCF3F71-74BB-ED69-D0E6-9F12348ABDD3 +File ::871E464B-4566-1FC2-55CB-B65AEB416413 -name IM_MOD_RL_yuv_.dll -parent 6CCF3F71-74BB-ED69-D0E6-9F12348ABDD3 +File ::7D7A8325-4C69-B9D3-C832-803BCF999B5C -name coder.xml -parent 6CCF3F71-74BB-ED69-D0E6-9F12348ABDD3 +File ::B0A3651D-19B1-09F1-8197-1E58ED2CC704 -name IM_MOD_RL_null_.dll -parent 6CCF3F71-74BB-ED69-D0E6-9F12348ABDD3 +File ::AB877243-6DAE-BF0C-70C2-F2D702B16231 -name IM_MOD_RL_pattern_.dll -parent 6CCF3F71-74BB-ED69-D0E6-9F12348ABDD3 +File ::F571F366-1737-7E65-5441-DEBD166DE247 -name IM_MOD_RL_plasma_.dll -parent 6CCF3F71-74BB-ED69-D0E6-9F12348ABDD3 +File ::93F18CDE-B871-B2D4-3C0F-7C1B933E1ACB -name IM_MOD_RL_pcx_.dll -parent 6CCF3F71-74BB-ED69-D0E6-9F12348ABDD3 +File ::D1567C76-29D0-C200-9FC7-F7E1399D3011 -name CORE_RL_xlib_.dll -parent 6CCF3F71-74BB-ED69-D0E6-9F12348ABDD3 +File ::BEF1E1AC-9564-EA49-2B8F-1AAC9F6A7669 -name IM_MOD_RL_caption_.dll -parent 6CCF3F71-74BB-ED69-D0E6-9F12348ABDD3 +File ::2D14864E-6A39-FE03-4EA8-CCE7AC94487D -name comic2lrf.exe -parent 6CCF3F71-74BB-ED69-D0E6-9F12348ABDD3 +File ::27CD65A5-D5F9-C982-5096-65298417EE61 -name IM_MOD_RL_url_.dll -parent 6CCF3F71-74BB-ED69-D0E6-9F12348ABDD3 +File ::A273E901-0B63-390B-D44A-7240491C6F59 -name IM_MOD_RL_info_.dll -parent 6CCF3F71-74BB-ED69-D0E6-9F12348ABDD3 +File ::B39B27EC-325A-D222-01FC-F6B3BC92E99A -name IM_MOD_RL_hdf_.dll -parent 6CCF3F71-74BB-ED69-D0E6-9F12348ABDD3 +File ::BA634D39-716B-C895-73DD-2E5FA3CA2F9C -name CORE_RL_png_.dll -parent 6CCF3F71-74BB-ED69-D0E6-9F12348ABDD3 +File ::35560FB0-A7BD-54C7-C799-3EB2922BED2C -name delegates.xml -parent 6CCF3F71-74BB-ED69-D0E6-9F12348ABDD3 +File ::FCE51670-E4AE-B813-6CFC-A7A9B627F72C -name IM_MOD_RL_matte_.dll -parent 6CCF3F71-74BB-ED69-D0E6-9F12348ABDD3 +File ::D10DB719-887D-4898-DAA8-8F1C6A4203B2 -name IM_MOD_RL_mono_.dll -parent 6CCF3F71-74BB-ED69-D0E6-9F12348ABDD3 +File ::78A66F97-ECEC-BFEC-75F2-2FA2087927C2 -name CORE_RL_jbig_.dll -parent 6CCF3F71-74BB-ED69-D0E6-9F12348ABDD3 +File ::FB74C41B-3F08-A9E8-B38D-C7C2FDFE9560 -name IM_MOD_RL_xtrn_.dll -parent 6CCF3F71-74BB-ED69-D0E6-9F12348ABDD3 +File ::ABC0A7AF-B14B-09BE-4756-76C8FE771517 -name IM_MOD_RL_vicar_.dll -parent 6CCF3F71-74BB-ED69-D0E6-9F12348ABDD3 +File ::F69B9AAD-EC2B-5EC7-5ED8-1395033DE0F5 -name IM_MOD_RL_psd_.dll -parent 6CCF3F71-74BB-ED69-D0E6-9F12348ABDD3 +File ::66CB1D9D-9995-F71C-155D-F1F4AA3B6D40 -name IM_MOD_RL_uyvy_.dll -parent 6CCF3F71-74BB-ED69-D0E6-9F12348ABDD3 +File ::4DB66BC3-4C48-C763-9BCA-9E831CA1FF0B -name IM_MOD_RL_art_.dll -parent 6CCF3F71-74BB-ED69-D0E6-9F12348ABDD3 +File ::EB24F574-4226-6404-B069-7B46C04988E0 -name IM_MOD_RL_ycbcr_.dll -parent 6CCF3F71-74BB-ED69-D0E6-9F12348ABDD3 +File ::A9990A18-D6A1-AA14-1EDF-FC43D8AE0C7E -name type-ghostscript.xml -parent 6CCF3F71-74BB-ED69-D0E6-9F12348ABDD3 +File ::5B72558A-192B-76EB-1BA8-C4CBA43C6C05 -name IM_MOD_RL_x_.dll -parent 6CCF3F71-74BB-ED69-D0E6-9F12348ABDD3 +File ::A3937F85-1D17-D3DD-2DF5-FB9FE4A99ADB -name IM_MOD_RL_dng_.dll -parent 6CCF3F71-74BB-ED69-D0E6-9F12348ABDD3 +File ::B2C41CC1-EB2D-F7E7-B22E-0C154C4C96C1 -name IM_MOD_RL_html_.dll -parent 6CCF3F71-74BB-ED69-D0E6-9F12348ABDD3 +File ::68A62902-7F48-6E7A-E5D3-1F58C895B409 -name IM_MOD_RL_tim_.dll -parent 6CCF3F71-74BB-ED69-D0E6-9F12348ABDD3 +File ::E5C83E45-56B1-9BD7-7676-07CABD98E0BF -name IM_MOD_RL_tile_.dll -parent 6CCF3F71-74BB-ED69-D0E6-9F12348ABDD3 +File ::084206D9-98DB-DE2A-19BC-FD17A191096D -name IM_MOD_RL_xc_.dll -parent 6CCF3F71-74BB-ED69-D0E6-9F12348ABDD3 +File ::43BE7C18-6369-E035-8390-2E13C8CBB33C -name CORE_RL_zlib_.dll -parent 6CCF3F71-74BB-ED69-D0E6-9F12348ABDD3 +File ::EFC4D6E5-4FC9-25D5-B308-8CC8C13EF3A1 -name IM_MOD_RL_gif_.dll -parent 6CCF3F71-74BB-ED69-D0E6-9F12348ABDD3 +File ::05A8646B-F100-4803-5916-4CBAC154BFE9 -name IM_MOD_RL_sgi_.dll -parent 6CCF3F71-74BB-ED69-D0E6-9F12348ABDD3 +File ::1B354F22-4795-739A-A47D-8F2D99DFB58A -name IM_MOD_RL_ept_.dll -parent 6CCF3F71-74BB-ED69-D0E6-9F12348ABDD3 +File ::B6725A29-1F09-2982-6BE1-29062A90F684 -name IM_MOD_RL_palm_.dll -parent 6CCF3F71-74BB-ED69-D0E6-9F12348ABDD3 +File ::445BD28F-0E70-B452-15B3-9E0C353CE345 -name IM_MOD_RL_ps_.dll -parent 6CCF3F71-74BB-ED69-D0E6-9F12348ABDD3 +File ::183A1789-2ED2-D555-AE4B-B7EBC97EB1D5 -name IM_MOD_RL_miff_.dll -parent 6CCF3F71-74BB-ED69-D0E6-9F12348ABDD3 +File ::69178142-77D3-D7C5-74C7-6F1597474123 -name IM_MOD_RL_vid_.dll -parent 6CCF3F71-74BB-ED69-D0E6-9F12348ABDD3 +File ::9D84C810-6DEC-5831-CFC6-AD0543D95881 -name IM_MOD_RL_rla_.dll -parent 6CCF3F71-74BB-ED69-D0E6-9F12348ABDD3 +File ::514DCC61-0BE9-6C5C-A970-170219D3A87E -name IM_MOD_RL_magick_.dll -parent 6CCF3F71-74BB-ED69-D0E6-9F12348ABDD3 +File ::AAF94AED-250D-DE8D-14C5-FA8BC05AAE74 -name IM_MOD_RL_djvu_.dll -parent 6CCF3F71-74BB-ED69-D0E6-9F12348ABDD3 Component ::F6829AB7-9F66-4CEE-CA0E-21F54C6D3609 -setup Install -active Yes -platforms {AIX-ppc FreeBSD-4-x86 FreeBSD-x86 HPUX-hppa Linux-x86 Solaris-sparc Windows} -name Main -parent Components SetupType ::D9ADE41C-B744-690C-2CED-CF826BF03D2E -setup Install -active Yes -platforms {AIX-ppc FreeBSD-4-x86 FreeBSD-x86 HPUX-hppa Linux-x86 Solaris-sparc Windows} -name Typical -parent SetupTypes diff --git a/setup.py b/setup.py index 9150a28b90..4a2ed4f372 100644 --- a/setup.py +++ b/setup.py @@ -48,112 +48,140 @@ main_functions = { if __name__ == '__main__': from setuptools import setup, find_packages, Extension import subprocess, glob + if 'mydevelop' in sys.argv: + LAUNCHER = '''\ +#!%(exe)s +import sys +sys.path.insert(0, %(ppath)s) +sys.argv[0] = %(basename)s +from %(module)s import %(func)s +%(func)s() - entry_points['console_scripts'].append('calibre_postinstall = calibre.linux:post_install') - ext_modules = [Extension('calibre.plugins.lzx', - sources=['src/calibre/utils/lzx/lzxmodule.c', - 'src/calibre/utils/lzx/lzxd.c'], - include_dirs=['src/calibre/utils/lzx']), - Extension('calibre.plugins.msdes', - sources=['src/calibre/utils/msdes/msdesmodule.c', - 'src/calibre/utils/msdes/des.c'], - include_dirs=['src/calibre/utils/msdes'])] - if iswindows: - ext_modules.append(Extension('calibre.plugins.winutil', - sources=['src/calibre/utils/windows/winutil.c'], - libraries=['shell32', 'setupapi'], - include_dirs=['C:/WinDDK/6001.18001/inc/api/']) - ) - if isosx: - ext_modules.append(Extension('calibre.plugins.usbobserver', - sources=['src/calibre/devices/usbobserver/usbobserver.c']) - ) + ''' + bindir = os.path.expanduser('~/bin') + def create_launcher(basename, module, func): + args = dict(exe=os.path.realpath(sys.executable), + ppath=repr(os.path.abspath('src')), + basename=repr(basename), + module=module, + func=func) + script = LAUNCHER%args + p = os.path.join(bindir, basename) + open(p, 'wb').write(script) + subprocess.check_call('chmod +x '+p, shell=True) + for x in ('console', 'gui'): + for i in range(len(basenames[x])): + create_launcher(basenames[x][i], main_modules[x][i], main_functions[x][i]) + create_launcher('calibre_postinstall', 'calibre.linux', 'post_install') + subprocess.check_call('python setup.py build', shell=True) + subprocess.check_call('sudo %s/calibre_postinstall'%bindir, shell=True) + else: - def build_PyQt_extension(path): - pro = glob.glob(os.path.join(path, '*.pro'))[0] - raw = open(pro).read() - base = qtplugin = re.search(r'TARGET\s*=\s*(.*)', raw).group(1) - ver = re.search(r'VERSION\s*=\s*(\d+)', raw).group(1) - cwd = os.getcwd() - os.chdir(os.path.dirname(pro)) - try: - if not os.path.exists('.build'): - os.mkdir('.build') - os.chdir('.build') - subprocess.check_call(( (os.path.expanduser('~/qt/bin/qmake') if isosx else 'qmake'), '..'+os.sep+os.path.basename(pro))) - subprocess.check_call(['mingw32-make' if iswindows else 'make']) - os.chdir(os.path.join('..', 'PyQt')) - if not os.path.exists('.build'): - os.mkdir('.build') - os.chdir('.build') - python = '/Library/Frameworks/Python.framework/Versions/Current/bin/python' if isosx else 'python' - subprocess.check_call([python, '..'+os.sep+'configure.py']) - subprocess.check_call(['mingw32-make' if iswindows else 'make']) - ext = '.pyd' if iswindows else '.so' - plugin = glob.glob(base+ext)[0] - shutil.copyfile(plugin, os.path.join(cwd, 'src', 'calibre', 'plugins', plugin)) - finally: - os.chdir(cwd) - if islinux or isosx: - for f in glob.glob(os.path.join('src', 'calibre', 'plugins', '*')): - try: - os.readlink(f) - os.unlink(f) - except: - continue + entry_points['console_scripts'].append('calibre_postinstall = calibre.linux:post_install') + ext_modules = [Extension('calibre.plugins.lzx', + sources=['src/calibre/utils/lzx/lzxmodule.c', + 'src/calibre/utils/lzx/lzxd.c'], + include_dirs=['src/calibre/utils/lzx']), + Extension('calibre.plugins.msdes', + sources=['src/calibre/utils/msdes/msdesmodule.c', + 'src/calibre/utils/msdes/des.c'], + include_dirs=['src/calibre/utils/msdes'])] + if iswindows: + ext_modules.append(Extension('calibre.plugins.winutil', + sources=['src/calibre/utils/windows/winutil.c'], + libraries=['shell32', 'setupapi'], + include_dirs=['C:/WinDDK/6001.18001/inc/api/']) + ) + if isosx: + ext_modules.append(Extension('calibre.plugins.usbobserver', + sources=['src/calibre/devices/usbobserver/usbobserver.c']) + ) - for path in [(os.path.join('src', 'calibre', 'gui2', 'pictureflow'))]: - build_PyQt_extension(path) + def build_PyQt_extension(path): + pro = glob.glob(os.path.join(path, '*.pro'))[0] + raw = open(pro).read() + base = qtplugin = re.search(r'TARGET\s*=\s*(.*)', raw).group(1) + ver = re.search(r'VERSION\s*=\s*(\d+)', raw).group(1) + cwd = os.getcwd() + os.chdir(os.path.dirname(pro)) + try: + if not os.path.exists('.build'): + os.mkdir('.build') + os.chdir('.build') + subprocess.check_call(( (os.path.expanduser('~/qt/bin/qmake') if isosx else 'qmake'), '..'+os.sep+os.path.basename(pro))) + subprocess.check_call(['mingw32-make' if iswindows else 'make']) + os.chdir(os.path.join('..', 'PyQt')) + if not os.path.exists('.build'): + os.mkdir('.build') + os.chdir('.build') + python = '/Library/Frameworks/Python.framework/Versions/Current/bin/python' if isosx else 'python' + subprocess.check_call([python, '..'+os.sep+'configure.py']) + subprocess.check_call(['mingw32-make' if iswindows else 'make']) + ext = '.pyd' if iswindows else '.so' + plugin = glob.glob(base+ext)[0] + shutil.copyfile(plugin, os.path.join(cwd, 'src', 'calibre', 'plugins', plugin)) + finally: + os.chdir(cwd) + if islinux or isosx: + for f in glob.glob(os.path.join('src', 'calibre', 'plugins', '*')): + try: + os.readlink(f) + os.unlink(f) + except: + continue - setup( - name=APPNAME, - packages = find_packages('src'), - package_dir = { '' : 'src' }, - version=VERSION, - author='Kovid Goyal', - author_email='kovid@kovidgoyal.net', - url = 'http://%s.kovidgoyal.net'%APPNAME, - package_data = {'calibre':['plugins/*']}, - include_package_data=True, - entry_points = entry_points, - zip_safe = False, - options = { 'bdist_egg' : {'exclude_source_files': True,}, }, - ext_modules=ext_modules, - description = - ''' - E-book management application. - ''', - long_description = - ''' - %s is an e-book library manager. It can view, convert and catalog e-books in most of the major e-book formats. It can also talk to a few e-book reader devices. It can go out to the internet and fetch metadata for your books. It can download newspapers and convert them into e-books for convenient reading. It is cross platform, running on Linux, Windows and OS X. + for path in [(os.path.join('src', 'calibre', 'gui2', 'pictureflow'))]: + build_PyQt_extension(path) - For screenshots: https://%s.kovidgoyal.net/wiki/Screenshots + setup( + name=APPNAME, + packages = find_packages('src'), + package_dir = { '' : 'src' }, + version=VERSION, + author='Kovid Goyal', + author_email='kovid@kovidgoyal.net', + url = 'http://%s.kovidgoyal.net'%APPNAME, + package_data = {'calibre':['plugins/*']}, + include_package_data=True, + entry_points = entry_points, + zip_safe = False, + options = { 'bdist_egg' : {'exclude_source_files': True,}, }, + ext_modules=ext_modules, + description = + ''' + E-book management application. + ''', + long_description = + ''' + %s is an e-book library manager. It can view, convert and catalog e-books in most of the major e-book formats. It can also talk to a few e-book reader devices. It can go out to the internet and fetch metadata for your books. It can download newspapers and convert them into e-books for convenient reading. It is cross platform, running on Linux, Windows and OS X. - For installation/usage instructions please see - http://%s.kovidgoyal.net + For screenshots: https://%s.kovidgoyal.net/wiki/Screenshots - For source code access: - bzr branch http://bzr.kovidgoyal.net/code/%s/trunk %s + For installation/usage instructions please see + http://%s.kovidgoyal.net - To update your copy of the source code: - bzr merge + For source code access: + bzr branch http://bzr.kovidgoyal.net/code/%s/trunk %s - '''%(APPNAME, APPNAME, APPNAME, APPNAME, APPNAME), - license = 'GPL', - classifiers = [ - 'Development Status :: 4 - Beta', - 'Environment :: Console', - 'Environment :: X11 Applications :: Qt', - 'Intended Audience :: Developers', - 'Intended Audience :: End Users/Desktop', - 'License :: OSI Approved :: GNU General Public License (GPL)', - 'Natural Language :: English', - 'Operating System :: POSIX :: Linux', - 'Programming Language :: Python', - 'Topic :: Software Development :: Libraries :: Python Modules', - 'Topic :: System :: Hardware :: Hardware Drivers' - ] - ) + To update your copy of the source code: + bzr merge - if 'develop' in ' '.join(sys.argv) and islinux: - subprocess.check_call('calibre_postinstall', shell=True) + '''%(APPNAME, APPNAME, APPNAME, APPNAME, APPNAME), + license = 'GPL', + classifiers = [ + 'Development Status :: 4 - Beta', + 'Environment :: Console', + 'Environment :: X11 Applications :: Qt', + 'Intended Audience :: Developers', + 'Intended Audience :: End Users/Desktop', + 'License :: OSI Approved :: GNU General Public License (GPL)', + 'Natural Language :: English', + 'Operating System :: POSIX :: Linux', + 'Programming Language :: Python', + 'Topic :: Software Development :: Libraries :: Python Modules', + 'Topic :: System :: Hardware :: Hardware Drivers' + ] + ) + + if 'develop' in ' '.join(sys.argv) and islinux: + subprocess.check_call('calibre_postinstall', shell=True) diff --git a/src/calibre/debug.py b/src/calibre/debug.py index 7a12ee62b5..f6f869cdb8 100644 --- a/src/calibre/debug.py +++ b/src/calibre/debug.py @@ -7,7 +7,7 @@ Embedded console for debugging. ''' import sys, os, re -from calibre import OptionParser, iswindows +from calibre import OptionParser, iswindows, isosx from calibre.libunzip import update def option_parser(): @@ -30,13 +30,18 @@ def update_zipfile(zipfile, mod, path): pat = re.compile(mod.replace('.', '/')+r'\.py[co]*') name = mod.replace('.', '/') + os.path.splitext(path)[-1] update(zipfile, [pat], [path], [name]) - + def update_module(mod, path): if not hasattr(sys, 'frozen'): raise RuntimeError('Modules can only be updated in frozen installs.') - if True or iswindows: + zp = None + if iswindows: zp = os.path.join(os.path.dirname(sys.executable), 'library.zip') + elif isosx: + zp = os.path.join(os.path.dirname(getattr(sys, 'frameworks_dir')), + 'Resources', 'lib', 'python2.5', 'site-packages.zip') + if zp is not None: update_zipfile(zp, mod, path) else: raise ValueError('Updating modules is not supported on this platform.') @@ -53,10 +58,10 @@ def main(args=sys.argv): from IPython.Shell import IPShellEmbed ipshell = IPShellEmbed() ipshell() - - + + return 0 if __name__ == '__main__': - sys.exit(main()) \ No newline at end of file + sys.exit(main()) diff --git a/src/calibre/devices/prs500/cli/main.py b/src/calibre/devices/prs500/cli/main.py index d85daf075c..dfd3eb1ed6 100755 --- a/src/calibre/devices/prs500/cli/main.py +++ b/src/calibre/devices/prs500/cli/main.py @@ -11,7 +11,7 @@ from optparse import OptionParser from calibre import __version__, iswindows, __appname__ from calibre.devices.errors import PathError -from calibre.terminfo import TerminalController +from calibre.utils.terminfo import TerminalController from calibre.devices.errors import ArgumentError, DeviceError, DeviceLocked from calibre.devices import devices from calibre.devices.scanner import DeviceScanner diff --git a/src/calibre/linux.py b/src/calibre/linux.py index efcb49b54c..8fbab59bcf 100644 --- a/src/calibre/linux.py +++ b/src/calibre/linux.py @@ -16,14 +16,14 @@ if os.environ.has_key('DESTDIR'): entry_points = { 'console_scripts': [ \ - 'prs500 = calibre.devices.prs500.cli.main:main', - 'lrf-meta = calibre.ebooks.lrf.meta:main', - 'rtf-meta = calibre.ebooks.metadata.rtf:main', - 'pdf-meta = calibre.ebooks.metadata.pdf:main', + 'prs500 = calibre.devices.prs500.cli.main:main', + 'lrf-meta = calibre.ebooks.lrf.meta:main', + 'rtf-meta = calibre.ebooks.metadata.rtf:main', + 'pdf-meta = calibre.ebooks.metadata.pdf:main', 'lit-meta = calibre.ebooks.metadata.lit:main', 'opf-meta = calibre.ebooks.metadata.opf:main', 'epub-meta = calibre.ebooks.metadata.epub:main', - 'txt2lrf = calibre.ebooks.lrf.txt.convert_from:main', + 'txt2lrf = calibre.ebooks.lrf.txt.convert_from:main', 'html2lrf = calibre.ebooks.lrf.html.convert_from:main', 'markdown-calibre = calibre.ebooks.markdown.markdown:main', 'lit2lrf = calibre.ebooks.lrf.lit.convert_from:main', @@ -51,8 +51,8 @@ entry_points = { 'calibredb = calibre.library.cli:main', 'calibre-fontconfig = calibre.utils.fontconfig:main', 'calibre-parallel = calibre.parallel:main', - ], - 'gui_scripts' : [ + ], + 'gui_scripts' : [ __appname__+' = calibre.gui2.main:main', 'lrfviewer = calibre.gui2.lrf_renderer.main:main', ], @@ -60,7 +60,7 @@ entry_points = { def options(option_parser): - parser = option_parser() + parser = option_parser() options = parser.option_list for group in parser.option_groups: options += group.option_list @@ -72,7 +72,7 @@ def options(option_parser): def opts_and_words(name, op, words): opts = '|'.join(options(op)) - words = '|'.join([w.replace("'", "\\'") for w in words]) + words = '|'.join([w.replace("'", "\\'") for w in words]) return '_'+name+'()'+\ ''' { @@ -82,13 +82,13 @@ def opts_and_words(name, op, words): cur="${COMP_WORDS[COMP_CWORD]}" opts="%s" words="%s" - + case "${cur}" in -* ) COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) ) COMPREPLY=( $( echo ${COMPREPLY[@]} | sed 's/ /\\\\ /g' | tr '\\n' '\\t' ) ) return 0 - ;; + ;; * ) COMPREPLY=( $(compgen -W "${words}" -- ${cur}) ) COMPREPLY=( $( echo ${COMPREPLY[@]} | sed 's/ /\\\\ /g' | tr '\\n' '\\t' ) ) @@ -167,16 +167,16 @@ def setup_completion(fatal_errors): from calibre.ebooks.lrf.feeds.convert_from import option_parser as feeds2lrf from calibre.ebooks.metadata.epub import option_parser as epub_meta from calibre.ebooks.lrf.comic.convert_from import option_parser as comicop - + f = open_file('/etc/bash_completion.d/libprs500') f.close() os.remove(f.name) manifest = [] f = open_file('/etc/bash_completion.d/calibre') manifest.append(f.name) - + f.write('# calibre Bash Shell Completion\n') - f.write(opts_and_exts('html2lrf', htmlop, + f.write(opts_and_exts('html2lrf', htmlop, ['htm', 'html', 'xhtml', 'xhtm', 'rar', 'zip', 'php'])) f.write(opts_and_exts('txt2lrf', txtop, ['txt'])) f.write(opts_and_exts('lit2lrf', htmlop, ['lit'])) @@ -185,8 +185,8 @@ def setup_completion(fatal_errors): f.write(opts_and_exts('mobi2lrf', htmlop, ['mobi', 'prc'])) f.write(opts_and_exts('fb22lrf', htmlop, ['fb2'])) f.write(opts_and_exts('pdf2lrf', htmlop, ['pdf'])) - f.write(opts_and_exts('any2lrf', htmlop, - ['epub', 'htm', 'html', 'xhtml', 'xhtm', 'rar', 'zip', + f.write(opts_and_exts('any2lrf', htmlop, + ['epub', 'htm', 'html', 'xhtml', 'xhtm', 'rar', 'zip', 'txt', 'lit', 'rtf', 'pdf', 'prc', 'mobi', 'fb2'])) f.write(opts_and_exts('lrf2lrs', lrf2lrsop, ['lrf'])) f.write(opts_and_exts('lrf-meta', metaop, ['lrf'])) @@ -228,17 +228,17 @@ _prs500_ls() prefix="${prefix}/" fi - echo $(compgen -P "${prefix}" -W "${listing}" "${pattern}") + echo $(compgen -P "${prefix}" -W "${listing}" "${pattern}") } _prs500() { - local cur prev + local cur prev cur="${COMP_WORDS[COMP_CWORD]}" prev="${COMP_WORDS[COMP_CWORD-1]}" COMPREPLY=() case "${prev}" in - ls|rm|mkdir|touch|cat ) + ls|rm|mkdir|touch|cat ) COMPREPLY=( $(_prs500_ls "${cur}") ) return 0 ;; @@ -284,7 +284,7 @@ complete -o nospace -F _prs500 prs500 import traceback traceback.print_exc() return manifest - + def setup_udev_rules(group_file, reload, fatal_errors): print 'Trying to setup udev rules...' manifest = [] @@ -325,7 +325,7 @@ def setup_udev_rules(group_file, reload, fatal_errors): break if not called and os.access('/etc/rc.d/rc.hald', os.X_OK): call(('/etc/rc.d/rc.hald', 'restart')) - + try: check_call('udevadm control --reload_rules', shell=True) except: @@ -351,9 +351,9 @@ def option_parser(): help='File from which to read group information. Default: %default') parser.add_option('--dont-check-root', action='store_true', default=False, dest='no_root', help='If set, do not check if we are root.') - parser.add_option('--make-errors-fatal', action='store_true', default=False, + parser.add_option('--make-errors-fatal', action='store_true', default=False, dest='fatal_errors', help='If set die on errors.') - parser.add_option('--save-manifest-to', default=None, + parser.add_option('--save-manifest-to', default=None, help='Save a manifest of all installed files to the specified location') return parser @@ -366,12 +366,14 @@ def install_man_pages(fatal_errors): f.write('[see also]\nhttp://%s.kovidgoyal.net\n'%__appname__) f.close() manifest = [] + os.environ['PATH'] += ':'+os.path.expanduser('~/bin') for src in entry_points['console_scripts']: prog = src[:src.index('=')].strip() - if prog in ('prs500', 'pdf-meta', 'epub-meta', 'lit-meta', + if prog in ('prs500', 'pdf-meta', 'epub-meta', 'lit-meta', 'markdown-calibre', 'calibre-debug', 'fb2-meta', 'calibre-fontconfig', 'calibre-parallel'): continue + help2man = ('help2man', prog, '--name', 'part of %s'%__appname__, '--section', '1', '--no-info', '--include', f.name, '--manual', __appname__) @@ -390,18 +392,18 @@ def install_man_pages(fatal_errors): print 'Unable to create MAN page for', prog continue f2 = open_file(manfile) - manifest.append(f2.name) + manifest.append(f2.name) f2.write(compress(raw)) return manifest def post_install(): parser = option_parser() opts = parser.parse_args()[0] - + if not opts.no_root and os.geteuid() != 0: print >> sys.stderr, 'You must be root to run this command.' sys.exit(1) - + global use_destdir use_destdir = opts.destdir manifest = [] @@ -409,18 +411,18 @@ def post_install(): manifest += setup_completion(opts.fatal_errors) setup_desktop_integration(opts.fatal_errors) manifest += install_man_pages(opts.fatal_errors) - + try: from PyQt4 import Qt if Qt.PYQT_VERSION < int('0x40402', 16): print 'WARNING: You need PyQt >= 4.4.2 for the GUI. You have', Qt.PYQT_VERSION_STR, '\nYou may experience crashes or other strange behavior.' except ImportError: print 'WARNING: You do not have PyQt4 installed. The GUI will not work.' - + if opts.save_manifest_to: open(opts.save_manifest_to, 'wb').write('\n'.join(manifest)+'\n') - + VIEWER = '''\ [Desktop Entry] Version=%s @@ -478,10 +480,10 @@ def setup_desktop_integration(fatal_errors): from PyQt4.QtCore import QFile from calibre.gui2 import images_rc # Load images from tempfile import mkdtemp - + print 'Setting up desktop integration...' - - + + tdir = mkdtemp() cwd = os.getcwdu() try: @@ -493,7 +495,7 @@ def setup_desktop_integration(fatal_errors): check_call('xdg-icon-resource install --size 128 calibre-gui.png calibre-gui', shell=True) render_svg(QFile(':/images/viewer.svg'), os.path.join(tdir, 'calibre-viewer.png')) check_call('xdg-icon-resource install --size 128 calibre-viewer.png calibre-viewer', shell=True) - + f = open('calibre-lrfviewer.desktop', 'wb') f.write(VIEWER) f.close() @@ -513,11 +515,11 @@ def setup_desktop_integration(fatal_errors): raise print >>sys.stderr, 'Could not setup desktop integration. Error:' print err - - + + if __name__ == '__main__': post_install() - - - + + + diff --git a/src/calibre/manual/faq.rst b/src/calibre/manual/faq.rst index f35c14d493..780de1d85b 100644 --- a/src/calibre/manual/faq.rst +++ b/src/calibre/manual/faq.rst @@ -142,7 +142,7 @@ If it still wont launch, start a command prompt (press the windows key and R; th calibre-debug -c "from calibre.gui2.main import main; main()" -Post any output you see in a help message on the `Forums `_. I want some feature added to |app|. What can I do? diff --git a/src/calibre/manual/resources/logo.png b/src/calibre/manual/resources/logo.png index ee3f19baa694403ad0a421b2f41bf8523f3f2842..42b9568956496f00a3b707126d35529af745adae 100644 GIT binary patch literal 9261 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 P00000NkvXXu0mjf2#Lp* literal 31560 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 LNkvXXu0mjfxah}a diff --git a/src/calibre/parallel.py b/src/calibre/parallel.py index a26e5e0721..cde249a779 100644 --- a/src/calibre/parallel.py +++ b/src/calibre/parallel.py @@ -13,7 +13,7 @@ has the environment variable :envvar:`CALIBRE_WORKER` defined. The worker control protocol has two modes of operation. In the first mode, the worker process listens for commands from the controller process. The controller -process can either hand off a job to the worker or tell the worker to die. +process can either hand off a job to the worker or tell the worker to die. Once a job is handed off to the worker, the protocol enters the second mode, where the controller listens for messages from the worker. The worker can send progress updates as well as console output (i.e. text that would normally have been written to stdout @@ -22,7 +22,7 @@ returns the result (or exception) to the controller and the protocol reverts to In the second mode, the controller can also send the worker STOP messages, in which case the worker interrupts the job and dies. The sending of progress and console output messages -is buffered and asynchronous to prevent the job from being IO bound. +is buffered and asynchronous to prevent the job from being IO bound. ''' import sys, os, gc, cPickle, traceback, atexit, cStringIO, time, signal, \ subprocess, socket, collections, binascii, re, thread, tempfile @@ -37,20 +37,20 @@ DEBUG = False #: A mapping from job names to functions that perform the jobs PARALLEL_FUNCS = { - 'any2lrf' : + 'any2lrf' : ('calibre.ebooks.lrf.any.convert_from', 'main', dict(gui_mode=True), None), - - 'lrfviewer' : + + 'lrfviewer' : ('calibre.gui2.lrf_renderer.main', 'main', {}, None), - - 'feeds2lrf' : + + 'feeds2lrf' : ('calibre.ebooks.lrf.feeds.convert_from', 'main', {}, 'notification'), - - 'render_table' : + + 'render_table' : ('calibre.ebooks.lrf.html.table_as_image', 'do_render', {}, None), - + 'comic2lrf' : - ('calibre.ebooks.lrf.comic.convert_from', 'do_convert', {}, 'notification'), + ('calibre.ebooks.lrf.comic.convert_from', 'do_convert', {}, 'notification'), } @@ -67,20 +67,20 @@ class WorkerStatus(object): ''' A platform independent class to control child processes. Provides the methods: - + .. method:: WorkerStatus.is_alive() - + Return True is the child process is alive (i.e. it hasn't exited and returned a return code). - + .. method:: WorkerStatus.returncode() - + Wait for the child process to exit and return its return code (blocks until child returns). - + .. method:: WorkerStatus.kill() - - Forcibly terminates child process using operating system specific semantics. + + Forcibly terminates child process using operating system specific semantics. ''' - + def __init__(self, obj): ''' `obj`: On windows a process handle, on unix a subprocess.Popen object. @@ -92,22 +92,22 @@ class WorkerStatus(object): ext = 'windows' if iswindows else 'unix' for func in ('is_alive', 'returncode', 'kill'): setattr(self, func, getattr(self, func+'_'+ext)) - + def is_alive_unix(self): return self.obj.poll() == None - + def returncode_unix(self): return self.obj.wait() - + def kill_unix(self): os.kill(self.obj.pid, self.signal.SIGKILL) - + def is_alive_windows(self): return win32event.WaitForSingleObject(self.obj, 0) != win32event.WAIT_OBJECT_0 - + def returncode_windows(self): return win32process.GetExitCodeProcess(self.obj) - + def kill_windows(self, returncode=-1): self.win32process.TerminateProcess(self.obj, returncode) @@ -115,16 +115,16 @@ class WorkerMother(object): ''' Platform independent object for launching child processes. All processes have the environment variable :envvar:`CALIBRE_WORKER` set. - + ..method:: WorkerMother.spawn_free_spirit(arg) - + Launch a non monitored process with argument `arg`. - + ..method:: WorkerMother.spawn_worker(arg) - - Launch a monitored and controllable process with argument `arg`. + + Launch a monitored and controllable process with argument `arg`. ''' - + def __init__(self): ext = 'windows' if iswindows else 'osx' if isosx else 'linux' self.os = os # Needed incase cleanup called when interpreter is shutting down @@ -140,26 +140,28 @@ class WorkerMother(object): contents = os.path.dirname(fd) resources = os.path.join(contents, 'Resources') sp = os.path.join(resources, 'lib', 'python'+sys.version[:3], 'site-packages.zip') - + self.prefix += 'import sys; sys.frameworks_dir = "%s"; sys.frozen = "macosx_app"; '%fd self.prefix += 'sys.path.insert(0, %s); '%repr(sp) if fd not in os.environ['PATH']: - self.env['PATH'] = os.environ['PATH']+':'+fd - self.env['PYTHONHOME'] = resources + self.env['PATH'] = os.environ['PATH']+':'+fd + self.env['PYTHONHOME'] = resources + self.env['MAGICK_HOME'] = os.path.join(getattr(sys, 'frameworks_dir'), 'ImageMagick') + self.env['DYLD_LIBRARY_PATH'] = os.path.join(getattr(sys, 'frameworks_dir'), 'ImageMagick', 'lib') else: self.executable = os.path.join(getattr(sys, 'frozen_path'), 'calibre-parallel') \ if isfrozen else 'calibre-parallel' if isfrozen: self.env['LD_LIBRARY_PATH'] = getattr(sys, 'frozen_path') + ':' + os.environ.get('LD_LIBRARY_PATH', '') - + self.spawn_worker_windows = lambda arg : self.spawn_free_spirit_windows(arg, type='worker') self.spawn_worker_linux = lambda arg : self.spawn_free_spirit_linux(arg, type='worker') self.spawn_worker_osx = lambda arg : self.spawn_free_spirit_osx(arg, type='worker') - + for func in ('spawn_free_spirit', 'spawn_worker'): setattr(self, func, getattr(self, func+'_'+ext)) - - + + def cleanup_child_windows(self, child, name=None, fd=None): try: child.kill() @@ -175,13 +177,13 @@ class WorkerMother(object): self.os.unlink(name) except: pass - + def cleanup_child_linux(self, child): try: child.kill() except: - pass - + pass + def get_env(self): env = dict(os.environ) env['CALIBRE_WORKER'] = '1' @@ -189,21 +191,21 @@ class WorkerMother(object): if hasattr(self, 'env'): env.update(self.env) return env - + def spawn_free_spirit_osx(self, arg, type='free_spirit'): script = 'from calibre.parallel import main; main(args=["calibre-parallel", %s]);'%repr(arg) cmdline = [self.executable, '-c', self.prefix+script] child = WorkerStatus(subprocess.Popen(cmdline, env=self.get_env())) atexit.register(self.cleanup_child_linux, child) return child - + def spawn_free_spirit_linux(self, arg, type='free_spirit'): cmdline = [self.executable, arg] - child = WorkerStatus(subprocess.Popen(cmdline, + child = WorkerStatus(subprocess.Popen(cmdline, env=self.get_env(), cwd=getattr(sys, 'frozen_path', None))) atexit.register(self.cleanup_child_linux, child) - return child - + return child + def spawn_free_spirit_windows(self, arg, type='free_spirit'): fd, name = tempfile.mkstemp('.log', 'calibre_'+type+'_') handle = msvcrt.get_osfhandle(fd) @@ -226,9 +228,9 @@ class WorkerMother(object): child = WorkerStatus(hProcess) atexit.register(self.cleanup_child_windows, child, name, fd) return child - - -mother = WorkerMother() + + +mother = WorkerMother() _comm_lock = RLock() def write(socket, msg, timeout=5): @@ -236,14 +238,14 @@ def write(socket, msg, timeout=5): Write a message on socket. If `msg` is unicode, it is encoded in utf-8. Raises a `RuntimeError` if the socket is not ready for writing or the writing fails. `msg` is broken into chunks of size 4096 and sent. The :function:`read` function - automatically re-assembles the chunks into whole message. + automatically re-assembles the chunks into whole message. ''' if isworker: _comm_lock.acquire() try: if isinstance(msg, unicode): msg = msg.encode('utf-8') - if DEBUG: + if DEBUG: print >>sys.__stdout__, 'write(%s):'%('worker' if isworker else 'overseer'), repr(msg) length = None while len(msg) > 0: @@ -260,12 +262,12 @@ def write(socket, msg, timeout=5): raise RuntimeError('Failed to write chunk to socket') finally: if isworker: - _comm_lock.release() - + _comm_lock.release() + def read(socket, timeout=5): ''' Read a message from `socket`. The message must have been sent with the :function:`write` - function. Raises a `RuntimeError` if the message is corrpted. Can return an + function. Raises a `RuntimeError` if the message is corrpted. Can return an empty string. ''' if isworker: @@ -298,25 +300,25 @@ def read(socket, timeout=5): class RepeatingTimer(Thread): ''' - Calls a specified function repeatedly at a specified interval. Runs in a + Calls a specified function repeatedly at a specified interval. Runs in a daemon thread (i.e. the interpreter can exit while it is still running). - Call :meth:`start()` to start it. + Call :meth:`start()` to start it. ''' - + def repeat(self): while True: self.event.wait(self.interval) if self.event.isSet(): break self.action() - + def __init__(self, interval, func, name): self.event = Event() self.interval = interval - self.action = func + self.action = func Thread.__init__(self, target=self.repeat, name=name) self.setDaemon(True) - + class ControlError(Exception): pass @@ -325,10 +327,10 @@ class Overseer(object): Responsible for controlling worker processes. The main interface is the methods, :meth:`initialize_job`, :meth:`control`. ''' - + KILL_RESULT = 'Server: job killed by user|||#@#$%&*)*(*$#$%#$@&' INTERVAL = 0.1 - + def __init__(self, server, port, timeout=5): self.worker_status = mother.spawn_worker('127.0.0.1:'+str(port)) self.socket = server.accept()[0] @@ -337,7 +339,7 @@ class Overseer(object): self.signal = signal self.on_probation = False self.terminated = False - + self.working = False self.timeout = timeout self.last_job_time = time.time() @@ -345,14 +347,14 @@ class Overseer(object): self._stop = False if not select([self.socket], [], [], 120)[0]: raise RuntimeError(_('Could not launch worker process.')) - ID = self.read().split(':') + ID = self.read().split(':') if ID[0] != 'CALIBRE_WORKER': raise RuntimeError('Impostor') self.worker_pid = int(ID[1]) self.write('OK') if self.read() != 'WAITING': raise RuntimeError('Worker sulking') - + def terminate(self): 'Kill worker process.' self.terminated = True @@ -379,31 +381,31 @@ class Overseer(object): self.worker_status.kill() except: pass - - + + def write(self, msg, timeout=None): write(self.socket, msg, timeout=self.timeout if timeout is None else timeout) - + def read(self, timeout=None): return read(self.socket, timeout=self.timeout if timeout is None else timeout) - + def __eq__(self, other): return hasattr(other, 'process') and hasattr(other, 'worker_pid') and self.worker_pid == other.worker_pid - + def is_viable(self): if self.terminated: return False return self.worker_status.is_alive() - + def select(self, timeout=0): return select([self.socket], [self.socket], [self.socket], timeout) - + def initialize_job(self, job): ''' Sends `job` to worker process. Can raise `ControlError` if worker process does not respond appropriately. In this case, this Overseer is useless and should be discarded. - + `job`: An instance of :class:`Job`. ''' self.job_id = job.job_id @@ -416,13 +418,13 @@ class Overseer(object): self.progress = job.progress if callable(job.progress) else None self.job = job self.last_report = time.time() - + def control(self): ''' Listens for messages from the worker process and dispatches them appropriately. If the worker process dies unexpectedly, returns a result of None with a ControlError indicating the worker died. - + Returns a :class:`Result` instance or None, if the worker is still working. ''' if select([self.socket],[],[],0)[0]: @@ -468,10 +470,10 @@ class Overseer(object): if not self.worker_status.is_alive() or time.time() - self.last_report > 180: self.terminate() return Result(None, ControlError('Worker process died unexpectedly with returncode: %s'%str(self.process.returncode)), '') - - + + class Job(object): - + def __init__(self, job_id, func, args, kwdargs, output, progress, done): self.job_id = job_id self.func = func @@ -480,20 +482,20 @@ class Job(object): self.output = output self.progress = progress self.done = done - + class Result(object): - + def __init__(self, result, exception, traceback): self.result = result self.exception = exception self.traceback = traceback - + def __len__(self): return 3 - + def __item__(self, i): return (self.result, self.exception, self.traceback)[i] - + def __iter__(self): return iter((self.result, self.exception, self.traceback)) @@ -503,12 +505,12 @@ def remove_ipc_socket(path): os.unlink(path) class Server(Thread): - + KILL_RESULT = Overseer.KILL_RESULT START_PORT = 10013 PID = os.getpid() - - + + def __init__(self, number_of_workers=detect_ncpus()): Thread.__init__(self) self.setDaemon(True) @@ -524,7 +526,7 @@ class Server(Thread): if not iswindows: atexit.register(remove_ipc_socket, self.port) self.server_socket.listen(5) - self.number_of_workers = number_of_workers + self.number_of_workers = number_of_workers self.pool, self.jobs, self.working, self.results = [], collections.deque(), [], {} atexit.register(self.killall) atexit.register(self.close) @@ -534,26 +536,26 @@ class Server(Thread): self.result_lock = RLock() self.pool_lock = RLock() self.start() - + def close(self): try: self.server_socket.shutdown(socket.SHUT_RDWR) except: pass - + def add_job(self, job): with self.job_lock: self.jobs.append(job) - + def store_result(self, result, id=None): if id: with self.job_lock: self.results[id] = result - + def result(self, id): with self.result_lock: return self.results.pop(id, None) - + def run(self): while True: job = None @@ -581,7 +583,7 @@ class Server(Thread): if o and o.is_viable(): with self.working_lock: self.working.append(o) - + with self.working_lock: done = [] for o in self.working: @@ -598,19 +600,19 @@ class Server(Thread): if o and o.is_viable(): with self.pool_lock: self.pool.append(o) - + try: time.sleep(1) except: - return - - + return + + def killall(self): with self.pool_lock: map(lambda x: x.terminate(), self.pool) self.pool = [] - - + + def kill(self, job_id): with self.working_lock: pop = None @@ -622,13 +624,13 @@ class Server(Thread): break if pop is not None: self.working.remove(pop) - - - - def run_job(self, job_id, func, args=[], kwdargs={}, + + + + def run_job(self, job_id, func, args=[], kwdargs={}, output=None, progress=None, done=None): ''' - Run a job in a separate process. Supports job control, output redirection + Run a job in a separate process. Supports job control, output redirection and progress reporting. ''' if done is None: @@ -636,20 +638,20 @@ class Server(Thread): job = Job(job_id, func, args, kwdargs, output, progress, done) with self.job_lock: self.jobs.append(job) - + def run_free_job(self, func, args=[], kwdargs={}): pt = PersistentTemporaryFile('.pickle', '_IPC_') pt.write(cPickle.dumps((func, args, kwdargs))) pt.close() mother.spawn_free_spirit(binascii.hexlify(pt.name)) - + ########################################################################################## ##################################### CLIENT CODE ##################################### ########################################################################################## class BufferedSender(object): - + def __init__(self, socket): self.socket = socket self.wbuf, self.pbuf = [], [] @@ -657,14 +659,14 @@ class BufferedSender(object): self.last_report = None self.timer = RepeatingTimer(0.5, self.send, 'BufferedSender') self.timer.start() - - + + def write(self, msg): if not isinstance(msg, basestring): msg = unicode(msg) with self.wlock: self.wbuf.append(msg) - + def send(self): if callable(select) and select([self.socket], [], [], 0)[0]: msg = read(self.socket) @@ -687,7 +689,7 @@ class BufferedSender(object): write(self.socket, 'OUTPUT:'+msg) read(self.socket, 10) reported = True - + with self.plock: if self.pbuf: msg = cPickle.dumps(self.pbuf, -1) @@ -703,11 +705,11 @@ class BufferedSender(object): write(self.socket, 'PING:') read(self.socket, 10) self.last_report = time.time() - + def notify(self, percent, msg=''): with self.plock: self.pbuf.append((percent, msg)) - + def flush(self): pass @@ -725,13 +727,13 @@ def work(client_socket, func, args, kwdargs): kargs[notification] = sys.stdout.notify kargs.update(kwdargs) res = func(*args, **kargs) - if hasattr(sys.stdout, 'send'): + if hasattr(sys.stdout, 'send'): sys.stdout.send() return res finally: sys.stdout.last_report = None time.sleep(5) # Give any in progress BufferedSend time to complete - + def worker(host, port): client_socket = socket.socket(SOCKET_TYPE, socket.SOCK_STREAM) @@ -742,10 +744,10 @@ def worker(host, port): if msg != 'OK': return 1 write(client_socket, 'WAITING') - + sys.stdout = BufferedSender(client_socket) sys.stderr = sys.stdout - + while True: if not select([client_socket], [], [], 60)[0]: time.sleep(1) @@ -766,7 +768,7 @@ def worker(host, port): break gc.collect() elif msg == 'PING:': - write(client_socket, 'OK') + write(client_socket, 'OK') elif msg == 'STOP:': client_socket.shutdown(socket.SHUT_RDWR) return 0 @@ -775,7 +777,7 @@ def worker(host, port): else: print >>sys.__stderr__, 'Invalid protocols message', msg return 1 - + def free_spirit(path): func, args, kwdargs = cPickle.load(open(path, 'rb')) try: @@ -785,7 +787,7 @@ def free_spirit(path): func, kargs = get_func(func)[:2] kargs.update(kwdargs) func(*args, **kargs) - + def main(args=sys.argv): global isworker isworker = True @@ -793,9 +795,9 @@ def main(args=sys.argv): if len(args) == 1: free_spirit(binascii.unhexlify(re.sub(r'[^a-f0-9A-F]', '', args[0]))) else: - worker(args[0].replace("'", ''), int(args[1]) if iswindows else args[1]) + worker(args[0].replace("'", ''), int(args[1]) if iswindows else args[1]) return 0 if __name__ == '__main__': sys.exit(main()) - + diff --git a/upload.py b/upload.py index 6a9f22807b..79a8c55738 100644 --- a/upload.py +++ b/upload.py @@ -12,7 +12,7 @@ def get_ip_address(ifname): 0x8915, # SIOCGIFADDR struct.pack('256s', ifname[:15]) )[20:24]) - + HOST=get_ip_address('eth0') PROJECT=os.path.basename(os.getcwd()) @@ -34,7 +34,7 @@ mkdir -p build dist src/calibre/plugins && \ %%s && \ rm -rf build/* && \ %%s %%s -'''%dict(host=HOST, project=PROJECT) +'''%dict(host=HOST, project=PROJECT) check_call = partial(_check_call, shell=True) #h = Host(hostType=VIX_SERVICEPROVIDER_VMWARE_WORKSTATION) @@ -43,7 +43,7 @@ def tag_release(): print 'Tagging release' check_call('bzr tag '+__version__) check_call('bzr commit --unchanged -m "IGN:Tag release"') - + def installer_name(ext): if ext in ('exe', 'dmg'): return 'dist/%s-%s.%s'%(__appname__, __version__, ext) @@ -87,7 +87,7 @@ def build_windows(shutdown=True): def build_osx(shutdown=True): installer = installer_name('dmg') vm = '/vmware/Mac OSX/Mac OSX.vmx' - python = '/Library/Frameworks/Python.framework/Versions/Current/bin/python' + python = '/Library/Frameworks/Python.framework/Versions/Current/bin/python' start_vm(vm, 'osx', (BUILD_SCRIPT%('sudo %s setup.py develop'%python, python, 'installer/osx/freeze.py')).replace('rm ', 'sudo rm ')) subprocess.check_call(('scp', 'osx:build/%s/dist/*.dmg'%PROJECT, 'dist')) if not os.path.exists(installer): @@ -95,7 +95,7 @@ def build_osx(shutdown=True): if shutdown: subprocess.Popen(('ssh', 'osx', 'sudo', '/sbin/shutdown', '-h', 'now')) return os.path.basename(installer) - + def build_linux(shutdown=True): installer = installer_name('tar.bz2') @@ -146,7 +146,7 @@ def curl_delete_file(path, url=MOBILEREAD): c.setopt(c.QUOTE, ['dele '+ path]) c.perform() c.close() - + def curl_upload_file(stream, url): c = pycurl.Curl() @@ -173,9 +173,9 @@ def curl_upload_file(stream, url): stream.seek(0,2) if size != stream.tell(): raise RuntimeError('curl failed to upload %s correctly'%getattr(stream, 'name', '')) - - - + + + def upload_installer(name): if not os.path.exists(name): return @@ -189,17 +189,19 @@ def upload_installer(name): def upload_installers(): for i in ('dmg', 'exe', 'tar.bz2'): upload_installer(installer_name(i)) - + check_call('''ssh divok echo %s \\> %s/latest_version'''%(__version__, DOWNLOADS)) - - + + def upload_docs(): + os.environ['PYTHONPATH'] = os.path.abspath('src') check_call('''epydoc --config epydoc.conf''') check_call('''scp -r docs/html divok:%s/'''%(DOCS,)) check_call('''epydoc -v --config epydoc-pdf.conf''') check_call('''scp docs/pdf/api.pdf divok:%s/'''%(DOCS,)) def upload_user_manual(): + os.environ['PYTHONPATH'] = os.path.abspath('src') cwd = os.getcwdu() os.chdir('src/calibre/manual') try: @@ -208,25 +210,24 @@ def upload_user_manual(): check_call('scp -r .build/html/* divok:%s'%USER_MANUAL) finally: os.chdir(cwd) - + def build_src_tarball(): check_call('bzr export dist/calibre-%s.tar.bz2'%__version__) - + def upload_src_tarball(): check_call('ssh divok rm -f %s/calibre-\*.tar.bz2'%DOWNLOADS) check_call('scp dist/calibre-*.tar.bz2 divok:%s/'%DOWNLOADS) def stage_one(): - shutil.rmtree('build') + check_call('sudo rm -rf build', shell=True) os.mkdir('build') shutil.rmtree('docs') os.mkdir('docs') - check_call(['python', 'setup.py', 'build']) - check_call('sudo rm -f src/%s/gui2/images_rc.pyc'%__appname__, shell=True) + check_call('python setup.py mydevelop', shell=True) check_call('make', shell=True) tag_release() upload_demo() - + def stage_two(): subprocess.check_call('rm -rf dist/*', shell=True) build_installers() @@ -250,8 +251,8 @@ def main(args=sys.argv): print 'Starting stage three...' stage_three() print 'Finished' - return 0 - - + return 0 + + if __name__ == '__main__': sys.exit(main())