launchpad-reviewers team mailing list archive
-
launchpad-reviewers team
-
Mailing list archive
-
Message #22455
[Merge] lp:~cjwatson/launchpad/scandir into lp:launchpad
Colin Watson has proposed merging lp:~cjwatson/launchpad/scandir into lp:launchpad with lp:~cjwatson/launchpad/importlib-resources as a prerequisite.
Commit message:
Convert all uses of os.walk and many uses of os.listdir to scandir.
Requested reviews:
Launchpad code reviewers (launchpad-reviewers)
For more details, see:
https://code.launchpad.net/~cjwatson/launchpad/scandir/+merge/345139
When switching to importlib-resources, I noticed scandir among the new dependencies, and it seems like a good idea. Replacing os.walk is straightforward; replacing os.listdir isn't always worth it, so I left many instances of that alone, but in some cases it's a clear improvement.
We lose the randomisation of os.listdir performed by the test harness when switching to scandir.scandir, which is a bit of a shame, but there's no good way to do that randomisation while preserving the iteration property, so it would potentially leave us open to problems caused by unlinking files while iterating over their containing directory. This seems a reasonable trade-off.
--
Your team Launchpad code reviewers is requested to review the proposed merge of lp:~cjwatson/launchpad/scandir into lp:launchpad.
=== modified file 'lib/devscripts/sourcecode.py'
--- lib/devscripts/sourcecode.py 2012-06-25 12:21:10 +0000
+++ lib/devscripts/sourcecode.py 2018-05-06 14:00:16 +0000
@@ -1,4 +1,4 @@
-# Copyright 2009 Canonical Ltd. This software is licensed under the
+# Copyright 2009-2018 Canonical Ltd. This software is licensed under the
# GNU Affero General Public License version 3 (see the file LICENSE).
"""Tools for maintaining the Launchpad source code."""
@@ -32,6 +32,7 @@
)
from bzrlib.upgrade import upgrade
from bzrlib.workingtree import WorkingTree
+import scandir
from devscripts import get_launchpad_root
@@ -136,12 +137,10 @@
def find_branches(directory):
"""List the directory names in 'directory' that are branches."""
branches = []
- for name in os.listdir(directory):
- if name in ('.', '..'):
- continue
+ for entry in scandir.scandir(directory):
try:
- Branch.open(os.path.join(directory, name))
- branches.append(name)
+ Branch.open(entry.path)
+ branches.append(entry.name)
except NotBranchError:
pass
return branches
=== modified file 'lib/lp/archivepublisher/customupload.py'
--- lib/lp/archivepublisher/customupload.py 2018-01-19 16:29:38 +0000
+++ lib/lp/archivepublisher/customupload.py 2018-05-06 14:00:16 +0000
@@ -20,6 +20,7 @@
import tarfile
import tempfile
+import scandir
from zope.interface import implementer
from lp.archivepublisher.debversion import (
@@ -287,7 +288,7 @@
"""Install the files from the custom upload to the archive."""
assert self.tmpdir is not None, "Must extract tarfile first"
extracted = False
- for dirpath, dirnames, filenames in os.walk(self.tmpdir):
+ for dirpath, dirnames, filenames in scandir.walk(self.tmpdir):
# Create symbolic links to directories.
for dirname in dirnames:
@@ -356,17 +357,17 @@
# now present in the target. Deliberately skip 'broken' versions
# because they can't be sorted anyway.
versions = []
- for inst in os.listdir(self.targetdir):
+ for entry in scandir.scandir(self.targetdir):
# Skip the symlink.
- if inst == 'current':
+ if entry.name == 'current':
continue
# Skip broken versions.
try:
- make_version(inst)
+ make_version(entry.name)
except VersionError:
continue
# Append the valid versions to the list.
- versions.append(inst)
+ versions.append(entry.name)
versions.sort(key=make_version, reverse=True)
# Make sure the 'current' symlink points to the most recent version
=== modified file 'lib/lp/archivepublisher/model/ftparchive.py'
--- lib/lp/archivepublisher/model/ftparchive.py 2016-09-24 04:24:30 +0000
+++ lib/lp/archivepublisher/model/ftparchive.py 2018-05-06 14:00:16 +0000
@@ -1,4 +1,4 @@
-# Copyright 2009-2016 Canonical Ltd. This software is licensed under the
+# Copyright 2009-2018 Canonical Ltd. This software is licensed under the
# GNU Affero General Public License version 3 (see the file LICENSE).
from collections import defaultdict
@@ -7,6 +7,7 @@
from StringIO import StringIO
import time
+import scandir
from storm.expr import (
Desc,
Join,
@@ -60,16 +61,16 @@
If omitted, all files are removed.
"""
if os.path.isdir(path):
- for name in os.listdir(path):
- if name == "by-hash" or not re.match(clean_pattern, name):
+ for entry in list(scandir.scandir(path)):
+ if (entry.name == "by-hash" or
+ not re.match(clean_pattern, entry.name)):
# Ignore existing by-hash directories; they will be cleaned
# up to match the rest of the directory tree later.
continue
- child_path = os.path.join(path, name)
# Directories containing index files should never have
# subdirectories other than by-hash. Guard against expensive
# mistakes by not recursing here.
- os.unlink(child_path)
+ os.unlink(entry.path)
else:
os.makedirs(path, 0o755)
=== modified file 'lib/lp/archivepublisher/publishing.py'
--- lib/lp/archivepublisher/publishing.py 2018-03-27 23:26:12 +0000
+++ lib/lp/archivepublisher/publishing.py 2018-05-06 14:00:16 +0000
@@ -34,6 +34,7 @@
_multivalued,
Release,
)
+import scandir
from storm.expr import Desc
from zope.component import getUtility
from zope.interface import (
@@ -377,12 +378,12 @@
hash_path = os.path.join(self.path, archive_hash.apt_name)
if os.path.exists(hash_path):
prune_hash_directory = True
- for digest in list(os.listdir(hash_path)):
- if digest not in self.known_digests[archive_hash.apt_name]:
- digest_path = os.path.join(hash_path, digest)
+ for entry in list(scandir.scandir(hash_path)):
+ if entry.name not in self.known_digests[
+ archive_hash.apt_name]:
self.log.debug(
- "by-hash: Deleting unreferenced %s" % digest_path)
- os.unlink(digest_path)
+ "by-hash: Deleting unreferenced %s" % entry.path)
+ os.unlink(entry.path)
else:
prune_hash_directory = False
if prune_hash_directory:
@@ -1202,11 +1203,11 @@
distroseries, pocket, component, core_files)
dep11_dir = os.path.join(suite_dir, component, "dep11")
try:
- for dep11_file in os.listdir(dep11_dir):
- if (dep11_file.startswith("Components-") or
- dep11_file.startswith("icons-")):
+ for entry in scandir.scandir(dep11_dir):
+ if (entry.name.startswith("Components-") or
+ entry.name.startswith("icons-")):
dep11_path = os.path.join(
- component, "dep11", dep11_file)
+ component, "dep11", entry.name)
extra_files.add(remove_suffix(dep11_path))
extra_files.add(dep11_path)
except OSError as e:
@@ -1359,11 +1360,11 @@
i18n_dir = os.path.join(self._config.distsroot, suite, i18n_subpath)
i18n_files = set()
try:
- for i18n_file in os.listdir(i18n_dir):
- if not i18n_file.startswith('Translation-'):
+ for entry in scandir.scandir(i18n_dir):
+ if not entry.name.startswith('Translation-'):
continue
- i18n_files.add(remove_suffix(i18n_file))
- i18n_files.add(i18n_file)
+ i18n_files.add(remove_suffix(entry.name))
+ i18n_files.add(entry.name)
except OSError as e:
if e.errno != errno.ENOENT:
raise
@@ -1556,7 +1557,7 @@
def add_dir(self, path):
"""Recursively add a directory path to be checksummed."""
- for dirpath, dirnames, filenames in os.walk(path):
+ for dirpath, dirnames, filenames in scandir.walk(path):
for filename in filenames:
self.add(os.path.join(dirpath, filename))
=== modified file 'lib/lp/archivepublisher/scripts/publish_ftpmaster.py'
--- lib/lp/archivepublisher/scripts/publish_ftpmaster.py 2018-01-18 15:31:02 +0000
+++ lib/lp/archivepublisher/scripts/publish_ftpmaster.py 2018-05-06 14:00:16 +0000
@@ -14,6 +14,7 @@
import shutil
from pytz import utc
+import scandir
from zope.component import getUtility
from lp.archivepublisher.config import getPubConfig
@@ -472,7 +473,7 @@
backup_top = os.path.join(get_backup_dists(archive_config), suite)
staging_top = os.path.join(archive_config.stagingroot, suite)
updated = False
- for staging_dir, _, filenames in os.walk(staging_top):
+ for staging_dir, _, filenames in scandir.walk(staging_top):
rel_dir = os.path.relpath(staging_dir, staging_top)
backup_dir = os.path.join(backup_top, rel_dir)
for filename in filenames:
=== modified file 'lib/lp/archivepublisher/signing.py'
--- lib/lp/archivepublisher/signing.py 2018-01-19 16:29:38 +0000
+++ lib/lp/archivepublisher/signing.py 2018-05-06 14:00:16 +0000
@@ -26,6 +26,8 @@
import tempfile
import textwrap
+import scandir
+
from lp.archivepublisher.config import getPubConfig
from lp.archivepublisher.customupload import CustomUpload
from lp.services.osutils import remove_if_exists
@@ -166,7 +168,7 @@
def findSigningHandlers(self):
"""Find all the signable files in an extracted tarball."""
- for dirpath, dirnames, filenames in os.walk(self.tmpdir):
+ for dirpath, dirnames, filenames in scandir.walk(self.tmpdir):
for filename in filenames:
if filename.endswith(".efi"):
yield (os.path.join(dirpath, filename), self.signUefi)
=== modified file 'lib/lp/archivepublisher/tests/test_publisher.py'
--- lib/lp/archivepublisher/tests/test_publisher.py 2018-04-05 11:32:50 +0000
+++ lib/lp/archivepublisher/tests/test_publisher.py 2018-05-06 14:00:16 +0000
@@ -38,6 +38,7 @@
from backports import lzma
import mock
import pytz
+import scandir
from testscenarios import (
load_tests_apply_scenarios,
WithScenarios,
@@ -513,7 +514,7 @@
def match(self, root):
children = set()
- for dirpath, dirnames, _ in os.walk(root):
+ for dirpath, dirnames, _ in scandir.walk(root):
if "by-hash" in dirnames:
children.add(os.path.relpath(dirpath, root))
mismatch = MatchesSetwise(
=== modified file 'lib/lp/archivepublisher/tests/test_signing.py'
--- lib/lp/archivepublisher/tests/test_signing.py 2018-03-28 09:30:48 +0000
+++ lib/lp/archivepublisher/tests/test_signing.py 2018-05-06 14:00:16 +0000
@@ -12,6 +12,7 @@
import tarfile
from fixtures import MonkeyPatch
+import scandir
from testtools.matchers import (
Contains,
Equals,
@@ -59,7 +60,7 @@
def match(self, base):
content = []
- for root, dirs, files in os.walk(base):
+ for root, dirs, files in scandir.walk(base):
content.extend(
[os.path.relpath(os.path.join(root, f), base) for f in files])
=== modified file 'lib/lp/archiveuploader/dscfile.py'
--- lib/lp/archiveuploader/dscfile.py 2018-03-02 16:17:35 +0000
+++ lib/lp/archiveuploader/dscfile.py 2018-05-06 14:00:16 +0000
@@ -1,4 +1,4 @@
-# Copyright 2009-2017 Canonical Ltd. This software is licensed under the
+# Copyright 2009-2018 Canonical Ltd. This software is licensed under the
# GNU Affero General Public License version 3 (see the file LICENSE).
""" DSCFile and related.
@@ -30,6 +30,7 @@
Deb822Dict,
PkgRelation,
)
+import scandir
from zope.component import getUtility
from lp.app.errors import NotFoundError
@@ -613,8 +614,8 @@
# Check if 'dpkg-source' created only one directory.
temp_directories = [
- dirname for dirname in os.listdir(unpacked_dir)
- if os.path.isdir(dirname)]
+ entry.name for entry in scandir.scandir(unpacked_dir)
+ if entry.is_dir()]
if len(temp_directories) > 1:
yield UploadError(
'Unpacked source contains more than one directory: %r'
=== modified file 'lib/lp/archiveuploader/livefsupload.py'
--- lib/lp/archiveuploader/livefsupload.py 2015-01-23 17:57:59 +0000
+++ lib/lp/archiveuploader/livefsupload.py 2018-05-06 14:00:16 +0000
@@ -1,4 +1,4 @@
-# Copyright 2014-2015 Canonical Ltd. This software is licensed under the
+# Copyright 2014-2018 Canonical Ltd. This software is licensed under the
# GNU Affero General Public License version 3 (see the file LICENSE).
"""Process a live filesystem upload."""
@@ -7,6 +7,7 @@
import os
+import scandir
from zope.component import getUtility
from lp.buildmaster.enums import BuildStatus
@@ -36,7 +37,7 @@
"""Process this upload, loading it into the database."""
self.logger.debug("Beginning processing.")
- for dirpath, _, filenames in os.walk(self.upload_path):
+ for dirpath, _, filenames in scandir.walk(self.upload_path):
if dirpath == self.upload_path:
# All relevant files will be in a subdirectory.
continue
=== modified file 'lib/lp/archiveuploader/snapupload.py'
--- lib/lp/archiveuploader/snapupload.py 2016-08-30 12:34:51 +0000
+++ lib/lp/archiveuploader/snapupload.py 2018-05-06 14:00:16 +0000
@@ -1,4 +1,4 @@
-# Copyright 2015-2016 Canonical Ltd. This software is licensed under the
+# Copyright 2015-2018 Canonical Ltd. This software is licensed under the
# GNU Affero General Public License version 3 (see the file LICENSE).
"""Process a snap package upload."""
@@ -7,6 +7,7 @@
import os
+import scandir
from zope.component import getUtility
from lp.archiveuploader.utils import UploadError
@@ -39,7 +40,7 @@
found_snap = False
snap_paths = []
- for dirpath, _, filenames in os.walk(self.upload_path):
+ for dirpath, _, filenames in scandir.walk(self.upload_path):
if dirpath == self.upload_path:
# All relevant files will be in a subdirectory.
continue
=== modified file 'lib/lp/archiveuploader/uploadprocessor.py'
--- lib/lp/archiveuploader/uploadprocessor.py 2018-03-02 16:17:35 +0000
+++ lib/lp/archiveuploader/uploadprocessor.py 2018-05-06 14:00:16 +0000
@@ -1,4 +1,4 @@
-# Copyright 2009-2017 Canonical Ltd. This software is licensed under the
+# Copyright 2009-2018 Canonical Ltd. This software is licensed under the
# GNU Affero General Public License version 3 (see the file LICENSE).
"""Code for 'processing' 'uploads'. Also see nascentupload.py.
@@ -51,6 +51,7 @@
import shutil
import sys
+import scandir
from sqlobject import SQLObjectNotFound
from zope.component import getUtility
@@ -210,8 +211,7 @@
alphabetically sorted.
"""
return sorted(
- dir_name for dir_name in os.listdir(fsroot)
- if os.path.isdir(os.path.join(fsroot, dir_name)))
+ entry.name for entry in scandir.scandir(fsroot) if entry.is_dir())
class UploadHandler:
@@ -258,7 +258,7 @@
"""
changes_files = []
- for dirpath, dirnames, filenames in os.walk(self.upload_path):
+ for dirpath, dirnames, filenames in scandir.walk(self.upload_path):
relative_path = dirpath[len(self.upload_path) + 1:]
for filename in filenames:
if filename.endswith(".changes"):
=== modified file 'lib/lp/bugs/tests/test_doc.py'
--- lib/lp/bugs/tests/test_doc.py 2016-09-07 22:41:08 +0000
+++ lib/lp/bugs/tests/test_doc.py 2018-05-06 14:00:16 +0000
@@ -1,4 +1,4 @@
-# Copyright 2009-2016 Canonical Ltd. This software is licensed under the
+# Copyright 2009-2018 Canonical Ltd. This software is licensed under the
# GNU Affero General Public License version 3 (see the file LICENSE).
"""
@@ -9,6 +9,8 @@
import os
import unittest
+import scandir
+
from lp.code.tests.test_doc import branchscannerSetUp
from lp.services.config import config
from lp.services.features.testing import FeatureFixture
@@ -482,11 +484,10 @@
stories_dir = os.path.join(os.path.pardir, 'stories')
suite.addTest(PageTestSuite(stories_dir))
stories_path = os.path.join(here, stories_dir)
- for story_dir in os.listdir(stories_path):
- full_story_dir = os.path.join(stories_path, story_dir)
- if not os.path.isdir(full_story_dir):
+ for story_entry in scandir.scandir(stories_path):
+ if not story_entry.is_dir():
continue
- story_path = os.path.join(stories_dir, story_dir)
+ story_path = os.path.join(stories_dir, story_entry.name)
suite.addTest(PageTestSuite(story_path))
testsdir = os.path.abspath(
=== modified file 'lib/lp/codehosting/codeimport/tests/test_worker.py'
--- lib/lp/codehosting/codeimport/tests/test_worker.py 2018-03-15 20:44:04 +0000
+++ lib/lp/codehosting/codeimport/tests/test_worker.py 2018-05-06 14:00:16 +0000
@@ -45,6 +45,7 @@
)
from dulwich.repo import Repo as GitRepo
from fixtures import FakeLogger
+import scandir
import subvertpy
import subvertpy.client
import subvertpy.ra
@@ -136,7 +137,7 @@
`directory1` are laid out in the same way as `directory2`.
"""
def list_files(directory):
- for path, ignored, ignored in os.walk(directory):
+ for path, ignored, ignored in scandir.walk(directory):
yield path[len(directory):]
self.assertEqual(
sorted(list_files(directory1)), sorted(list_files(directory2)))
=== modified file 'lib/lp/registry/model/codeofconduct.py'
--- lib/lp/registry/model/codeofconduct.py 2018-03-02 16:17:35 +0000
+++ lib/lp/registry/model/codeofconduct.py 2018-05-06 14:00:16 +0000
@@ -1,4 +1,4 @@
-# Copyright 2009-2015 Canonical Ltd. This software is licensed under the
+# Copyright 2009-2018 Canonical Ltd. This software is licensed under the
# GNU Affero General Public License version 3 (see the file LICENSE).
"""A module for CodeOfConduct (CoC) related classes.
@@ -14,6 +14,7 @@
import os
import pytz
+import scandir
from sqlobject import (
BoolCol,
ForeignKey,
@@ -151,11 +152,11 @@
cocs_path = getUtility(ICodeOfConductConf).path
# iter through files and store the CoC Object
- for filename in os.listdir(cocs_path):
+ for entry in scandir.scandir(cocs_path):
# Select the correct filenames
- if filename.endswith('.txt'):
+ if entry.name.endswith('.txt'):
# Extract the version from filename
- version = filename.replace('.txt', '')
+ version = entry.name.replace('.txt', '')
releases.append(CodeOfConduct(version))
# Return the available list of CoCs objects
=== modified file 'lib/lp/registry/scripts/productreleasefinder/walker.py'
--- lib/lp/registry/scripts/productreleasefinder/walker.py 2017-10-21 18:14:14 +0000
+++ lib/lp/registry/scripts/productreleasefinder/walker.py 2018-05-06 14:00:16 +0000
@@ -1,4 +1,4 @@
-# Copyright 2009-2011 Canonical Ltd. This software is licensed under the
+# Copyright 2009-2018 Canonical Ltd. This software is licensed under the
# GNU Affero General Public License version 3 (see the file LICENSE).
"""HTTP and FTP walker.
@@ -30,6 +30,7 @@
InvalidURIError,
URI,
)
+import scandir
from lp.registry.scripts.productreleasefinder import log
from lp.services.beautifulsoup import BeautifulSoup
@@ -63,7 +64,7 @@
"""Base class for URL walkers.
This class is a base class for those wishing to implement protocol
- specific walkers. Walkers behave much like the os.walk() function,
+ specific walkers. Walkers behave much like the scandir.walk() function,
but taking a URL and working remotely.
A typical usage would be:
@@ -116,7 +117,7 @@
"""Walk through the URL.
Yields (dirpath, dirnames, filenames) for each path under the base;
- dirnames can be modified as with os.walk.
+ dirnames can be modified as with scandir.walk.
"""
try:
self.open()
@@ -421,7 +422,7 @@
elif scheme in ["http", "https"]:
return HTTPWalker(url, log_parent)
elif scheme in ["file"]:
- return os.walk(path)
+ return scandir.walk(path)
else:
raise WalkerError("Unknown scheme: %s" % scheme)
=== modified file 'lib/lp/scripts/utilities/js/combinecss.py'
--- lib/lp/scripts/utilities/js/combinecss.py 2017-10-20 12:01:51 +0000
+++ lib/lp/scripts/utilities/js/combinecss.py 2018-05-06 14:00:16 +0000
@@ -1,13 +1,14 @@
-# Copyright 2009-2017 Canonical Ltd. This software is licensed under the
+# Copyright 2009-2018 Canonical Ltd. This software is licensed under the
# GNU Affero General Public License version 3 (see the file LICENSE).
import os
+import scandir
+
+from lp.scripts.utilities.js.combo import combine_files
from lp.scripts.utilities.js.jsbuild import ComboFile
-from lp.scripts.utilities.js.combo import combine_files
from lp.services.config import config
-
# It'd probably be nice to have this script find all the CSS files we might
# need and combine them together, but if we do that we'd certainly end up
# including lots of styles that we don't need/want, so keeping this hard-coded
@@ -60,7 +61,7 @@
# every time a new component is added.
component_dir = 'css/components'
component_path = os.path.abspath(os.path.join(icing, component_dir))
- for root, dirs, files in os.walk(component_path):
+ for root, dirs, files in scandir.walk(component_path):
for file in files:
if file.endswith('.css'):
names.append('%s/%s' % (component_dir, file))
=== modified file 'lib/lp/scripts/utilities/js/jsbuild.py'
--- lib/lp/scripts/utilities/js/jsbuild.py 2015-12-01 12:27:09 +0000
+++ lib/lp/scripts/utilities/js/jsbuild.py 2018-05-06 14:00:16 +0000
@@ -1,4 +1,4 @@
-# Copyright 2011-2012 Canonical Ltd. This software is licensed under the
+# Copyright 2011-2018 Canonical Ltd. This software is licensed under the
# GNU Affero General Public License version 3 (see the file LICENSE).
"""build.py - Minifies and creates the JS build directory."""
@@ -17,6 +17,7 @@
import cssutils
from cssutils import settings
+import scandir
HERE = os.path.dirname(__file__)
@@ -276,8 +277,8 @@
return
# Process sub-skins.
- for skin in os.listdir(src_skins_dir):
- self.build_skin(component_name, skin)
+ for entry in scandir.scandir(src_skins_dir):
+ self.build_skin(component_name, entry.name)
def link_directory_content(self, src_dir, target_dir, link_filter=None):
"""Link all the files in src_dir into target_dir.
@@ -289,14 +290,13 @@
If the filter returns False, no symlink will be created. By
default a symlink is created for everything.
"""
- for name in os.listdir(src_dir):
- if name.endswith('~'):
- continue
- src = os.path.join(src_dir, name)
- if link_filter and not link_filter(src):
- continue
- target = os.path.join(target_dir, name)
- self.ensure_link(relative_path(target, src), target)
+ for entry in scandir.scandir(src_dir):
+ if entry.name.endswith('~'):
+ continue
+ if link_filter and not link_filter(entry.path):
+ continue
+ target = os.path.join(target_dir, entry.name)
+ self.ensure_link(relative_path(target, entry.path), target)
def build_skin(self, component_name, skin_name):
"""Build a skin for a particular component."""
@@ -350,11 +350,10 @@
combined_css.update()
def do_build(self):
- for name in os.listdir(self.src_dir):
- path = os.path.join(self.src_dir, name)
- if not os.path.isdir(path):
+ for entry in scandir.scandir(self.src_dir):
+ if not entry.is_dir():
continue
- self.build_assets(name)
+ self.build_assets(entry.name)
self.update_combined_css_skins()
=== modified file 'lib/lp/services/config/fixture.py'
--- lib/lp/services/config/fixture.py 2017-12-19 17:16:38 +0000
+++ lib/lp/services/config/fixture.py 2018-05-06 14:00:16 +0000
@@ -1,4 +1,4 @@
-# Copyright 2010-2016 Canonical Ltd. This software is licensed under the
+# Copyright 2010-2018 Canonical Ltd. This software is licensed under the
# GNU Affero General Public License version 3 (see the file LICENSE).
"""Fixtures related to configs.
@@ -18,6 +18,7 @@
from textwrap import dedent
from fixtures import Fixture
+import scandir
from lp.services.config import config
@@ -54,12 +55,12 @@
self.absroot = os.path.abspath(root)
self.addCleanup(shutil.rmtree, self.absroot)
source = os.path.join(config.root, 'configs', self.copy_from_instance)
- for basename in os.listdir(source):
- if basename == 'launchpad-lazr.conf':
+ for entry in scandir.scandir(source):
+ if entry.name == 'launchpad-lazr.conf':
self.add_section(self._extend_str % self.copy_from_instance)
continue
- with open(source + '/' + basename, 'rb') as input:
- with open(root + '/' + basename, 'wb') as out:
+ with open(entry.path, 'rb') as input:
+ with open(os.path.join(root, entry.name), 'wb') as out:
out.write(input.read())
=== modified file 'lib/lp/services/config/tests/test_config.py'
--- lib/lp/services/config/tests/test_config.py 2018-05-06 14:00:16 +0000
+++ lib/lp/services/config/tests/test_config.py 2018-05-06 14:00:16 +0000
@@ -1,4 +1,4 @@
-# Copyright 2009-2016 Canonical Ltd. This software is licensed under the
+# Copyright 2009-2018 Canonical Ltd. This software is licensed under the
# GNU Affero General Public License version 3 (see the file LICENSE).
# We know we are not using root and handlers.
@@ -19,6 +19,7 @@
import importlib_resources
from lazr.config import ConfigSchema
from lazr.config.interfaces import ConfigErrors
+import scandir
import testtools
import ZConfig
@@ -150,7 +151,7 @@
load_testcase = unittest.defaultTestLoader.loadTestsFromTestCase
# Add a test for every launchpad[.lazr].conf file in our tree.
for config_dir in lp.services.config.CONFIG_ROOT_DIRS:
- for dirpath, dirnames, filenames in os.walk(config_dir):
+ for dirpath, dirnames, filenames in scandir.walk(config_dir):
if os.path.basename(dirpath) in EXCLUDED_CONFIGS:
del dirnames[:] # Don't look in subdirectories.
continue
=== modified file 'lib/lp/services/librarianserver/librariangc.py'
--- lib/lp/services/librarianserver/librariangc.py 2018-04-19 00:03:57 +0000
+++ lib/lp/services/librarianserver/librariangc.py 2018-05-06 14:00:16 +0000
@@ -1,4 +1,4 @@
-# Copyright 2009-2017 Canonical Ltd. This software is licensed under the
+# Copyright 2009-2018 Canonical Ltd. This software is licensed under the
# GNU Affero General Public License version 3 (see the file LICENSE).
"""Librarian garbage collection routines"""
@@ -18,6 +18,7 @@
import iso8601
import pytz
+import scandir
from swiftclient import client as swiftclient
from zope.interface import implementer
@@ -633,7 +634,7 @@
hex_content_id_re = re.compile('^([0-9a-f]{8})(\.migrated)?$')
ONE_DAY = 24 * 60 * 60
- for dirpath, dirnames, filenames in os.walk(
+ for dirpath, dirnames, filenames in scandir.walk(
get_storage_root(), followlinks=True):
# Ignore known and harmless noise in the Librarian storage area.
=== modified file 'lib/lp/services/librarianserver/swift.py'
--- lib/lp/services/librarianserver/swift.py 2018-01-03 17:17:12 +0000
+++ lib/lp/services/librarianserver/swift.py 2018-05-06 14:00:16 +0000
@@ -1,4 +1,4 @@
-# Copyright 2013-2017 Canonical Ltd. This software is licensed under the
+# Copyright 2013-2018 Canonical Ltd. This software is licensed under the
# GNU Affero General Public License version 3 (see the file LICENSE).
"""Move files from Librarian disk storage into Swift."""
@@ -21,6 +21,7 @@
import time
import urllib
+import scandir
from swiftclient import client as swiftclient
from lp.services.config import config
@@ -79,7 +80,8 @@
# Walk the Librarian on disk file store, searching for matching
# files that may need to be copied into Swift. We need to follow
# symlinks as they are being used span disk partitions.
- for dirpath, dirnames, filenames in os.walk(fs_root, followlinks=True):
+ for dirpath, dirnames, filenames in scandir.walk(
+ fs_root, followlinks=True):
# Don't recurse if we know this directory contains no matching
# files.
=== modified file 'lib/lp/services/mail/mailbox.py'
--- lib/lp/services/mail/mailbox.py 2015-09-21 06:04:04 +0000
+++ lib/lp/services/mail/mailbox.py 2018-05-06 14:00:16 +0000
@@ -1,4 +1,4 @@
-# Copyright 2009-2011 Canonical Ltd. This software is licensed under the
+# Copyright 2009-2018 Canonical Ltd. This software is licensed under the
# GNU Affero General Public License version 3 (see the file LICENSE).
__metaclass__ = type
@@ -16,6 +16,7 @@
import socket
import threading
+import scandir
from zope.interface import (
implementer,
Interface,
@@ -168,10 +169,10 @@
def items(self):
"""See IMailBox."""
- for name in os.listdir(self.mail_dir):
- filename = os.path.join(self.mail_dir, name)
- if os.path.isfile(filename):
- yield (filename, open(filename).read())
+ for entry in scandir.scandir(self.mail_dir):
+ if entry.is_file():
+ with open(entry.path) as mail_file:
+ yield (entry.path, mail_file.read())
def delete(self, id):
"""See IMailBox."""
=== modified file 'lib/lp/services/mailman/runmailman.py'
--- lib/lp/services/mailman/runmailman.py 2015-10-14 15:22:01 +0000
+++ lib/lp/services/mailman/runmailman.py 2018-05-06 14:00:16 +0000
@@ -1,4 +1,4 @@
-# Copyright 2009 Canonical Ltd. This software is licensed under the
+# Copyright 2009-2018 Canonical Ltd. This software is licensed under the
# GNU Affero General Public License version 3 (see the file LICENSE).
"""Start and stop the Mailman processes."""
@@ -16,6 +16,8 @@
import subprocess
import sys
+import scandir
+
import lp.services.config
from lp.services.mailman.config import configure_prefix
from lp.services.mailman.monkeypatches import monkey_patch
@@ -96,8 +98,8 @@
if error.errno != errno.ENOENT:
raise
lock_dir = os.path.join(mailman_path, 'locks')
- for filename in os.listdir(lock_dir):
- os.remove(os.path.join(lock_dir, filename))
+ for entry in scandir.scandir(lock_dir):
+ os.remove(entry.path)
def start_mailman(quiet=False, config=None):
=== modified file 'lib/lp/services/scripts/tests/__init__.py'
--- lib/lp/services/scripts/tests/__init__.py 2012-06-27 13:57:04 +0000
+++ lib/lp/services/scripts/tests/__init__.py 2018-05-06 14:00:16 +0000
@@ -1,4 +1,4 @@
-# Copyright 2009-2012 Canonical Ltd. This software is licensed under the
+# Copyright 2009-2018 Canonical Ltd. This software is licensed under the
# GNU Affero General Public License version 3 (see the file LICENSE).
__metaclass__ = type
@@ -10,6 +10,8 @@
import os
import subprocess
+import scandir
+
import lp
from lp.services.config import config
@@ -32,7 +34,7 @@
scripts = []
for script_location in SCRIPT_LOCATIONS:
location = os.path.join(LP_TREE, script_location)
- for path, dirs, filenames in os.walk(location):
+ for path, dirs, filenames in scandir.walk(location):
for filename in filenames:
script_path = os.path.join(path, filename)
if (filename.startswith('_') or
=== modified file 'lib/lp/services/testing/__init__.py'
--- lib/lp/services/testing/__init__.py 2018-04-13 20:47:03 +0000
+++ lib/lp/services/testing/__init__.py 2018-05-06 14:00:16 +0000
@@ -21,6 +21,8 @@
import os
import unittest
+import scandir
+
# This import registers the 'doctest' Unicode codec.
import lp.services.testing.doctestcodec
from lp.testing.systemdocs import (
@@ -93,11 +95,10 @@
stories_path = os.path.join(base_dir, stories_dir)
if os.path.exists(stories_path):
suite.addTest(PageTestSuite(stories_dir, package))
- for story_dir in os.listdir(stories_path):
- full_story_dir = os.path.join(stories_path, story_dir)
- if not os.path.isdir(full_story_dir):
+ for story_entry in scandir.scandir(stories_path):
+ if not story_entry.is_dir():
continue
- story_path = os.path.join(stories_dir, story_dir)
+ story_path = os.path.join(stories_dir, story_entry.name)
if story_path in special_tests:
continue
suite.addTest(PageTestSuite(story_path, package))
=== modified file 'lib/lp/services/webservice/tests/test_wadllib.py'
--- lib/lp/services/webservice/tests/test_wadllib.py 2015-10-14 15:22:01 +0000
+++ lib/lp/services/webservice/tests/test_wadllib.py 2018-05-06 14:00:16 +0000
@@ -1,4 +1,4 @@
-# Copyright 2009 Canonical Ltd. This software is licensed under the
+# Copyright 2009-2018 Canonical Ltd. This software is licensed under the
# GNU Affero General Public License version 3 (see the file LICENSE).
"""Run the standalone wadllib tests."""
@@ -10,6 +10,7 @@
import os
import unittest
+import scandir
import wadllib
from lp.testing.systemdocs import LayeredDocFileSuite
@@ -23,7 +24,7 @@
# Find all the doctests in wadllib.
packages = []
- for dirpath, dirnames, filenames in os.walk(topdir):
+ for dirpath, dirnames, filenames in scandir.walk(topdir):
if 'docs' in dirnames:
docsdir = os.path.join(dirpath, 'docs')[len(topdir) + 1:]
packages.append(docsdir)
=== modified file 'lib/lp/soyuz/doc/soyuz-set-of-uploads.txt'
--- lib/lp/soyuz/doc/soyuz-set-of-uploads.txt 2016-01-26 15:47:37 +0000
+++ lib/lp/soyuz/doc/soyuz-set-of-uploads.txt 2018-05-06 14:00:16 +0000
@@ -107,13 +107,14 @@
Firstly, we need a way to copy a test upload into the queue (but skip
lock files, which have names starting with a dot).
+ >>> import shutil
+ >>> import scandir
>>> from lp.archiveuploader.tests import datadir
>>> def punt_upload_into_queue(leaf, distro):
... inc_dir = os.path.join(incoming_dir, leaf, distro)
... os.makedirs(inc_dir)
- ... for file_leaf in os.listdir(datadir(os.path.join("suite", leaf))):
- ... os.system("cp %s %s" % (
- ... datadir(os.path.join("suite", leaf, file_leaf)), inc_dir))
+ ... for entry in scandir.scandir(datadir(os.path.join("suite", leaf))):
+ ... shutil.copy(entry.path, inc_dir)
We need a way to count the items in a queue directory
@@ -227,7 +228,6 @@
We'll be doing a lot of uploads with sanity checks, and expect them to
succeed. A helper function, simulate_upload does that with all the checking.
- >>> import shutil
>>> from lp.services.mail import stub
>>> def simulate_upload(
=== modified file 'lib/lp/soyuz/doc/soyuz-upload.txt'
--- lib/lp/soyuz/doc/soyuz-upload.txt 2017-08-03 14:26:40 +0000
+++ lib/lp/soyuz/doc/soyuz-upload.txt 2018-05-06 14:00:16 +0000
@@ -99,11 +99,12 @@
>>> def get_md5(filename):
... return hashlib.md5(open(filename).read()).digest()
+ >>> import scandir
>>> def get_upload_dir(num, dir=incoming_dir):
... """Return the path to the upload, if found in the dir."""
- ... for upload_dir in os.listdir(dir):
- ... if upload_dir.endswith("%06d" % num):
- ... return os.path.join(dir, upload_dir)
+ ... for upload_entry in scandir.scandir(dir):
+ ... if upload_entry.name.endswith("%06d" % num):
+ ... return upload_entry.path
... return None
>>> def find_upload_dir(num):
@@ -183,7 +184,6 @@
... IPersonSet,
... PersonCreationRationale,
... )
- >>> from lp.services.gpg.interfaces import GPGKeyAlgorithm
>>> name, address = "Katie", "katie@xxxxxxxxxxxxxxxxxxxxx"
>>> user = getUtility(IPersonSet).ensurePerson(
... address, name, PersonCreationRationale.OWNER_CREATED_LAUNCHPAD)
=== modified file 'lib/lp/soyuz/scripts/gina/packages.py'
--- lib/lp/soyuz/scripts/gina/packages.py 2016-03-18 14:12:07 +0000
+++ lib/lp/soyuz/scripts/gina/packages.py 2018-05-06 14:00:16 +0000
@@ -1,4 +1,4 @@
-# Copyright 2009-2016 Canonical Ltd. This software is licensed under the
+# Copyright 2009-2018 Canonical Ltd. This software is licensed under the
# GNU Affero General Public License version 3 (see the file LICENSE).
"""Package information classes.
@@ -28,6 +28,8 @@
import shutil
import tempfile
+import scandir
+
from lp.app.validators.version import valid_debian_version
from lp.archivepublisher.diskpool import poolify
from lp.archiveuploader.changesfile import ChangesFile
@@ -88,13 +90,13 @@
return filename, fullpath, component
# Do a second pass, scrubbing through all components in the pool.
- for alt_component in os.listdir(pool_root):
- if not os.path.isdir(os.path.join(pool_root, alt_component)):
+ for alt_component_entry in scandir.scandir(pool_root):
+ if not alt_component_entry.is_dir():
continue
- pool_dir = poolify(name, alt_component)
+ pool_dir = poolify(name, alt_component_entry.name)
fullpath = os.path.join(pool_root, pool_dir, filename)
if os.path.exists(fullpath):
- return filename, fullpath, alt_component
+ return filename, fullpath, alt_component_entry.name
# Couldn't find the file anywhere -- too bad.
raise PoolFileNotFound("File %s not in archive" % filename)
=== modified file 'lib/lp/soyuz/tests/fakepackager.py'
--- lib/lp/soyuz/tests/fakepackager.py 2018-02-02 03:14:35 +0000
+++ lib/lp/soyuz/tests/fakepackager.py 2018-05-06 14:00:16 +0000
@@ -20,6 +20,7 @@
import tempfile
import time
+import scandir
from zope.component import getUtility
from lp.archiveuploader.nascentupload import NascentUpload
@@ -378,9 +379,8 @@
def listAvailableUploads(self):
"""Return the path for all available changesfiles."""
- changes = [os.path.join(self.sandbox_path, filename)
- for filename in os.listdir(self.sandbox_path)
- if filename.endswith('.changes')]
+ changes = [entry.path for entry in scandir.scandir(self.sandbox_path)
+ if entry.name.endswith('.changes')]
return sorted(changes)
=== modified file 'lib/lp/soyuz/tests/test_doc.py'
--- lib/lp/soyuz/tests/test_doc.py 2018-02-02 03:14:35 +0000
+++ lib/lp/soyuz/tests/test_doc.py 2018-05-06 14:00:16 +0000
@@ -11,6 +11,7 @@
import os
import unittest
+import scandir
import transaction
from lp.services.config import config
@@ -165,11 +166,10 @@
stories_dir = os.path.join(os.path.pardir, 'stories')
suite.addTest(PageTestSuite(stories_dir))
stories_path = os.path.join(here, stories_dir)
- for story_dir in os.listdir(stories_path):
- full_story_dir = os.path.join(stories_path, story_dir)
- if not os.path.isdir(full_story_dir):
+ for story_entry in scandir.scandir(stories_path):
+ if not story_entry.is_dir():
continue
- story_path = os.path.join(stories_dir, story_dir)
+ story_path = os.path.join(stories_dir, story_entry.name)
suite.addTest(PageTestSuite(story_path))
# Add special needs tests
=== modified file 'lib/lp/soyuz/tests/test_publishing.py'
--- lib/lp/soyuz/tests/test_publishing.py 2018-02-02 03:14:35 +0000
+++ lib/lp/soyuz/tests/test_publishing.py 2018-05-06 14:00:16 +0000
@@ -13,6 +13,7 @@
import tempfile
import pytz
+import scandir
from storm.store import Store
from testtools.matchers import Equals
import transaction
@@ -494,7 +495,7 @@
def _findChangesFile(self, top, name_fragment):
"""File with given name fragment in directory tree starting at top."""
- for root, dirs, files in os.walk(top, topdown=False):
+ for root, dirs, files in scandir.walk(top, topdown=False):
for name in files:
if (name.endswith('.changes') and
name.find(name_fragment) > -1):
=== modified file 'lib/lp/testing/__init__.py'
--- lib/lp/testing/__init__.py 2017-11-10 02:13:28 +0000
+++ lib/lp/testing/__init__.py 2018-05-06 14:00:16 +0000
@@ -1,4 +1,4 @@
-# Copyright 2009-2017 Canonical Ltd. This software is licensed under the
+# Copyright 2009-2018 Canonical Ltd. This software is licensed under the
# GNU Affero General Public License version 3 (see the file LICENSE).
from __future__ import absolute_import
@@ -93,6 +93,7 @@
import lp_sitecustomize
import oops_datedir_repo.serializer_rfc822
import pytz
+import scandir
import simplejson
from storm.store import Store
import subunit
@@ -1172,7 +1173,7 @@
def _harvest_yui_test_files(file_path):
- for dirpath, dirnames, filenames in os.walk(file_path):
+ for dirpath, dirnames, filenames in scandir.walk(file_path):
for filename in filenames:
if fnmatchcase(filename, "test_*.html"):
yield os.path.join(dirpath, filename)
=== modified file 'lib/lp/testing/gpgkeys/__init__.py'
--- lib/lp/testing/gpgkeys/__init__.py 2017-07-31 11:19:23 +0000
+++ lib/lp/testing/gpgkeys/__init__.py 2018-05-06 14:00:16 +0000
@@ -1,4 +1,4 @@
-# Copyright 2009-2017 Canonical Ltd. This software is licensed under the
+# Copyright 2009-2018 Canonical Ltd. This software is licensed under the
# GNU Affero General Public License version 3 (see the file LICENSE).
"""OpenPGP keys used for testing.
@@ -23,14 +23,12 @@
import os
import gpgme
+import scandir
from zope.component import getUtility
from lp.registry.interfaces.gpg import IGPGKeySet
from lp.registry.interfaces.person import IPersonSet
-from lp.services.gpg.interfaces import (
- GPGKeyAlgorithm,
- IGPGHandler,
- )
+from lp.services.gpg.interfaces import IGPGHandler
gpgkeysdir = os.path.join(os.path.dirname(__file__), 'data')
@@ -109,9 +107,9 @@
def test_keyrings():
"""Iterate over the filenames for test keyrings."""
- for name in os.listdir(gpgkeysdir):
- if name.endswith('.gpg'):
- yield os.path.join(gpgkeysdir, name)
+ for entry in scandir.scandir(gpgkeysdir):
+ if entry.name.endswith('.gpg'):
+ yield entry.path
def decrypt_content(content, password):
=== modified file 'lib/lp/testing/yuixhr.py'
--- lib/lp/testing/yuixhr.py 2017-07-20 17:32:10 +0000
+++ lib/lp/testing/yuixhr.py 2018-05-06 14:00:16 +0000
@@ -1,4 +1,4 @@
-# Copyright 2011-2016 Canonical Ltd. This software is licensed under the
+# Copyright 2011-2018 Canonical Ltd. This software is licensed under the
# GNU Affero General Public License version 3 (see the file LICENSE).
"""Fixture code for YUITest + XHR integration testing."""
@@ -20,6 +20,7 @@
from lazr.restful import ResourceJSONEncoder
from lazr.restful.utils import get_current_browser_request
+import scandir
import simplejson
from zope.component import getUtility
from zope.exceptions.exceptionformatter import format_exception
@@ -451,7 +452,7 @@
def find_tests(root):
- for dirpath, dirnames, filenames in os.walk(root):
+ for dirpath, dirnames, filenames in scandir.walk(root):
dirpath = os.path.relpath(dirpath, root)
for filename in filenames:
if fnmatchcase(filename, 'test_*.js'):
=== modified file 'lib/lp/testopenid/stories/tests.py'
--- lib/lp/testopenid/stories/tests.py 2013-03-20 03:41:40 +0000
+++ lib/lp/testopenid/stories/tests.py 2018-05-06 14:00:16 +0000
@@ -1,9 +1,11 @@
-# Copyright 2004-2008 Canonical Ltd. This software is licensed under the
+# Copyright 2004-2018 Canonical Ltd. This software is licensed under the
# GNU Affero General Public License version 3 (see the file LICENSE).
import os
import unittest
+import scandir
+
from lp.testing.pages import PageTestSuite
@@ -12,8 +14,8 @@
def test_suite():
stories = sorted(
- dir for dir in os.listdir(here)
- if not dir.startswith('.') and os.path.isdir(os.path.join(here, dir)))
+ entry.name for entry in scandir.scandir(here)
+ if not entry.name.startswith('.') and entry.is_dir())
suite = unittest.TestSuite()
suite.addTest(PageTestSuite('.'))
=== modified file 'lib/lp/tests/test_opensource.py'
--- lib/lp/tests/test_opensource.py 2015-10-26 14:54:43 +0000
+++ lib/lp/tests/test_opensource.py 2018-05-06 14:00:16 +0000
@@ -1,4 +1,4 @@
-# Copyright 2009 Canonical Ltd. This software is licensed under the
+# Copyright 2009-2018 Canonical Ltd. This software is licensed under the
# GNU Affero General Public License version 3 (see the file LICENSE).
"""Run the standalone tests in an opensource package.
@@ -21,6 +21,7 @@
import unittest
import launchpadlib
+import scandir
import wadllib
from lp.testing.layers import AppServerLayer
@@ -32,7 +33,7 @@
topdir = os.path.dirname(package.__file__)
packages = []
- for dirpath, dirnames, filenames in os.walk(topdir):
+ for dirpath, dirnames, filenames in scandir.walk(topdir):
if 'docs' in dirnames:
docsdir = os.path.join(dirpath, 'docs')[len(topdir) + 1:]
packages.append(docsdir)
=== modified file 'lib/lp/translations/tests/test_doc.py'
--- lib/lp/translations/tests/test_doc.py 2011-12-28 17:03:06 +0000
+++ lib/lp/translations/tests/test_doc.py 2018-05-06 14:00:16 +0000
@@ -1,4 +1,4 @@
-# Copyright 2009 Canonical Ltd. This software is licensed under the
+# Copyright 2009-2018 Canonical Ltd. This software is licensed under the
# GNU Affero General Public License version 3 (see the file LICENSE).
"""
@@ -9,6 +9,8 @@
import os
import unittest
+import scandir
+
from lp.testing.layers import (
LaunchpadFunctionalLayer,
LaunchpadZopelessLayer,
@@ -54,11 +56,10 @@
stories_dir = os.path.join(os.path.pardir, 'stories')
suite.addTest(PageTestSuite(stories_dir))
stories_path = os.path.join(here, stories_dir)
- for story_dir in os.listdir(stories_path):
- full_story_dir = os.path.join(stories_path, story_dir)
- if not os.path.isdir(full_story_dir):
+ for story_entry in scandir.scandir(stories_path):
+ if not story_entry.is_dir():
continue
- story_path = os.path.join(stories_dir, story_dir)
+ story_path = os.path.join(stories_dir, story_entry.name)
suite.addTest(PageTestSuite(story_path))
testsdir = os.path.abspath(
=== modified file 'lib/lp/translations/utilities/tests/xpi_helpers.py'
--- lib/lp/translations/utilities/tests/xpi_helpers.py 2010-08-20 20:31:18 +0000
+++ lib/lp/translations/utilities/tests/xpi_helpers.py 2018-05-06 14:00:16 +0000
@@ -1,4 +1,4 @@
-# Copyright 2009 Canonical Ltd. This software is licensed under the
+# Copyright 2009-2018 Canonical Ltd. This software is licensed under the
# GNU Affero General Public License version 3 (see the file LICENSE).
"""Helper methods for XPI testing"""
@@ -15,6 +15,8 @@
from textwrap import dedent
import zipfile
+import scandir
+
import lp.translations
@@ -55,7 +57,7 @@
jar = zipfile.ZipFile(jarfile, 'w')
jarlist = []
data_dir = os.path.join(test_root, 'en-US-jar/')
- for root, dirs, files in os.walk(data_dir):
+ for root, dirs, files in scandir.walk(data_dir):
for name in files:
relative_dir = root[len(data_dir):].strip('/')
jarlist.append(os.path.join(relative_dir, name))
@@ -69,11 +71,10 @@
xpifile = tempfile.TemporaryFile()
xpi = zipfile.ZipFile(xpifile, 'w')
- xpilist = os.listdir(test_root)
- xpilist.remove('en-US-jar')
- for file_name in xpilist:
- f = open(os.path.join(test_root, file_name), 'r')
- xpi.writestr(file_name, f.read())
+ for xpi_entry in scandir.scandir(test_root):
+ if xpi_entry.name != 'en-US-jar':
+ with open(xpi_entry.path) as f:
+ xpi.writestr(xpi_entry.name, f.read())
xpi.writestr('chrome/en-US.jar', jarfile.read())
xpi.close()
xpifile.seek(0)
=== modified file 'scripts/migrate-librarian-content-md5.py'
--- scripts/migrate-librarian-content-md5.py 2012-01-01 03:13:08 +0000
+++ scripts/migrate-librarian-content-md5.py 2018-05-06 14:00:16 +0000
@@ -1,15 +1,20 @@
-#!/usr/bin/env python
-# Copyright 2009 Canonical Ltd. This software is licensed under the
+#!/usr/bin/python -S
+#
+# Copyright 2009-2018 Canonical Ltd. This software is licensed under the
# GNU Affero General Public License version 3 (see the file LICENSE).
"""Script to generate SQL to add MD5 sums for existing librarian files."""
__metaclass__ = type
+import _pythonpath
+
import commands
import os
import sys
+import scandir
+
SQL = "UPDATE LibraryFileContent SET md5 = '%s' WHERE id = %d;"
@@ -18,10 +23,10 @@
if not path.endswith('/'):
path += '/'
- for dirpath, dirname, filenames in os.walk(path):
+ for dirpath, dirname, filenames in scandir.walk(path):
dirname.sort()
databaseID = dirpath[len(path):]
- if not len(databaseID) == 8: # "xx/xx/xx"
+ if not len(databaseID) == 8: # "xx/xx/xx"
continue
for filename in filenames:
databaseID = int(databaseID.replace('/', '') + filename, 16)
@@ -31,6 +36,7 @@
md5sum = commands.getoutput('md5sum ' + filename).split(' ', 1)[0]
yield databaseID, md5sum
+
if __name__ == '__main__':
if len(sys.argv) > 2:
minimumID = int(sys.argv[2])
=== modified file 'setup.py'
--- setup.py 2018-05-06 14:00:16 +0000
+++ setup.py 2018-05-06 14:00:16 +0000
@@ -209,6 +209,7 @@
'rabbitfixture',
'requests',
'requests-toolbelt',
+ 'scandir',
'setproctitle',
'setuptools',
'six',
=== modified file 'utilities/findimports.py'
--- utilities/findimports.py 2012-06-29 08:40:05 +0000
+++ utilities/findimports.py 2018-05-06 14:00:16 +0000
@@ -1,6 +1,6 @@
#!/usr/bin/python
#
-# Copyright 2009 Canonical Ltd. This software is licensed under the
+# Copyright 2009-2018 Canonical Ltd. This software is licensed under the
# GNU Affero General Public License version 3 (see the file LICENSE).
"""
@@ -44,6 +44,8 @@
import os
import sys
+import scandir
+
class ImportFinder(ASTVisitor):
"""AST visitor that collects all imported names in its imports attribute.
@@ -167,7 +169,7 @@
def parsePathname(self, pathname):
if os.path.isdir(pathname):
- for root, dirs, files in os.walk(pathname):
+ for root, dirs, files in scandir.walk(pathname):
for fn in files:
# ignore emacsish junk
if fn.endswith('.py') and not fn.startswith('.#'):
=== modified file 'utilities/format-imports'
--- utilities/format-imports 2012-09-28 06:15:58 +0000
+++ utilities/format-imports 2018-05-06 14:00:16 +0000
@@ -1,6 +1,6 @@
#!/usr/bin/python
#
-# Copyright 2010-2012 Canonical Ltd. This software is licensed under the
+# Copyright 2010-2018 Canonical Ltd. This software is licensed under the
# GNU Affero General Public License version 3 (see the file LICENSE).
""" Format import sections in python files
@@ -133,6 +133,8 @@
import sys
from textwrap import dedent
+import scandir
+
sys.path[0:0] = [os.path.dirname(__file__)]
from python_standard_libs import python_standard_libs
@@ -385,7 +387,7 @@
def process_tree(dpath):
"""Walk a directory tree and process all *.py files."""
- for dirpath, dirnames, filenames in os.walk(dpath):
+ for dirpath, dirnames, filenames in scandir.walk(dpath):
for filename in filenames:
if filename.endswith('.py'):
process_file(os.path.join(dirpath, filename))
Follow ups