Skip to content

Instantly share code, notes, and snippets.

@washort

washort/files.py Secret

Created March 27, 2018 03:28
Show Gist options
  • Save washort/48c109e843b0411d5d64de7d788a534c to your computer and use it in GitHub Desktop.
Save washort/48c109e843b0411d5d64de7d788a534c to your computer and use it in GitHub Desktop.
import os
from rpython.rlib.objectmodel import specialize
from rpython.rlib.rarithmetic import intmask
from rpython.rtyper.lltypesystem.lltype import scoped_alloc
from rpython.rtyper.lltypesystem.rffi import charpsize2str
from typhon import log, rsodium, ruv
from typhon.atoms import getAtom
from typhon.autohelp import autohelp, method
from typhon.errors import userError
from typhon.futures import FutureCtx, FutureCallback, resolve, Ok, Err, Break, Continue, LOOP_BREAK, LOOP_CONTINUE
from typhon.macros import macros
from typhon.objects.constants import NullObject
from typhon.objects.data import BytesObject, StrObject, unwrapStr
from typhon.objects.refs import LocalResolver, makePromise
from typhon.objects.root import Object, runnable
from typhon.vats import currentVat, scopedVat
ABORTFLOW_0 = getAtom(u'abortFlow', 0)
FLOWABORTED_1 = getAtom(u'flowAborted', 1)
FLOWSTOPPED_1 = getAtom(u'flowStopped', 1)
RECEIVE_1 = getAtom(u'receive', 1)
RUN_1 = getAtom(u'run', 1)
@autohelp
class FileUnpauser(Object):
'\n A pause on a file fount.\n '
def __init__(self, fount):
self.fount = fount
@method('Void')
def unpause(self):
if (self.fount is not None):
self.fount.unpause()
self.fount = None
def renameCB(fs):
try:
success = intmask(fs.c_result)
(vat, r) = ruv.unstashFS(fs)
if (success < 0):
msg = ruv.formatError(success).decode('utf-8')
r.smash(StrObject((u"Couldn't rename file: %s" % msg)))
else:
r.resolve(NullObject)
ruv.fsDiscard(fs)
except:
print 'Exception in renameCB'
class SetContents(Object):
pos = 0
def __init__(self, vat, data, resolver, src, dest):
self.vat = vat
self.data = data
self.resolver = resolver
self.src = src
self.dest = dest
def fail(self, reason):
self.resolver.smash(StrObject(reason))
def queueWrite(self):
fs = ruv.alloc_fs()
sb = ruv.scopedBufs([self.data], self)
bufs = sb.allocate()
ruv.stashFS(fs, (self.vat, sb))
ruv.fsWrite(self.vat.uv_loop, fs, self.fd, bufs, 1, (-1), writeSetContentsCB)
def startWriting(self, fd):
self.fd = fd
self.queueWrite()
def written(self, size):
self.pos += size
self.data = self.data[size:]
if self.data:
self.queueWrite()
else:
fs = ruv.alloc_fs()
ruv.stashFS(fs, (self.vat, self))
ruv.fsClose(self.vat.uv_loop, fs, self.fd, closeSetContentsCB)
def rename(self):
p = self.src.rename(self.dest.asBytes())
self.resolver.resolve(p)
def openSetContentsCB(fs):
try:
fd = intmask(fs.c_result)
(vat, sc) = ruv.unstashFS(fs)
assert isinstance(sc, SetContents)
if (fd < 0):
msg = ruv.formatError(fd).decode('utf-8')
sc.fail((u"Couldn't open file fount: %s" % msg))
else:
sc.startWriting(fd)
ruv.fsDiscard(fs)
except:
print 'Exception in openSetContentsCB'
def writeSetContentsCB(fs):
try:
(vat, sb) = ruv.unstashFS(fs)
sc = sb.obj
assert isinstance(sc, SetContents)
size = intmask(fs.c_result)
if (size >= 0):
sc.written(size)
else:
msg = ruv.formatError(size).decode('utf-8')
sc.fail((u'libuv error: %s' % msg))
ruv.fsDiscard(fs)
sb.deallocate()
except:
print 'Exception in writeSetContentsCB'
def closeSetContentsCB(fs):
try:
(vat, sc) = ruv.unstashFS(fs)
with scopedVat(vat):
assert isinstance(sc, SetContents)
size = intmask(fs.c_result)
if (size < 0):
msg = ruv.formatError(size).decode('utf-8')
sc.fail((u'libuv error: %s' % msg))
else:
sc.rename()
ruv.fsDiscard(fs)
except:
print 'Exception in closeSetContentsCB'
def readLoopCore(state, data):
if (data == ''):
return Break(''.join(state.pieces))
else:
state.pieces.append(data)
state.pos += len(data)
return Continue()
class _State1(FutureCtx):
def __init__(_1, vat, future, buf, pieces, pos, outerState, k):
_1.vat = vat
_1.future = future
_1.buf = buf
_1.pieces = pieces
_1.pos = pos
_1.outerState = outerState
_1.k = k
class ReadLoop_K0(ruv.FSReadFutureCallback):
def do(self, state, result):
(inStatus, data, inErr) = result
(status, output, err) = readLoopCore(state, data)
if (status == LOOP_CONTINUE):
state.future.run(state, readLoop_k0)
elif (status == LOOP_BREAK):
state.k.do(state.outerState, Ok(output))
else:
raise ValueError(status)
readLoop_k0 = ReadLoop_K0()
class readLoop(ruv.FSReadFutureCallback):
callbackType = ruv.FSReadFutureCallback
def __init__(self, f, buf):
self.f = f
self.buf = buf
def run(self, state, k):
ruv.magic_fsRead(state.vat, self.f, self.buf).run(_State1(state.vat, self, self.buf, [], 0, state, k), readLoop_k0)
@autohelp
class FileResource(Object):
'\n A Resource which provides access to the file system of the current\n process.\n '
_immutable_fields_ = ('segments[*]',)
def __init__(self, segments):
self.segments = segments
def toString(self):
return (u'<file resource %s>' % self.asBytes().decode('utf-8'))
def asBytes(self):
return '/'.join(self.segments)
def rename(self, dest):
(p, r) = makePromise()
vat = currentVat.get()
uv_loop = vat.uv_loop
fs = ruv.alloc_fs()
src = self.asBytes()
ruv.stashFS(fs, (vat, r))
ruv.fsRename(uv_loop, fs, src, dest, renameCB)
return p
def sibling(self, segment):
return FileResource((self.segments[:(-1)] + [segment]))
def temporarySibling(self, suffix):
fileName = (rsodium.randomHex() + suffix)
return self.sibling(fileName)
@method('Any')
def getContents(self):
(p, r) = makePromise()
vat = currentVat.get()
buf = ruv.allocBuf(16384)
path = self.asBytes()
log.log(['fs'], (u"makeFileResource: Opening file '%s'" % path.decode('utf-8')))
iostart_callback.do(State(vat, path, buf, r), (Ok1, None, None))
return p
@method('Any', 'Bytes')
def setContents(self, data):
sibling = self.temporarySibling('.setContents')
(p, r) = makePromise()
vat = currentVat.get()
uv_loop = vat.uv_loop
fs = ruv.alloc_fs()
path = sibling.asBytes()
flags = ((os.O_WRONLY | os.O_CREAT) | os.O_EXCL)
sc = SetContents(vat, data, r, sibling, self)
ruv.stashFS(fs, (vat, sc))
ruv.fsOpen(uv_loop, fs, path, flags, 511, openSetContentsCB)
return p
@method('Any', 'Any', _verb='rename')
def _rename(self, fr):
if (not isinstance(fr, FileResource)):
raise userError(u'rename/1: Must be file resource')
return self.rename(fr.asBytes())
@method('Any', 'Str', _verb='sibling')
def _sibling(self, name):
if (u'/' in name):
raise userError((u"sibling/1: Illegal file name '%s'" % name))
return self.sibling(name.encode('utf-8'))
@method('Any', _verb='temporarySibling')
def _temporarySibling(self):
return self.temporarySibling('.new')
@runnable(RUN_1)
def makeFileResource(path):
'\n Make a file Resource.\n '
path = unwrapStr(path)
segments = [segment.encode('utf-8') for segment in path.split(u'/')]
if (not path.startswith(u'/')):
segments = (os.getcwd().split('/') + segments)
log.log(['fs'], (u"makeFileResource.run/1: Relative path '%s'" % path))
return FileResource(segments)
from typhon.futures import FutureCtx as FutureCtx1, Ok as Ok1, Err as Err1
class iostart_callback_Class(object):
def do(self1, state1, result1):
ruv.magic_fsOpen(state1.vat, state1.path, os.O_RDONLY, 0).run(state1, io1)
iostart_callback = iostart_callback_Class()
class io1_Class(ruv.magic_fsOpen.callbackType):
def do(self2, state2, result2):
(status1, f, err1) = result2
state2.f = f
readLoop(state2.f, state2.buf).run(state2, readLoop1)
io1 = io1_Class()
class readLoop1_Class(readLoop.callbackType):
def do(self3, state3, result3):
(status2, contents, err2) = result3
state3.contents = contents
ruv.magic_fsClose(state3.vat, state3.f).run(state3, io2)
readLoop1 = readLoop1_Class()
class io2_Class(ruv.magic_fsClose.callbackType):
def do(self4, state4, result4):
resolve(state4.r, BytesObject(state4.contents)).run(state4, None)
io2 = io2_Class()
class State(FutureCtx1):
def __init__(self4, vat, path, buf, r):
self4.vat = vat
self4.path = path
self4.buf = buf
self4.r = r
self4.f = 0
self4.contents = None
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment