Skip to content

Commit

Permalink
A whole raft of str versus bytes issues.
Browse files Browse the repository at this point in the history
  • Loading branch information
Chris Rossi committed Sep 13, 2012
1 parent 533a336 commit 5647daf
Show file tree
Hide file tree
Showing 2 changed files with 91 additions and 65 deletions.
120 changes: 73 additions & 47 deletions acidfs/__init__.py
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import logging import logging
import os import os
import shutil import shutil
import sys
import subprocess import subprocess
import tempfile import tempfile
import traceback import traceback
Expand Down Expand Up @@ -496,9 +497,9 @@ def tpc_finish(self, tx):
# If not updating current head, just write the commit to the ref # If not updating current head, just write the commit to the ref
# file directly. # file directly.
reffile = os.path.join(self.db, 'refs', 'heads', self.head) reffile = os.path.join(self.db, 'refs', 'heads', self.head)
with open(reffile, 'w') as f: with open(reffile, 'wb') as f:
f.write(self.next_commit) f.write(self.next_commit)
f.write('\n') f.write(b'\n')


self.close() self.close()


Expand Down Expand Up @@ -618,33 +619,33 @@ def expect(expectation, *msg):


while line: while line:
if state is None: # default, scanning for start of a change if state is None: # default, scanning for start of a change
if line[0].isalpha(): if isalpha(line[0]):
# If first column is a letter, then we have the first # If first column is a letter, then we have the first
# line of a change, which describes the change. # line of a change, which describes the change.
line = line.strip() line = line.strip()
if line in ('added in local', 'removed in local', if line in (b'added in local', b'removed in local',
'removed in both'): b'removed in both'):
# We don't care about changes to our current tree. # We don't care about changes to our current tree.
# We already know about those. # We already know about those.
pass pass


elif line == 'added in remote': elif line == b'added in remote':
# The head got a new file, we should grab it # The head got a new file, we should grab it
state = _MERGE_ADDED_IN_REMOTE state = _MERGE_ADDED_IN_REMOTE
extra_state = [] extra_state = []


elif line == 'removed in remote': elif line == b'removed in remote':
# File got deleted from head, remove it # File got deleted from head, remove it
state = _MERGE_REMOVED_IN_REMOTE state = _MERGE_REMOVED_IN_REMOTE
extra_state = [] extra_state = []


elif line == 'changed in both': elif line == b'changed in both':
# File was edited in both branches, see if we can # File was edited in both branches, see if we can
# patch # patch
state = _MERGE_CHANGED_IN_BOTH state = _MERGE_CHANGED_IN_BOTH
extra_state = [] extra_state = []


elif line == 'added in both': elif line == b'added in both':
state = _MERGE_ADDED_IN_BOTH state = _MERGE_ADDED_IN_BOTH
extra_state = [] extra_state = []


Expand All @@ -653,39 +654,39 @@ def expect(expectation, *msg):
raise ConflictError() raise ConflictError()


elif state is _MERGE_ADDED_IN_REMOTE: elif state is _MERGE_ADDED_IN_REMOTE:
if line[0].isalpha() or line[0] == '@': if isalpha(line[0]) or line.startswith(b'@'):
# Done collecting tree lines, only expecting one # Done collecting tree lines, only expecting one
expect(len(extra_state) == 1, 'Wrong number of lines') expect(len(extra_state) == 1, 'Wrong number of lines')
whose, mode, oid, path = extra_state[0].split() whose, mode, oid, path = extra_state[0].split()
expect(whose == 'their', 'Unexpected whose: %s', whose) expect(whose == b'their', 'Unexpected whose: %s', whose)
expect(mode == '100644', 'Unexpected mode: %s', mode) expect(mode == b'100644', 'Unexpected mode: %s', mode)
parsed = path.split('/') parsed = path.decode('ascii').split('/')
folder = self.find(parsed[:-1]) folder = self.find(parsed[:-1])
expect(isinstance(folder, _TreeNode), expect(isinstance(folder, _TreeNode),
'Not a folder: %s', path) 'Not a folder: %s', path)
folder.set(parsed[-1], ('blob', oid, None)) folder.set(parsed[-1], (b'blob', oid, None))
state = extra_state = None state = extra_state = None
continue continue


else: else:
extra_state.append(line) extra_state.append(line)


elif state is _MERGE_REMOVED_IN_REMOTE: elif state is _MERGE_REMOVED_IN_REMOTE:
if line[0].isalpha() or line[0] == '@': if isalpha(line[0]) or line.startswith(b'@'):
# Done collecting tree lines, expect two, one for base, # Done collecting tree lines, expect two, one for base,
# one for our copy, whose sha1s should match # one for our copy, whose sha1s should match
expect(len(extra_state) == 2, 'Wrong number of lines') expect(len(extra_state) == 2, 'Wrong number of lines')
whose, mode, oid, path = extra_state[0].split() whose, mode, oid, path = extra_state[0].split()
expect(whose in ('our', 'base'), 'Unexpected whose: %s', expect(whose in (b'our', b'base'),
whose) 'Unexpected whose: %s', whose)
expect(mode == '100644', 'Unexpected mode: %s', mode) expect(mode == b'100644', 'Unexpected mode: %s', mode)
whose, mode, oid2, path2 = extra_state[1].split() whose, mode, oid2, path2 = extra_state[1].split()
expect(whose in ('our', 'base'), 'Unexpected whose: %s', expect(whose in (b'our', b'base'),
whose) 'Unexpected whose: %s', whose)
expect(mode == '100644', 'Unexpected mode: %s', mode) expect(mode == b'100644', 'Unexpected mode: %s', mode)
expect(oid == oid2, "SHA1s don't match") expect(oid == oid2, "SHA1s don't match")
expect(path == path2, "Paths don't match") expect(path == path2, "Paths don't match")
path = path.split('/') path = path.decode('ascii').split('/')
folder = self.find(path[:-1]) folder = self.find(path[:-1])
expect(isinstance(folder, _TreeNode), "Not a folder") expect(isinstance(folder, _TreeNode), "Not a folder")
folder.remove(path[-1]) folder.remove(path[-1])
Expand All @@ -696,22 +697,22 @@ def expect(expectation, *msg):
extra_state.append(line) extra_state.append(line)


elif state is _MERGE_CHANGED_IN_BOTH: elif state is _MERGE_CHANGED_IN_BOTH:
if line[0] == '@': if line.startswith(b'@'):
# Done collecting tree lines, expect three, one for base # Done collecting tree lines, expect three, one for base
# and one for each copy # and one for each copy
expect(len(extra_state) == 3, 'Wrong number of lines') expect(len(extra_state) == 3, 'Wrong number of lines')
whose, mode, oid, path = extra_state[0].split() whose, mode, oid, path = extra_state[0].split()
expect(whose in ('base', 'our', 'their'), expect(whose in (b'base', b'our', b'their'),
'Unexpected whose: %s', whose) 'Unexpected whose: %s', whose)
expect(mode == '100644', 'Unexpected mode: %s', mode) expect(mode == b'100644', 'Unexpected mode: %s', mode)
for extra_line in extra_state[1:]: for extra_line in extra_state[1:]:
whose, mode, oid2, path2 = extra_line.split() whose, mode, oid2, path2 = extra_line.split()
expect(whose in ('base', 'our', 'their'), expect(whose in (b'base', b'our', b'their'),
'Unexpected whose: %s', whose) 'Unexpected whose: %s', whose)
expect(mode == '100644', 'Unexpected mode: %s', expect(mode == b'100644', 'Unexpected mode: %s',
mode) mode)
expect(path == path2, "Paths don't match") expect(path == path2, "Paths don't match")
parsed = path.split('/') parsed = path.decode('ascii').split('/')
folder = self.find(parsed[:-1]) folder = self.find(parsed[:-1])
expect(isinstance(folder, _TreeNode), "Not a folder") expect(isinstance(folder, _TreeNode), "Not a folder")
name = parsed[-1] name = parsed[-1]
Expand All @@ -724,8 +725,8 @@ def expect(expectation, *msg):
stdout=subprocess.PIPE, stdout=subprocess.PIPE,
stderr=subprocess.PIPE) as p: stderr=subprocess.PIPE) as p:
f = p.stdin f = p.stdin
while line and not line[0].isalpha(): while line and not isalpha(line[0]):
if line[1:9] == '<<<<<<< ': if line[1:9] == b'<<<<<<< ':
raise ConflictError() raise ConflictError()
f.write(line) f.write(line)
line = stream.readline() line = stream.readline()
Expand All @@ -739,18 +740,18 @@ def expect(expectation, *msg):
extra_state.append(line) extra_state.append(line)


elif state is _MERGE_ADDED_IN_BOTH: elif state is _MERGE_ADDED_IN_BOTH:
if line[0].isalpha() or line[0] == '@': if isalpha(line[0]) or line.startswith(b'@'):
# Done collecting tree lines, expect two, one for base, # Done collecting tree lines, expect two, one for base,
# one for our copy, whose sha1s should match # one for our copy, whose sha1s should match
expect(len(extra_state) == 2, 'Wrong number of lines') expect(len(extra_state) == 2, 'Wrong number of lines')
whose, mode, oid, path = extra_state[0].split() whose, mode, oid, path = extra_state[0].split()
expect(whose in ('our', 'their'), 'Unexpected whose: %s', expect(whose in (b'our', b'their'), 'Unexpected whose: %s',
whose) whose)
expect(mode == '100644', 'Unexpected mode: %s', mode) expect(mode == b'100644', 'Unexpected mode: %s', mode)
whose, mode, oid2, path2 = extra_state[1].split() whose, mode, oid2, path2 = extra_state[1].split()
expect(whose in ('our', 'their'), 'Unexpected whose: %s', expect(whose in (b'our', b'their'),
whose) 'Unexpected whose: %s', whose)
expect(mode == '100644', 'Unexpected mode: %s', mode) expect(mode == b'100644', 'Unexpected mode: %s', mode)
expect(path == path2, "Paths don't match") expect(path == path2, "Paths don't match")
# Either it's the same file or a different file. # Either it's the same file or a different file.
if oid != oid2: if oid != oid2:
Expand Down Expand Up @@ -779,6 +780,8 @@ def read(cls, db, oid):
stdout=subprocess.PIPE, cwd=db) as lstree: stdout=subprocess.PIPE, cwd=db) as lstree:
for line in lstree.stdout.readlines(): for line in lstree.stdout.readlines():
mode, type, oid, name = line.split() mode, type, oid, name = line.split()
name = str(name, 'ascii')
oid = str(oid, 'ascii')
contents[name] = (type, oid, None) contents[name] = (type, oid, None)


return node return node
Expand All @@ -793,9 +796,9 @@ def get(self, name):
if not obj: if not obj:
return None return None
type, oid, obj = obj type, oid, obj = obj
assert type in ('tree', 'blob') assert type in (b'tree', b'blob')
if not obj: if not obj:
if type == 'tree': if type == b'tree':
obj = _TreeNode.read(self.db, oid) obj = _TreeNode.read(self.db, oid)
else: else:
obj = _Blob(self.db, oid) obj = _Blob(self.db, oid)
Expand All @@ -815,15 +818,15 @@ def new_blob(self, name, prev):
obj = _NewBlob(self.db, prev) obj = _NewBlob(self.db, prev)
obj.parent = self obj.parent = self
obj.name = name obj.name = name
self.contents[name] = ('blob', None, weakref.proxy(obj)) self.contents[name] = (b'blob', None, weakref.proxy(obj))
self.set_dirty() self.set_dirty()
return obj return obj


def new_tree(self, name): def new_tree(self, name):
node = _TreeNode(self.db) node = _TreeNode(self.db)
node.parent = self node.parent = self
node.name = name node.name = name
self.contents[name] = ('tree', None, node) self.contents[name] = (b'tree', None, node)
self.set_dirty() self.set_dirty()
return node return node


Expand All @@ -849,17 +852,22 @@ def save(self):
continue # Nothing to do continue # Nothing to do
if isinstance(obj, _NewBlob): if isinstance(obj, _NewBlob):
raise ValueError("Cannot commit transaction with open files.") raise ValueError("Cannot commit transaction with open files.")
elif type == 'tree' and (obj.dirty or not oid): elif type == b'tree' and (obj.dirty or not oid):
new_oid = obj.save() new_oid = obj.save()
self.contents[name] = ('tree', new_oid, None) self.contents[name] = (b'tree', new_oid, None)


# Save tree object out to database # Save tree object out to database
with _popen(['git', 'mktree'], cwd=self.db, with _popen(['git', 'mktree'], cwd=self.db,
stdin=subprocess.PIPE, stdout=subprocess.PIPE) as proc: stdin=subprocess.PIPE, stdout=subprocess.PIPE) as proc:
for name, (type, oid, obj) in self.contents.items(): for name, (type, oid, obj) in self.contents.items():
mode = '100644' if type == 'blob' else '040000' proc.stdin.write(b'100644' if type == b'blob' else b'040000')
proc.stdin.write('%s %s %s\t%s' % (mode, type, oid, name)) proc.stdin.write(b' ')
proc.stdin.write('\n') proc.stdin.write(type)
proc.stdin.write(b' ')
proc.stdin.write(b(oid))
proc.stdin.write(b'\t')
proc.stdin.write(b(name))
proc.stdin.write(b'\n')
proc.stdin.close() proc.stdin.close()
oid = proc.stdout.read().strip() oid = proc.stdout.read().strip()
return oid return oid
Expand Down Expand Up @@ -909,7 +917,7 @@ def close(self):
if retcode != 0: if retcode != 0:
raise subprocess.CalledProcessError( raise subprocess.CalledProcessError(
retcode, 'git hash-object -w --stdin') retcode, 'git hash-object -w --stdin')
self.parent.contents[self.name] = ('blob', oid, None) self.parent.contents[self.name] = (b'blob', oid, None)


def writable(self): def writable(self):
return True return True
Expand Down Expand Up @@ -965,7 +973,10 @@ def _popen(args, **kw):
yield proc yield proc
for stream in (proc.stdin, proc.stdout, proc.stderr): for stream in (proc.stdin, proc.stdout, proc.stderr):
if stream is not None: if stream is not None:
stream.close() if not stream.closed:
if stream.readable():
stream.read()
stream.close()
retcode = proc.wait() retcode = proc.wait()
if retcode != 0: if retcode != 0:
raise subprocess.CalledProcessError(retcode, repr(args)) raise subprocess.CalledProcessError(retcode, repr(args))
Expand Down Expand Up @@ -1024,3 +1035,18 @@ def _check_output(*popenargs, **kwargs):
cmd = popenargs[0] cmd = popenargs[0]
raise subprocess.CalledProcessError(retcode, cmd, output=output) raise subprocess.CalledProcessError(retcode, cmd, output=output)
return output return output


if sys.version_info[0] == 2:
b = lambda s: s
isalpha = lambda s: s.isalpha()
else:
def b(s):
if isinstance(s, str):
s = bytes(s, 'ascii')
return s

aa, zz, AA, ZZ = ord('a'), ord('z'), ord('A'), ord('Z')
def isalpha(b):
return aa <= b <= zz or AA <= b <= ZZ

Loading

0 comments on commit 5647daf

Please sign in to comment.