- Revision
- 16065
- Author
- heikki
- Date
- 2007-12-06 12:58:23 -0800 (Thu, 06 Dec 2007)
Log Message
Bug 11454, Plugin install fails if no write access to CHANDLERHOME/plugins. Now if we can't install in that dir,
we'll install into $PROFILEDIR/plugins. That part of the patch by vajda, r=heikki.
Since this change could expose users' profile directory in chandler.log, I added code to replace profile dir
part of the log message that is done during plugin install with '$PROFILEDIR' string. r=vajda for this part.
we'll install into $PROFILEDIR/plugins. That part of the patch by vajda, r=heikki.
Since this change could expose users' profile directory in chandler.log, I added code to replace profile dir
part of the log message that is done during plugin install with '$PROFILEDIR' string. r=vajda for this part.
Modified Paths
Added Paths
Diff
Modified: trunk/chandler/application/Plugins.py (16064 => 16065)
--- trunk/chandler/application/Plugins.py 2007-12-06 20:47:27 UTC (rev 16064) +++ trunk/chandler/application/Plugins.py 2007-12-06 20:58:23 UTC (rev 16065) @@ -80,17 +80,45 @@ if archive is not None: options = Globals.options - pluginsDir = options.pluginPath[0] - if not os.path.exists(pluginsDir): - os.makedirs(pluginsDir) + # find writable path on options.pluginPath + # it is assumed that, unless the user changed the defaults, + # that pluginPath contains at least a path relative to CHANDLERHOME + # and another relative to the user's PROFILEDIR, in that order, + # so that plugins are installed in a shared directory (when + # CHANDLERHOME is shared) by default. + + for pluginsDir in options.pluginPath: + try: + if not os.path.exists(pluginsDir): + os.makedirs(pluginsDir) + except OSError: + continue + if os.access(pluginsDir, os.W_OK): + break + else: + raise ValueError, ('no writable path in pluginPath', + options.pluginPath) + try: from setuptools.command.easy_install import main from distutils.log import _global_log - + from util.string_utils import nocase_replace + # patch distutils' logger with logging's # distutils logging levels happen to be one tenth of logging's + # Also ensure that we don't write full profileDir to log, + # which would be a security issue. def log(level, msg, args): + if msg: + if wx.Platform == '__WXMSW__': + msg = nocase_replace(msg, + Globals.options.profileDir, + '$PROFILEDIR') + else: + msg = msg.replace(Globals.options.profileDir, + '$PROFILEDIR') + logger.log(level * 10, msg, *args) _log = _global_log._log
Modified: trunk/chandler/application/Utility.py (16064 => 16065)
--- trunk/chandler/application/Utility.py 2007-12-06 20:47:27 UTC (rev 16064) +++ trunk/chandler/application/Utility.py 2007-12-06 20:58:23 UTC (rev 16065) @@ -17,7 +17,7 @@ """ import os, sys, logging, logging.config, logging.handlers, string, glob -import i18n, schema +import i18n, schema, itertools import M2Crypto.Rand as Rand, M2Crypto.threading as m2threading from optparse import OptionParser from configobj import ConfigObj @@ -265,7 +265,7 @@ # short opt, long opt, type flag, default value, env var, help text COMMAND_LINE_OPTIONS = { 'parcelPath': ('-p', '--parcelPath', 's', None, 'PARCELPATH', 'Parcel search path'), - 'pluginPath': ('' , '--pluginPath', 's', 'plugins', None, 'Plugin search path, relative to CHANDLERHOME'), + 'pluginPath': ('' , '--pluginPath', 's', 'plugins', None, 'Plugin search path, relative to CHANDLERHOME and PROFILEDIR'), 'webserver': ('-W', '--webserver', 'v', [], 'CHANDLERWEBSERVER', 'Activate the built-in webserver'), 'profileDir': ('-P', '--profileDir', 's', '', 'PROFILEDIR', 'location of the Chandler user profile directory (relative to CHANDLERHOME)'), 'testScripts':('-t', '--testScripts','b', False, None, 'run all test scripts'), @@ -462,11 +462,23 @@ value = prefs[name] setattr(options, name, value) - # Resolve pluginPath relative to chandlerDirectory chandlerDirectory = locateChandlerDirectory() - options.pluginPath = [os.path.join(chandlerDirectory, path) - for path in options.pluginPath.split(os.pathsep)] - + + # Resolve pluginPath relative to chandlerDirectory and profileDir + # This means that relative paths in options.pluginPath get expanded + # twice into options.pluginPath, once relative to chandlerDirectory and + # once relative to profileDir, in this order, removing duplicates. + pluginPath = [os.path.expanduser(path) + for path in options.pluginPath.split(os.pathsep)] + options.pluginPath = [] + for path in itertools.chain((os.path.join(chandlerDirectory, path) + for path in pluginPath), + (os.path.join(options.profileDir, path) + for path in pluginPath)): + path = os.path.abspath(os.path.normpath(path)) + if path not in options.pluginPath: + options.pluginPath.append(path) + # Store up the remaining args options.args = args @@ -501,6 +513,8 @@ options.profileDir = os.path.expanduser(profileDir) elif not os.path.isdir(options.profileDir): createProfileDir(options.profileDir) + + options.profileDir = os.path.normpath(options.profileDir) def loadPrefs(options):
Added: trunk/chandler/util/string_utils.py (16064 => 16065)
--- trunk/chandler/util/string_utils.py 2007-12-06 20:47:27 UTC (rev 16064) +++ trunk/chandler/util/string_utils.py 2007-12-06 20:58:23 UTC (rev 16065) @@ -0,0 +1,56 @@ +# Copyright (c) 2007 Open Source Applications Foundation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +def nocase_replace(msg, old, new): + """ + Like str.replace, but case insensitive find. + + >>> s = 'Aabb' + >>> nocase_replace(s, 'a', 'cc') + 'ccccbb' + >>> s = 'Hello World! The WORLD is not Enough!' + >>> nocase_replace(s, 'world', 'Moon') + 'Hello Moon! The Moon is not Enough!' + >>> nocase_replace(s, '', 'Moon') + Traceback (most recent call last): + ... + ValueError: Need a non-empty string to search for + >>> s = '' + >>> nocase_replace(s, 'a', 'cc') + '' + """ + if not old: + raise ValueError('Need a non-empty string to search for') + if not msg: + return msg + + s = msg.lower() + o = old.lower() + ret = [] + i = 0 + j = s.find(o) + oldLen = len(old) + + while j > -1: + ret.append(msg[i:j]) + ret.append(new) + i = j + oldLen + j = s.find(o, i) + ret.append(msg[i:]) + + return ''.join(ret) + +if __name__ == '__main__': + import doctest + doctest.testmod(optionflags=doctest.ELLIPSIS)
_______________________________________________ Commits mailing list [email protected] http://lists.osafoundation.org/mailman/listinfo/commits
