Merge lp:~gz/bzr-builddeb/nonascii_import_dir_508258 into lp:bzr-builddeb

Proposed by Martin Packman
Status: Merged
Approved by: Jelmer Vernooij
Approved revision: 638
Merged at revision: 637
Proposed branch: lp:~gz/bzr-builddeb/nonascii_import_dir_508258
Merge into: lp:bzr-builddeb
Diff against target: 108 lines (+28/-22)
3 files modified
bzrtools_import.py (+6/-16)
tests/__init__.py (+8/-2)
tests/test_bzrtools_import.py (+14/-4)
To merge this branch: bzr merge lp:~gz/bzr-builddeb/nonascii_import_dir_508258
Reviewer Review Type Date Requested Status
Jelmer Vernooij code Approve
Review via email: mp+80243@code.launchpad.net

Description of the change

This branch should allow the package importer to work with non-ascii filenames from upstream sources. There are a few provisos as this depends on the fix from bug 488519. If the name can't be represented in the filesystem encoding, a (much nicer) error giving the filename and encoding is raised, except on bzr 2.1 which will fail in much the same way as currently.

The package importer is already making an effort to say it wants to use UTF-8 filenames, but is being foiled by bad filesystem walking code. Nearly every use of os.listdir is a bug, it's easy to use incorrectly even for code like this that doesn't care about running on non-posix systems. Swapping in osutils.walkdirs instead is not ideal because it's a rather baroque interface and still doesn't handle the edge case of undecodable bytestring names. However, it's in all the bzrlib versions that builddeb needs to support and gets the common case right.

It would be nice to get rid of the bits copied over from bzrtools entirely. The bzrtools_import module is built around the idea of importing from tar, and this bug is in the compat layer designed to make an actual directory look like a tarfile. But bzr-builddeb only wants the import_dir function, so that design is backwards. The only significant chunk is the TreeTransform construction in _import_archive which should really live somewhere else.

To post a comment you must log in.
Revision history for this message
Jelmer Vernooij (jelmer) wrote :

+1

Also, I like the idea of getting rid of the bzrtools import code.

review: Approve (code)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'bzrtools_import.py'
2--- bzrtools_import.py 2010-10-28 18:13:44 +0000
3+++ bzrtools_import.py 2011-10-24 17:38:25 +0000
4@@ -14,7 +14,7 @@
5 from bzrlib.bzrdir import BzrDir
6 from bzrlib.errors import NoSuchFile, BzrCommandError, NotBranchError
7 from bzrlib.osutils import (pathjoin, isdir, file_iterator, basename,
8- file_kind, splitpath, normpath)
9+ file_kind, splitpath, normpath, walkdirs)
10 from bzrlib.trace import warning
11 from bzrlib.transform import TreeTransform, resolve_conflicts, cook_conflicts
12 from bzrlib.workingtree import WorkingTree
13@@ -74,19 +74,10 @@
14 def __repr__(self):
15 return 'DirWrapper(%r)' % self.root
16
17- def getmembers(self, subdir=None):
18- if subdir is not None:
19- mydir = pathjoin(self.root, subdir)
20- else:
21- mydir = self.root
22- for child in os.listdir(mydir):
23- if subdir is not None:
24- child = pathjoin(subdir, child)
25- fi = FileInfo(self.root, child)
26- yield fi
27- if fi.isdir():
28- for v in self.getmembers(child):
29- yield v
30+ def getmembers(self):
31+ for _, dir_block in walkdirs(self.root):
32+ for relpath, _, _, stat_result, _ in dir_block:
33+ yield FileInfo(self.root, relpath, stat_result)
34
35 def extractfile(self, member):
36 return open(member.fullpath)
37@@ -94,7 +85,7 @@
38
39 class FileInfo(object):
40
41- def __init__(self, root, filepath):
42+ def __init__(self, root, filepath, stat):
43 self.fullpath = pathjoin(root, filepath)
44 self.root = root
45 if filepath != '':
46@@ -102,7 +93,6 @@
47 else:
48 self.name = basename(root)
49 self.type = None
50- stat = os.lstat(self.fullpath)
51 self.mode = stat.st_mode
52 if self.isdir():
53 self.name += '/'
54
55=== modified file 'tests/__init__.py'
56--- tests/__init__.py 2011-10-01 20:41:14 +0000
57+++ tests/__init__.py 2011-10-24 17:38:25 +0000
58@@ -36,9 +36,15 @@
59
60 from bzrlib.tests import TestUtil, multiply_tests
61 try:
62- from bzrlib.tests.features import ModuleAvailableFeature
63+ from bzrlib.tests.features import (
64+ ModuleAvailableFeature,
65+ UnicodeFilenameFeature,
66+ )
67 except ImportError: # bzr < 2.5
68- from bzrlib.tests import ModuleAvailableFeature
69+ from bzrlib.tests import (
70+ ModuleAvailableFeature,
71+ UnicodeFilenameFeature,
72+ )
73
74
75 def make_new_upstream_dir(source, dest):
76
77=== modified file 'tests/test_bzrtools_import.py'
78--- tests/test_bzrtools_import.py 2011-06-13 23:01:14 +0000
79+++ tests/test_bzrtools_import.py 2011-10-24 17:38:25 +0000
80@@ -19,10 +19,10 @@
81 #
82
83 from bzrlib.plugins.builddeb.bzrtools_import import import_dir
84-from bzrlib.plugins.builddeb.tests import TestCaseWithTransport
85-
86-
87-class ImportArchiveTests(TestCaseWithTransport):
88+from bzrlib.plugins.builddeb import tests
89+
90+
91+class ImportArchiveTests(tests.TestCaseWithTransport):
92
93 def test_strips_common_prefix(self):
94 tree = self.make_branch_and_tree(".")
95@@ -172,3 +172,13 @@
96 import_dir(tree, "source", target_tree=file_ids_tree)
97 self.assertEqual("a-id", tree.path2id("b"))
98 self.assertEqual("b-id", tree.path2id("b/b"))
99+
100+ def test_nonascii_filename(self):
101+ self.requireFeature(tests.UnicodeFilenameFeature)
102+ tree = self.make_branch_and_tree(".")
103+ tree.lock_write()
104+ self.addCleanup(tree.unlock)
105+ self.build_tree(["source/", u"source/\xa7"])
106+ import_dir(tree, "source")
107+ self.assertEqual(["", u"\xa7"],
108+ sorted([tree.id2path(i) for i in tree.all_file_ids()]))

Subscribers

People subscribed via source and target branches