forked from buildbot/buildbot
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* ticket820: add docs for potential encoding problems tweaks to contrib script Get fix_changes_pickle_encoding script working and tested...sort of Improve exception on unicode decode failure Raise an exception if the db can't store unicode data formatting Test regular ascii data Test that trying to import non-utf8 data will raise exceptions Make remove_none return u"" for None, and not replace data Reduce length of scheduler name, class_name columns so they fit with Decode strings from change objects as if they're utf-8.
- Loading branch information
Showing
9 changed files
with
256 additions
and
23 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
123 changes: 123 additions & 0 deletions
123
buildbot/test/regressions/test_import_unicode_changes.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,123 @@ | ||
import os | ||
import shutil | ||
import cPickle | ||
|
||
from twisted.trial import unittest | ||
|
||
from buildbot.changes.changes import Change | ||
|
||
from buildbot.db.schema import manager | ||
from buildbot.db.dbspec import DBSpec | ||
from buildbot.db.connector import DBConnector | ||
|
||
import buildbot | ||
|
||
class Thing: | ||
def __init__(self, **kwargs): | ||
self.__dict__.update(kwargs) | ||
|
||
|
||
class TestUnicodeChanges(unittest.TestCase): | ||
def setUp(self): | ||
self.basedir = "UnicodeChanges" | ||
if os.path.exists(self.basedir): | ||
shutil.rmtree(self.basedir) | ||
os.makedirs(self.basedir) | ||
|
||
# Now try the upgrade process, which will import the old changes. | ||
self.spec = DBSpec.from_url("sqlite:///state.sqlite", self.basedir) | ||
|
||
self.db = DBConnector(self.spec) | ||
self.db.start() | ||
|
||
def tearDown(self): | ||
if self.db: | ||
self.db.stop() | ||
|
||
def testUnicodeChange(self): | ||
# Create changes.pck | ||
changes = [Change(who=u"Frosty the \N{SNOWMAN}".encode("utf8"), | ||
files=["foo"], comments=u"Frosty the \N{SNOWMAN}".encode("utf8"), | ||
branch="b1", revision=12345)] | ||
cPickle.dump(Thing(changes=changes), open(os.path.join(self.basedir, | ||
"changes.pck"), "w")) | ||
|
||
sm = manager.DBSchemaManager(self.spec, self.basedir) | ||
sm.upgrade() | ||
|
||
c = self.db.getChangeNumberedNow(1) | ||
|
||
self.assertEquals(c.who, u"Frosty the \N{SNOWMAN}") | ||
self.assertEquals(c.comments, u"Frosty the \N{SNOWMAN}") | ||
|
||
def testNonUnicodeChange(self): | ||
# Create changes.pck | ||
changes = [Change(who="\xff\xff\x00", files=["foo"], | ||
comments="\xff\xff\x00", branch="b1", revision=12345)] | ||
cPickle.dump(Thing(changes=changes), open(os.path.join(self.basedir, | ||
"changes.pck"), "w")) | ||
|
||
sm = manager.DBSchemaManager(self.spec, self.basedir) | ||
self.assertRaises(UnicodeError, sm.upgrade) | ||
|
||
def testAsciiChange(self): | ||
# Create changes.pck | ||
changes = [Change(who="Frosty the Snowman", | ||
files=["foo"], comments="Frosty the Snowman", branch="b1", revision=12345)] | ||
cPickle.dump(Thing(changes=changes), open(os.path.join(self.basedir, | ||
"changes.pck"), "w")) | ||
|
||
sm = manager.DBSchemaManager(self.spec, self.basedir) | ||
sm.upgrade() | ||
|
||
c = self.db.getChangeNumberedNow(1) | ||
|
||
self.assertEquals(c.who, "Frosty the Snowman") | ||
self.assertEquals(c.comments, "Frosty the Snowman") | ||
|
||
def testUTF16Change(self): | ||
# Create changes.pck | ||
changes = [Change(who=u"Frosty the \N{SNOWMAN}".encode("utf16"), | ||
files=["foo"], comments=u"Frosty the \N{SNOWMAN}".encode("utf16"), | ||
branch="b1", revision=12345)] | ||
cPickle.dump(Thing(changes=changes), open(os.path.join(self.basedir, | ||
"changes.pck"), "w")) | ||
|
||
# Run fix_changes_pickle_encoding.py | ||
contrib_dir = os.path.join(os.path.dirname(buildbot.__file__), "../contrib") | ||
retval = os.system("python %s/fix_changes_pickle_encoding.py %s utf16" % (contrib_dir, os.path.join(self.basedir, "changes.pck"))) | ||
self.assertEquals(retval, 0) | ||
|
||
sm = manager.DBSchemaManager(self.spec, self.basedir) | ||
sm.upgrade() | ||
|
||
c = self.db.getChangeNumberedNow(1) | ||
|
||
self.assertEquals(c.who, u"Frosty the \N{SNOWMAN}") | ||
self.assertEquals(c.comments, u"Frosty the \N{SNOWMAN}") | ||
|
||
class TestMySQLDBUnicodeChanges(TestUnicodeChanges): | ||
def setUp(self): | ||
self.basedir = "MySQLDBUnicodeChanges" | ||
if os.path.exists(self.basedir): | ||
shutil.rmtree(self.basedir) | ||
os.makedirs(self.basedir) | ||
|
||
# Now try the upgrade process, which will import the old changes. | ||
self.spec = DBSpec.from_url( | ||
"mysql://buildbot_test:buildbot_test@localhost/buildbot_test", self.basedir) | ||
|
||
self.db = DBConnector(self.spec) | ||
self.db.start() | ||
|
||
result = self.db.runQueryNow("SHOW TABLES") | ||
for row in result: | ||
self.db.runQueryNow("DROP TABLE %s" % row[0]) | ||
self.db.runQueryNow("COMMIT") | ||
|
||
try: | ||
import MySQLdb | ||
conn = MySQLdb.connect(user="buildbot_test", db="buildbot_test", | ||
passwd="buildbot_test", use_unicode=True, charset='utf8') | ||
except: | ||
TestMySQLDBUnicodeChanges.skip = True |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
#!/usr/bin/python | ||
"""%prog [options] [changes.pck] old_encoding | ||
Re-encodes changes in a pickle file to UTF-8 from the given encoding | ||
""" | ||
|
||
def recode_changes(changes, old_encoding): | ||
"""Returns a new list of changes, with the change attributes re-encoded | ||
as UTF-8 bytestrings""" | ||
retval = [] | ||
nconvert = 0 | ||
for c in changes: | ||
for attr in ("who", "comments", "revlink", "category", "branch", "revision"): | ||
a = getattr(c, attr) | ||
if isinstance(a, str): | ||
try: | ||
setattr(c, attr, a.decode(old_encoding)) | ||
nconvert += 1 | ||
except UnicodeDecodeError: | ||
raise UnicodeError("Error decoding %s of change #%s as %s:\n%s" % (attr, c.number, old_encoding, a)) | ||
retval.append(c) | ||
print "converted %d strings" % nconvert | ||
return retval | ||
|
||
if __name__ == '__main__': | ||
import sys, os | ||
from cPickle import load, dump | ||
from optparse import OptionParser | ||
|
||
parser = OptionParser(__doc__) | ||
|
||
options, args = parser.parse_args() | ||
|
||
if len(args) == 2: | ||
changes_file = args[0] | ||
old_encoding = args[1] | ||
elif len(args) == 1: | ||
changes_file = "changes.pck" | ||
old_encoding = args[0] | ||
else: | ||
parser.error("Need at least one argument") | ||
|
||
print "opening %s" % (changes_file,) | ||
try: | ||
fp = open(changes_file) | ||
except IOError, e: | ||
parser.error("Couldn't open %s: %s" % (changes_file, str(e))) | ||
|
||
changes = load(fp) | ||
fp.close() | ||
|
||
print "decoding bytestrings in %s using %s" % (changes_file, old_encoding) | ||
changes.changes = recode_changes(changes.changes, old_encoding) | ||
|
||
changes_backup = changes_file + ".old" | ||
i = 0 | ||
while os.path.exists(changes_backup): | ||
i += 1 | ||
changes_backup = changes_file + ".old.%i" % i | ||
|
||
print "backing up %s to %s" % (changes_file, changes_backup) | ||
os.rename(changes_file, changes_backup) | ||
dump(changes, open(changes_file, "w")) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters