centralize all tmp dir access

This commit is contained in:
Damien Elmes 2011-04-17 01:07:05 +09:00
parent d96a0eaf08
commit 344b111b80
5 changed files with 72 additions and 44 deletions

View file

@ -2,8 +2,8 @@
# Copyright: Damien Elmes <anki@ichi2.net> # Copyright: Damien Elmes <anki@ichi2.net>
# License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html # License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
import re, tempfile, os, sys, shutil, cgi, subprocess import re, os, sys, shutil, cgi, subprocess
from anki.utils import checksum, call from anki.utils import checksum, call, namedtmp, tmpdir, isMac
from anki.hooks import addHook from anki.hooks import addHook
from htmlentitydefs import entitydefs from htmlentitydefs import entitydefs
from anki.lang import _ from anki.lang import _
@ -17,10 +17,8 @@ regexps = {
"math": re.compile(r"\[\$\$\](.+?)\[/\$\$\]", re.DOTALL | re.IGNORECASE), "math": re.compile(r"\[\$\$\](.+?)\[/\$\$\]", re.DOTALL | re.IGNORECASE),
} }
tmpdir = tempfile.mkdtemp(prefix="anki")
# add standard tex install location to osx # add standard tex install location to osx
if sys.platform == "darwin": if isMac:
os.environ['PATH'] += ":/usr/texbin" os.environ['PATH'] += ":/usr/texbin"
def stripLatex(text): def stripLatex(text):
@ -76,17 +74,17 @@ def _buildImg(deck, latex, fname):
latex + "\n" + latex + "\n" +
deck.conf["latexPost"]) deck.conf["latexPost"])
# write into a temp file # write into a temp file
log = open(os.path.join(tmpdir, "latex_log.txt"), "w+") log = open(namedtmp("latex_log.txt"), "w")
texpath = os.path.join(tmpdir, "tmp.tex") texfile = file(namedtmp("tmp.tex"), "w")
texfile = file(texpath, "w")
texfile.write(latex) texfile.write(latex)
texfile.close() texfile.close()
# make sure we have a valid mediaDir # make sure we have a valid mediaDir
mdir = deck.media.dir(create=True) mdir = deck.media.dir(create=True)
oldcwd = os.getcwd() oldcwd = os.getcwd()
png = namedtmp("tmp.png")
try: try:
# generate dvi # generate dvi
os.chdir(tmpdir) os.chdir(tmpdir())
if call(latexCmd + ["tmp.tex"], stdout=log, stderr=log): if call(latexCmd + ["tmp.tex"], stdout=log, stderr=log):
return _errMsg("latex") return _errMsg("latex")
# and png # and png
@ -94,7 +92,7 @@ def _buildImg(deck, latex, fname):
stdout=log, stderr=log): stdout=log, stderr=log):
return _errMsg("dvipng") return _errMsg("dvipng")
# add to media # add to media
shutil.copy2(os.path.join(tmpdir, "tmp.png"), shutil.copy2(png,
os.path.join(mdir, fname)) os.path.join(mdir, fname))
return return
finally: finally:
@ -103,7 +101,7 @@ def _buildImg(deck, latex, fname):
def _errMsg(type): def _errMsg(type):
msg = (_("Error executing %s.") % type) + "<br>" msg = (_("Error executing %s.") % type) + "<br>"
try: try:
log = open(os.path.join(tmpdir, "latex_log.txt")).read() log = open(namedtmp("latex_log.txt")).read()
if not log: if not log:
raise Exception() raise Exception()
msg += "<small><pre>" + cgi.escape(log) + "</pre></small>" msg += "<small><pre>" + cgi.escape(log) + "</pre></small>"

View file

@ -2,9 +2,9 @@
# Copyright: Damien Elmes <anki@ichi2.net> # Copyright: Damien Elmes <anki@ichi2.net>
# License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html # License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
import os, shutil, re, urllib, urllib2, time, tempfile, unicodedata, \ import os, shutil, re, urllib, urllib2, time, unicodedata, \
urllib, sys urllib, sys
from anki.utils import checksum, intTime from anki.utils import checksum, intTime, namedtmp, isWin
from anki.lang import _ from anki.lang import _
class MediaRegistry(object): class MediaRegistry(object):
@ -111,7 +111,7 @@ If the same name exists, compare checksums."""
# problem is more complicated - if we percent-escape as utf8 it fixes # problem is more complicated - if we percent-escape as utf8 it fixes
# some images but breaks others. When filenames are normalized by # some images but breaks others. When filenames are normalized by
# dropbox they become unreadable if we escape them. # dropbox they become unreadable if we escape them.
if sys.platform.startswith("win32"): if isWin:
return string return string
def repl(match): def repl(match):
tag = match.group(1) tag = match.group(1)
@ -212,12 +212,11 @@ If the same name exists, compare checksums."""
for f in mediaFiles(txt, remote=True): for f in mediaFiles(txt, remote=True):
refs[f] = True refs[f] = True
tmpdir = tempfile.mkdtemp(prefix="anki")
failed = [] failed = []
passed = [] passed = []
for c, link in enumerate(refs.keys()): for c, link in enumerate(refs.keys()):
try: try:
path = os.path.join(tmpdir, os.path.basename(link)) path = namedtmp(os.path.basename(link))
url = urllib2.urlopen(link) url = urllib2.urlopen(link)
open(path, "wb").write(url.read()) open(path, "wb").write(url.read())
newpath = copyToMedia(self.deck, path) newpath = copyToMedia(self.deck, path)

View file

@ -3,8 +3,9 @@
# License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html # License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
import re, sys, threading, time, subprocess, os, signal, errno, atexit import re, sys, threading, time, subprocess, os, signal, errno, atexit
import tempfile, shutil import shutil
from anki.hooks import addHook, runHook from anki.hooks import addHook, runHook
from anki.utils import namedtmp, tmpdir, isWin, isMac
# Shared utils # Shared utils
########################################################################## ##########################################################################
@ -30,23 +31,18 @@ processingChain = [
["lame", "rec.wav", processingDst, "--noreplaygain", "--quiet"], ["lame", "rec.wav", processingDst, "--noreplaygain", "--quiet"],
] ]
tmpdir = None
# don't show box on windows # don't show box on windows
if sys.platform == "win32": if isWin:
si = subprocess.STARTUPINFO() si = subprocess.STARTUPINFO()
try: try:
si.dwFlags |= subprocess.STARTF_USESHOWWINDOW si.dwFlags |= subprocess.STARTF_USESHOWWINDOW
except: except:
# python2.7+ # python2.7+
si.dwFlags |= subprocess._subprocess.STARTF_USESHOWWINDOW si.dwFlags |= subprocess._subprocess.STARTF_USESHOWWINDOW
# tmp dir for non-hashed media
tmpdir = unicode(
tempfile.mkdtemp(prefix="anki"), sys.getfilesystemencoding())
else: else:
si = None si = None
if sys.platform.startswith("darwin"): if isMac:
# make sure lame, which is installed in /usr/local/bin, is in the path # make sure lame, which is installed in /usr/local/bin, is in the path
os.environ['PATH'] += ":" + "/usr/local/bin" os.environ['PATH'] += ":" + "/usr/local/bin"
dir = os.path.dirname(os.path.abspath(__file__)) dir = os.path.dirname(os.path.abspath(__file__))
@ -64,7 +60,7 @@ def retryWait(proc):
# Mplayer settings # Mplayer settings
########################################################################## ##########################################################################
if sys.platform.startswith("win32"): if isWin:
mplayerCmd = ["mplayer.exe", "-ao", "win32"] mplayerCmd = ["mplayer.exe", "-ao", "win32"]
dir = os.path.dirname(os.path.abspath(sys.argv[0])) dir = os.path.dirname(os.path.abspath(sys.argv[0]))
os.environ['PATH'] += ";" + dir os.environ['PATH'] += ";" + dir
@ -157,13 +153,13 @@ def queueMplayer(path):
ensureMplayerThreads() ensureMplayerThreads()
while mplayerEvt.isSet(): while mplayerEvt.isSet():
time.sleep(0.1) time.sleep(0.1)
if tmpdir and os.path.exists(path): if isWin and os.path.exists(path):
# mplayer on windows doesn't like the encoding, so we create a # mplayer on windows doesn't like the encoding, so we create a
# temporary file instead. oddly, foreign characters in the dirname # temporary file instead. oddly, foreign characters in the dirname
# don't seem to matter. # don't seem to matter.
(fd, name) = tempfile.mkstemp(suffix=os.path.splitext(path)[1], dir = tmpdir().encode(sys.getfilesystemencoding())
dir=tmpdir) name = os.path.join(dir, "audio"+os.path.splitext(path)[1])
f = os.fdopen(fd, "wb") f = open(name, "wb")
f.write(open(path, "rb").read()) f.write(open(path, "rb").read())
f.close() f.close()
# it wants unix paths, too! # it wants unix paths, too!
@ -194,12 +190,7 @@ def stopMplayer(*args):
return return
mplayerManager.kill() mplayerManager.kill()
def onExit():
if tmpdir:
shutil.rmtree(tmpdir)
addHook("deckClosed", stopMplayer) addHook("deckClosed", stopMplayer)
atexit.register(onExit)
# PyAudio recording # PyAudio recording
########################################################################## ##########################################################################

View file

@ -3,7 +3,7 @@
# License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html # License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
import zlib, re, urllib, urllib2, socket, simplejson, time, shutil import zlib, re, urllib, urllib2, socket, simplejson, time, shutil
import os, base64, httplib, sys, tempfile, httplib, types import os, base64, httplib, sys, httplib, types
from datetime import date from datetime import date
import anki, anki.deck, anki.cards import anki, anki.deck, anki.cards
from anki.errors import * from anki.errors import *
@ -851,8 +851,8 @@ and cards.id in %s""" % ids2str([c[0] for c in cards])))
try: try:
# write into a temporary file, since POST needs content-length # write into a temporary file, since POST needs content-length
src = open(path, "rb") src = open(path, "rb")
(fd, name) = tempfile.mkstemp(prefix="anki") name = namedtmp("fullsync.anki")
tmp = open(name, "w+b") tmp = open(name, "wb")
# post vars # post vars
for (key, value) in fields.items(): for (key, value) in fields.items():
tmp.write('--' + MIME_BOUNDARY + "\r\n") tmp.write('--' + MIME_BOUNDARY + "\r\n")
@ -900,8 +900,6 @@ and cards.id in %s""" % ids2str([c[0] for c in cards])))
finally: finally:
sendProgressHook = None sendProgressHook = None
tmp.close() tmp.close()
os.close(fd)
os.unlink(name)
finally: finally:
runHook("fullSyncFinished") runHook("fullSyncFinished")
@ -910,8 +908,7 @@ and cards.id in %s""" % ids2str([c[0] for c in cards])))
runHook("fullSyncStarted", 0) runHook("fullSyncStarted", 0)
fields = urllib.urlencode(fields) fields = urllib.urlencode(fields)
src = urllib.urlopen(SYNC_URL + "fulldown", fields) src = urllib.urlopen(SYNC_URL + "fulldown", fields)
(fd, tmpname) = tempfile.mkstemp(dir=os.path.dirname(path), tmpname = namedtmp("fullsync.anki")
prefix="fullsync")
tmp = open(tmpname, "wb") tmp = open(tmpname, "wb")
decomp = zlib.decompressobj() decomp = zlib.decompressobj()
cnt = 0 cnt = 0

View file

@ -2,7 +2,8 @@
# Copyright: Damien Elmes <anki@ichi2.net> # Copyright: Damien Elmes <anki@ichi2.net>
# License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html # License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
import re, os, random, time, types, math, htmlentitydefs, subprocess import re, os, random, time, types, math, htmlentitydefs, subprocess, \
tempfile, shutil
try: try:
import hashlib import hashlib
@ -231,7 +232,7 @@ def joinFields(list):
def splitFields(string): def splitFields(string):
return string.split("\x1f") return string.split("\x1f")
# Misc # Checksums
############################################################################## ##############################################################################
def checksum(data): def checksum(data):
@ -241,10 +242,46 @@ def fieldChecksum(data):
# 32 bit unsigned number from first 8 digits of md5 hash # 32 bit unsigned number from first 8 digits of md5 hash
return int(checksum(data.encode("utf-8"))[:8], 16) return int(checksum(data.encode("utf-8"))[:8], 16)
# Temp files
##############################################################################
_tmpdir = None
def tmpdir():
"A reusable temp folder which we clean out on each program invocation."
global _tmpdir
if not _tmpdir:
def cleanup():
shutil.rmtree(_tmpdir)
import atexit
atexit.register(cleanup)
_tmpdir = os.path.join(tempfile.gettempdir(), "anki_temp")
try:
shutil.rmtree(_tmpdir)
except (IOError, OSError):
pass
os.mkdir(_tmpdir)
return _tmpdir
def tmpfile(prefix=None, suffix=None):
return tempfile.mkstemp(dir=tmpdir(), prefix=prefix, suffix=suffix)
def namedtmp(name):
"Return tmpdir+name. Deletes any existing file."
path = os.path.join(tmpdir(), name)
try:
os.unlink(path)
except (OSError, IOError):
pass
return path
# Cmd invocation
##############################################################################
def call(argv, wait=True, **kwargs): def call(argv, wait=True, **kwargs):
"Execute a command. If WAIT, return exit code." "Execute a command. If WAIT, return exit code."
# ensure we don't open a separate window for forking process on windows # ensure we don't open a separate window for forking process on windows
if sys.platform == "win32": if isWin:
si = subprocess.STARTUPINFO() si = subprocess.STARTUPINFO()
try: try:
si.dwFlags |= subprocess.STARTF_USESHOWWINDOW si.dwFlags |= subprocess.STARTF_USESHOWWINDOW
@ -270,3 +307,9 @@ def call(argv, wait=True, **kwargs):
else: else:
ret = 0 ret = 0
return ret return ret
# OS helpers
##############################################################################
isMac = sys.platform.startswith("darwin")
isWin = sys.platform.startswith("win32")