# HG changeset patch
# Parent 252f94e03103dec9f9ec19e2fcee898c8d172db8
#9536: use `with` for automatically closing files and releasing locks.
Also, made `trac.util.AtomicFile` a context manager.
diff -r 252f94e03103 trac/admin/console.py
|
a
|
b
|
|
| 12 | 12 | # individuals. For the exact contribution history, see the revision |
| 13 | 13 | # history and logs, available at http://trac.edgewall.org/log/. |
| 14 | 14 | |
| | 15 | from __future__ import with_statement |
| | 16 | |
| 15 | 17 | import cmd |
| 16 | 18 | import locale |
| 17 | 19 | import os.path |
| … |
… |
def find_readline_lib(): |
| 44 | 46 | linked to the readline module. |
| 45 | 47 | """ |
| 46 | 48 | import readline |
| 47 | | f = open(readline.__file__, "rb") |
| 48 | | try: |
| | 49 | with open(readline.__file__, "rb") as f: |
| 49 | 50 | data = f.read() |
| 50 | | finally: |
| 51 | | f.close() |
| 52 | 51 | import re |
| 53 | 52 | m = re.search('\0([^\0]*libreadline[^\0]*)\0', data) |
| 54 | 53 | if m: |
diff -r 252f94e03103 trac/admin/web_ui.py
|
a
|
b
|
|
| 14 | 14 | # |
| 15 | 15 | # Author: Jonas Borgström <jonas@edgewall.com> |
| 16 | 16 | |
| | 17 | from __future__ import with_statement |
| | 18 | |
| 17 | 19 | from functools import partial |
| 18 | 20 | import os |
| 19 | 21 | import pkg_resources |
| … |
… |
class PluginAdminPanel(Component): |
| 477 | 479 | except AttributeError: |
| 478 | 480 | # OS_BINARY not available on every platform |
| 479 | 481 | pass |
| 480 | | target_file = os.fdopen(os.open(target_path, flags, 0666), 'w') |
| 481 | | try: |
| | 482 | with os.fdopen(os.open(target_path, flags, 0666), 'w') as target_file: |
| 482 | 483 | shutil.copyfileobj(upload.file, target_file) |
| 483 | 484 | self.log.info('Plugin %s installed to %s', plugin_filename, |
| 484 | 485 | target_path) |
| 485 | | finally: |
| 486 | | target_file.close() |
| 487 | | |
| 488 | 486 | # TODO: Validate that the uploaded file is actually a valid Trac plugin |
| 489 | 487 | |
| 490 | 488 | # Make the environment reset itself on the next request |
diff -r 252f94e03103 trac/attachment.py
|
a
|
b
|
class Attachment(object): |
| 265 | 265 | filename = unicode_quote(filename) |
| 266 | 266 | path, targetfile = create_unique_file(os.path.join(self.path, |
| 267 | 267 | filename)) |
| 268 | | try: |
| | 268 | with targetfile: |
| 269 | 269 | # Note: `path` is an unicode string because `self.path` was one. |
| 270 | 270 | # As it contains only quoted chars and numbers, we can use `ascii` |
| 271 | 271 | basename = os.path.basename(path).encode('ascii') |
| … |
… |
class Attachment(object): |
| 281 | 281 | |
| 282 | 282 | self.env.log.info("New attachment: %s by %s", self.title, |
| 283 | 283 | self.author) |
| 284 | | finally: |
| 285 | | targetfile.close() |
| 286 | 284 | |
| 287 | 285 | for listener in AttachmentModule(self.env).change_listeners: |
| 288 | 286 | listener.attachment_added(self) |
| … |
… |
class AttachmentModule(Component): |
| 725 | 723 | 'title': get_resource_name(self.env, attachment.resource), |
| 726 | 724 | 'attachment': attachment} |
| 727 | 725 | |
| 728 | | fd = attachment.open() |
| 729 | | try: |
| | 726 | with attachment.open() as fd: |
| 730 | 727 | mimeview = Mimeview(self.env) |
| 731 | 728 | |
| 732 | 729 | # MIME type detection |
| … |
… |
class AttachmentModule(Component): |
| 775 | 772 | os.fstat(fd.fileno()).st_size, mime_type, |
| 776 | 773 | attachment.filename, raw_href, annotations=['lineno']) |
| 777 | 774 | return data |
| 778 | | finally: |
| 779 | | fd.close() |
| 780 | 775 | |
| 781 | 776 | def _format_link(self, formatter, ns, target, label): |
| 782 | 777 | link, params, fragment = formatter.split_link(target) |
| … |
… |
class AttachmentAdmin(Component): |
| 946 | 941 | attachment = Attachment(self.env, realm, id) |
| 947 | 942 | attachment.author = author |
| 948 | 943 | attachment.description = description |
| 949 | | f = open(path, 'rb') |
| 950 | | try: |
| | 944 | with open(path, 'rb') as f: |
| 951 | 945 | attachment.insert(os.path.basename(path), f, os.path.getsize(path)) |
| 952 | | finally: |
| 953 | | f.close() |
| 954 | 946 | |
| 955 | 947 | def _do_remove(self, resource, name): |
| 956 | 948 | (realm, id) = self.split_resource(resource) |
| … |
… |
class AttachmentAdmin(Component): |
| 966 | 958 | if os.path.isfile(destination): |
| 967 | 959 | raise AdminCommandError(_("File '%(name)s' exists", |
| 968 | 960 | name=destination)) |
| 969 | | input = attachment.open() |
| 970 | | try: |
| | 961 | with attachment.open() as input: |
| 971 | 962 | output = (destination is None) and sys.stdout \ |
| 972 | 963 | or open(destination, "wb") |
| 973 | 964 | try: |
| … |
… |
class AttachmentAdmin(Component): |
| 975 | 966 | finally: |
| 976 | 967 | if destination is not None: |
| 977 | 968 | output.close() |
| 978 | | finally: |
| 979 | | input.close() |
| 980 | 969 | |
diff -r 252f94e03103 trac/config.py
|
a
|
b
|
|
| 12 | 12 | # individuals. For the exact contribution history, see the revision |
| 13 | 13 | # history and logs, available at http://trac.edgewall.org/log/. |
| 14 | 14 | |
| | 15 | from __future__ import with_statement |
| | 16 | |
| 15 | 17 | from ConfigParser import ConfigParser |
| 16 | 18 | from copy import deepcopy |
| 17 | 19 | import os.path |
| … |
… |
class Configuration(object): |
| 231 | 233 | |
| 232 | 234 | # At this point, all the strings in `sections` are UTF-8 encoded `str` |
| 233 | 235 | try: |
| 234 | | fileobj = AtomicFile(self.filename, 'w') |
| 235 | | try: |
| | 236 | with AtomicFile(self.filename, 'w') as fileobj: |
| 236 | 237 | fileobj.write('# -*- coding: utf-8 -*-\n\n') |
| 237 | 238 | for section, options in sections: |
| 238 | 239 | fileobj.write('[%s]\n' % section) |
| … |
… |
class Configuration(object): |
| 244 | 245 | .replace('\n', '\n ') |
| 245 | 246 | fileobj.write('%s = %s\n' % (key_str, val_str)) |
| 246 | 247 | fileobj.write('\n') |
| 247 | | finally: |
| 248 | | fileobj.close() |
| 249 | 248 | self._old_sections = deepcopy(self.parser._sections) |
| 250 | 249 | except Exception: |
| 251 | 250 | # Revert all changes to avoid inconsistencies |
diff -r 252f94e03103 trac/env.py
|
a
|
b
|
class Environment(Component, ComponentMa |
| 350 | 350 | def verify(self): |
| 351 | 351 | """Verify that the provided path points to a valid Trac environment |
| 352 | 352 | directory.""" |
| 353 | | fd = open(os.path.join(self.path, 'VERSION'), 'r') |
| 354 | | try: |
| | 353 | with open(os.path.join(self.path, 'VERSION'), 'r') as fd: |
| 355 | 354 | assert fd.read(26) == 'Trac Environment Version 1' |
| 356 | | finally: |
| 357 | | fd.close() |
| 358 | 355 | |
| 359 | 356 | def get_db_cnx(self): |
| 360 | 357 | """Return a database connection from the connection pool |
| … |
… |
def open_environment(env_path=None, use_ |
| 754 | 751 | |
| 755 | 752 | env_path = os.path.normcase(os.path.normpath(env_path)) |
| 756 | 753 | if use_cache: |
| 757 | | env_cache_lock.acquire() |
| 758 | | try: |
| | 754 | with env_cache_lock: |
| 759 | 755 | env = env_cache.get(env_path) |
| 760 | 756 | if env and env.config.parse_if_needed(): |
| 761 | 757 | # The environment configuration has changed, so shut it down |
| … |
… |
def open_environment(env_path=None, use_ |
| 769 | 765 | env = env_cache.setdefault(env_path, open_environment(env_path)) |
| 770 | 766 | else: |
| 771 | 767 | CacheManager(env).reset_metadata() |
| 772 | | finally: |
| 773 | | env_cache_lock.release() |
| 774 | 768 | else: |
| 775 | 769 | env = Environment(env_path) |
| 776 | 770 | needs_upgrade = False |
| … |
… |
class EnvironmentAdmin(Component): |
| 841 | 835 | template = Chrome(self.env).load_template('deploy_trac.' + script, |
| 842 | 836 | 'text') |
| 843 | 837 | stream = template.generate(**data) |
| 844 | | out = file(dest, 'w') |
| 845 | | try: |
| | 838 | with open(dest, 'w') as out: |
| 846 | 839 | stream.render('text', out=out) |
| 847 | | finally: |
| 848 | | out.close() |
| 849 | 840 | |
| 850 | 841 | def _do_hotcopy(self, dest, no_db=None): |
| 851 | 842 | if no_db not in (None, '--no-database'): |
diff -r 252f94e03103 trac/tests/config.py
|
a
|
b
|
|
| 12 | 12 | # individuals. For the exact contribution history, see the revision |
| 13 | 13 | # history and logs, available at http://trac.edgewall.org/log/. |
| 14 | 14 | |
| | 15 | from __future__ import with_statement |
| | 16 | |
| 15 | 17 | import os |
| 16 | 18 | import tempfile |
| 17 | 19 | import time |
| … |
… |
class ConfigurationTestCase(unittest.Tes |
| 39 | 41 | return Configuration(self.filename) |
| 40 | 42 | |
| 41 | 43 | def _write(self, lines): |
| 42 | | fileobj = open(self.filename, 'w') |
| 43 | | try: |
| | 44 | with open(self.filename, 'w') as fileobj: |
| 44 | 45 | fileobj.write(('\n'.join(lines + [''])).encode('utf-8')) |
| 45 | | finally: |
| 46 | | fileobj.close() |
| 47 | 46 | |
| 48 | 47 | def test_default(self): |
| 49 | 48 | config = self._read() |
| … |
… |
class ConfigurationTestCase(unittest.Tes |
| 433 | 432 | |
| 434 | 433 | def _test_with_inherit(self, testcb): |
| 435 | 434 | sitename = os.path.join(tempfile.gettempdir(), 'trac-site.ini') |
| 436 | | sitefile = open(sitename, 'w') |
| 437 | 435 | try: |
| 438 | | try: |
| | 436 | with open(sitename, 'w') as sitefile: |
| 439 | 437 | sitefile.write('[a]\noption = x\n') |
| 440 | | finally: |
| 441 | | sitefile.close() |
| 442 | 438 | |
| 443 | 439 | self._write(['[inherit]', 'file = trac-site.ini']) |
| 444 | 440 | testcb() |
diff -r 252f94e03103 trac/util/__init__.py
|
a
|
b
|
|
| 17 | 17 | # Author: Jonas Borgström <jonas@edgewall.com> |
| 18 | 18 | # Matthew Good <trac@matt-good.net> |
| 19 | 19 | |
| | 20 | from __future__ import with_statement |
| | 21 | |
| 20 | 22 | import errno |
| 21 | 23 | import inspect |
| 22 | 24 | from itertools import izip, tee |
| … |
… |
class AtomicFile(object): |
| 181 | 183 | |
| 182 | 184 | def __getattr__(self, name): |
| 183 | 185 | return getattr(self._file, name) |
| 184 | | |
| | 186 | |
| 185 | 187 | def commit(self): |
| 186 | 188 | if self._file is None: |
| 187 | 189 | return |
| … |
… |
class AtomicFile(object): |
| 204 | 206 | os.unlink(self._temp) |
| 205 | 207 | except: |
| 206 | 208 | pass |
| 207 | | |
| | 209 | |
| 208 | 210 | close = commit |
| 209 | 211 | __del__ = rollback |
| 210 | 212 | |
| | 213 | def __enter__(self): |
| | 214 | return self |
| | 215 | |
| | 216 | def __exit__(self, exc_type, exc_value, traceback): |
| | 217 | self.close() |
| | 218 | |
| | 219 | closed = property(lambda self: self._file is None or self._file.closed) |
| | 220 | |
| 211 | 221 | |
| 212 | 222 | def read_file(path, mode='r'): |
| 213 | 223 | """Read a file and return its content.""" |
| … |
… |
def read_file(path, mode='r'): |
| 220 | 230 | |
| 221 | 231 | def create_file(path, data='', mode='w'): |
| 222 | 232 | """Create a new file with the given data.""" |
| 223 | | f = open(path, mode) |
| 224 | | try: |
| | 233 | with open(path, mode) as f: |
| 225 | 234 | if data: |
| 226 | 235 | f.write(data) |
| 227 | | finally: |
| 228 | | f.close() |
| 229 | 236 | |
| 230 | 237 | |
| 231 | 238 | def create_unique_file(path): |
diff -r 252f94e03103 trac/util/daemon.py
|
a
|
b
|
|
| 11 | 11 | # individuals. For the exact contribution history, see the revision |
| 12 | 12 | # history and logs, available at http://trac.edgewall.org/log/. |
| 13 | 13 | |
| | 14 | from __future__ import with_statement |
| | 15 | |
| 14 | 16 | import atexit |
| 15 | 17 | import errno |
| 16 | 18 | import os |
| … |
… |
def daemonize(pidfile=None, progname=Non |
| 26 | 28 | # process running |
| 27 | 29 | pidfile = os.path.abspath(pidfile) |
| 28 | 30 | if os.path.exists(pidfile): |
| 29 | | fileobj = open(pidfile) |
| 30 | | try: |
| | 31 | with open(pidfile) as fileobj: |
| 31 | 32 | try: |
| 32 | 33 | pid = int(fileobj.read()) |
| 33 | 34 | except ValueError: |
| 34 | 35 | sys.exit('Invalid PID in file %s' % pidfile) |
| 35 | | finally: |
| 36 | | fileobj.close() |
| 37 | 36 | |
| 38 | 37 | try: # signal the process to see if it is still running |
| 39 | 38 | os.kill(pid, 0) |
| … |
… |
def daemonize(pidfile=None, progname=Non |
| 80 | 79 | if os.path.exists(pidfile): |
| 81 | 80 | os.remove(pidfile) |
| 82 | 81 | atexit.register(remove_pidfile) |
| 83 | | fileobj = open(pidfile, 'w') |
| 84 | | try: |
| | 82 | with open(pidfile, 'w') as fileobj: |
| 85 | 83 | fileobj.write(str(os.getpid())) |
| 86 | | finally: |
| 87 | | fileobj.close() |
| 88 | 84 | |
| 89 | 85 | |
| 90 | 86 | def handle_signal(signum, frame): |
diff -r 252f94e03103 trac/util/dist.py
|
a
|
b
|
|
| 11 | 11 | # individuals. For the exact contribution history, see the revision |
| 12 | 12 | # history and logs, available at http://trac.edgewall.org/log/. |
| 13 | 13 | |
| | 14 | from __future__ import with_statement |
| | 15 | |
| 14 | 16 | """Extra commands for setup.py. |
| 15 | 17 | |
| 16 | 18 | In addition to providing a few extra command classes in `l10n_cmdclass`, |
| … |
… |
try: |
| 131 | 133 | log.info('generating messages javascript %r to %r', |
| 132 | 134 | mo_file, js_file) |
| 133 | 135 | |
| 134 | | infile = open(mo_file, 'rb') |
| 135 | | try: |
| | 136 | with open(mo_file, 'rb') as infile: |
| 136 | 137 | t = Translations(infile, self.domain) |
| 137 | 138 | catalog = t._catalog |
| 138 | | finally: |
| 139 | | infile.close() |
| 140 | 139 | |
| 141 | | outfile = open(js_file, 'w') |
| 142 | | try: |
| | 140 | with open(js_file, 'w') as outfile: |
| 143 | 141 | write_js(outfile, catalog, self.domain, locale) |
| 144 | | finally: |
| 145 | | outfile.close() |
| 146 | 142 | |
| 147 | 143 | def write_js(fileobj, catalog, domain, locale): |
| 148 | 144 | data = {'domain': domain, 'locale': locale} |
diff -r 252f94e03103 trac/util/tests/__init__.py
|
a
|
b
|
|
| 11 | 11 | # individuals. For the exact contribution history, see the revision |
| 12 | 12 | # history and logs, available at http://trac.edgewall.org/log/. |
| 13 | 13 | |
| | 14 | from __future__ import with_statement |
| | 15 | |
| 14 | 16 | import doctest |
| 15 | 17 | import os.path |
| 16 | 18 | import random |
| … |
… |
class AtomicFileTestCase(unittest.TestCa |
| 33 | 35 | pass |
| 34 | 36 | |
| 35 | 37 | def test_non_existing(self): |
| 36 | | f = util.AtomicFile(self.path) |
| 37 | | try: |
| | 38 | with util.AtomicFile(self.path) as f: |
| 38 | 39 | f.write('test content') |
| 39 | | finally: |
| 40 | | f.close() |
| | 40 | self.assertEqual(True, f.closed) |
| 41 | 41 | self.assertEqual('test content', util.read_file(self.path)) |
| 42 | 42 | |
| 43 | 43 | def test_existing(self): |
| 44 | 44 | util.create_file(self.path, 'Some content') |
| 45 | 45 | self.assertEqual('Some content', util.read_file(self.path)) |
| 46 | | f = util.AtomicFile(self.path) |
| 47 | | try: |
| | 46 | with util.AtomicFile(self.path) as f: |
| 48 | 47 | f.write('Some new content') |
| 49 | | finally: |
| 50 | | f.close() |
| | 48 | self.assertEqual(True, f.closed) |
| 51 | 49 | self.assertEqual('Some new content', util.read_file(self.path)) |
| 52 | 50 | |
| 53 | 51 | if util.can_rename_open_file: |
| 54 | 52 | def test_existing_open_for_reading(self): |
| 55 | 53 | util.create_file(self.path, 'Initial file content') |
| 56 | 54 | self.assertEqual('Initial file content', util.read_file(self.path)) |
| 57 | | rf = open(self.path) |
| 58 | | try: |
| 59 | | f = util.AtomicFile(self.path) |
| 60 | | try: |
| | 55 | with open(self.path) as rf: |
| | 56 | with util.AtomicFile(self.path) as f: |
| 61 | 57 | f.write('Replaced content') |
| 62 | | finally: |
| 63 | | f.close() |
| 64 | | finally: |
| 65 | | rf.close() |
| | 58 | self.assertEqual(True, rf.closed) |
| | 59 | self.assertEqual(True, f.closed) |
| 66 | 60 | self.assertEqual('Replaced content', util.read_file(self.path)) |
| 67 | 61 | |
| 68 | 62 | # FIXME: It is currently not possible to make this test pass on all |
| … |
… |
class AtomicFileTestCase(unittest.TestCa |
| 73 | 67 | # we require Python 3. |
| 74 | 68 | def _test_unicode_path(self): |
| 75 | 69 | self.path = os.path.join(tempfile.gettempdir(), u'träc-témpfilè') |
| 76 | | f = util.AtomicFile(self.path) |
| 77 | | try: |
| | 70 | with util.AtomicFile(self.path) as f: |
| 78 | 71 | f.write('test content') |
| 79 | | finally: |
| 80 | | f.close() |
| | 72 | self.assertEqual(True, f.closed) |
| 81 | 73 | self.assertEqual('test content', util.read_file(self.path)) |
| 82 | 74 | |
| 83 | 75 | |
diff -r 252f94e03103 trac/util/translation.py
|
a
|
b
|
|
| 11 | 11 | # individuals. For the exact contribution history, see the revision |
| 12 | 12 | # history and logs, available at http://trac.edgewall.org/log/. |
| 13 | 13 | |
| | 14 | from __future__ import with_statement |
| | 15 | |
| 14 | 16 | """Utilities for text translation with gettext.""" |
| 15 | 17 | |
| 16 | 18 | import pkg_resources |
| … |
… |
try: |
| 128 | 130 | # Public API |
| 129 | 131 | |
| 130 | 132 | def add_domain(self, domain, env_path, locales_dir): |
| 131 | | self._plugin_domains_lock.acquire() |
| 132 | | try: |
| | 133 | with self._plugin_domains_lock: |
| 133 | 134 | if env_path not in self._plugin_domains: |
| 134 | 135 | self._plugin_domains[env_path] = [] |
| 135 | 136 | self._plugin_domains[env_path].append((domain, locales_dir)) |
| 136 | | finally: |
| 137 | | self._plugin_domains_lock.release() |
| 138 | 137 | |
| 139 | 138 | def make_activable(self, get_locale, env_path=None): |
| 140 | 139 | self._current.args = (get_locale, env_path) |
| … |
… |
try: |
| 149 | 148 | if not t or t.__class__ is NullTranslations: |
| 150 | 149 | t = self._null_translations |
| 151 | 150 | elif env_path: |
| 152 | | self._plugin_domains_lock.acquire() |
| 153 | | try: |
| | 151 | with self._plugin_domains_lock: |
| 154 | 152 | domains = list(self._plugin_domains.get(env_path, [])) |
| 155 | | finally: |
| 156 | | self._plugin_domains_lock.release() |
| 157 | 153 | for domain, dirname in domains: |
| 158 | 154 | t.add(Translations.load(dirname, locale, domain)) |
| 159 | 155 | self._current.translations = t |
diff -r 252f94e03103 trac/versioncontrol/api.py
|
a
|
b
|
class RepositoryManager(Component): |
| 594 | 594 | |
| 595 | 595 | def reload_repositories(self): |
| 596 | 596 | """Reload the repositories from the providers.""" |
| 597 | | self._lock.acquire() |
| 598 | | try: |
| | 597 | with self._lock: |
| 599 | 598 | # FIXME: trac-admin doesn't reload the environment |
| 600 | 599 | self._cache = {} |
| 601 | 600 | self._all_repositories = None |
| 602 | | finally: |
| 603 | | self._lock.release() |
| 604 | 601 | self.config.touch() # Force environment reload |
| 605 | 602 | |
| 606 | 603 | def notify(self, event, reponame, revs): |
| … |
… |
class RepositoryManager(Component): |
| 650 | 647 | def shutdown(self, tid=None): |
| 651 | 648 | if tid: |
| 652 | 649 | assert tid == threading._get_ident() |
| 653 | | try: |
| 654 | | self._lock.acquire() |
| | 650 | with self._lock: |
| 655 | 651 | repositories = self._cache.pop(tid, {}) |
| 656 | 652 | for reponame, repos in repositories.iteritems(): |
| 657 | 653 | repos.close() |
| 658 | | finally: |
| 659 | | self._lock.release() |
| 660 | 654 | |
| 661 | 655 | # private methods |
| 662 | 656 | |
diff -r 252f94e03103 trac/web/auth.py
|
a
|
b
|
class PasswordFileAuthentication(HTTPAut |
| 265 | 265 | self._lock = threading.Lock() |
| 266 | 266 | |
| 267 | 267 | def check_reload(self): |
| 268 | | self._lock.acquire() |
| 269 | | try: |
| | 268 | with self._lock: |
| 270 | 269 | mtime = os.stat(self.filename).st_mtime |
| 271 | 270 | if mtime > self.mtime: |
| 272 | 271 | self.mtime = mtime |
| 273 | 272 | self.load(self.filename) |
| 274 | | finally: |
| 275 | | self._lock.release() |
| 276 | 273 | |
| 277 | 274 | |
| 278 | 275 | class BasicAuthentication(PasswordFileAuthentication): |
diff -r 252f94e03103 trac/web/chrome.py
|
a
|
b
|
|
| 14 | 14 | # |
| 15 | 15 | # Author: Christopher Lenz <cmlenz@gmx.de> |
| 16 | 16 | |
| | 17 | from __future__ import with_statement |
| | 18 | |
| 17 | 19 | """Content presentation for the web layer. |
| 18 | 20 | |
| 19 | 21 | The Chrome module deals with delivering and shaping content to the end user, |
| … |
… |
class Chrome(Component): |
| 485 | 487 | os.mkdir(templates_dir) |
| 486 | 488 | |
| 487 | 489 | site_path = os.path.join(templates_dir, 'site.html.sample') |
| 488 | | fileobj = open(site_path, 'w') |
| 489 | | try: |
| | 490 | with open(site_path, 'w') as fileobj: |
| 490 | 491 | fileobj.write("""\ |
| 491 | 492 | <html xmlns="http://www.w3.org/1999/xhtml" |
| 492 | 493 | xmlns:xi="http://www.w3.org/2001/XInclude" |
| … |
… |
class Chrome(Component): |
| 504 | 505 | --> |
| 505 | 506 | </html> |
| 506 | 507 | """) |
| 507 | | finally: |
| 508 | | fileobj.close() |
| 509 | 508 | |
| 510 | 509 | def environment_needs_upgrade(self, db): |
| 511 | 510 | return False |
diff -r 252f94e03103 trac/web/modpython_frontend.py
|
a
|
b
|
|
| 16 | 16 | # Author: Christopher Lenz <cmlenz@gmx.de> |
| 17 | 17 | # Matthew Good <trac@matt-good.net> |
| 18 | 18 | |
| | 19 | from __future__ import with_statement |
| | 20 | |
| 19 | 21 | import os |
| 20 | 22 | import pkg_resources |
| 21 | 23 | import sys |
| … |
… |
_first_lock = threading.Lock() |
| 126 | 128 | |
| 127 | 129 | def handler(req): |
| 128 | 130 | global _first |
| 129 | | try: |
| 130 | | _first_lock.acquire() |
| | 131 | with _first_lock: |
| 131 | 132 | if _first: |
| 132 | 133 | _first = False |
| 133 | 134 | options = req.get_options() |
| … |
… |
def handler(req): |
| 141 | 142 | if egg_cache: |
| 142 | 143 | pkg_resources.set_extraction_path(egg_cache) |
| 143 | 144 | reload(sys.modules['trac.web']) |
| 144 | | finally: |
| 145 | | _first_lock.release() |
| 146 | 145 | pkg_resources.require('Trac==%s' % VERSION) |
| 147 | 146 | gateway = ModPythonGateway(req, req.get_options()) |
| 148 | 147 | from trac.web.main import dispatch_request |
diff -r 252f94e03103 trac/wiki/admin.py
|
a
|
b
|
class WikiAdmin(Component): |
| 106 | 106 | if os.path.isfile(filename): |
| 107 | 107 | raise AdminCommandError(_("File '%(name)s' exists", |
| 108 | 108 | name=filename)) |
| 109 | | f = open(filename, 'w') |
| 110 | | try: |
| | 109 | with open(filename, 'w') as f: |
| 111 | 110 | f.write(text.encode('utf-8')) |
| 112 | | finally: |
| 113 | | f.close() |
| 114 | 111 | break |
| 115 | 112 | else: |
| 116 | 113 | raise AdminCommandError(_("Page '%(page)s' not found", page=page)) |