Trees Indices Help
Trac
Package trac :: Module env

Source Code for Module trac.env

 1 # -*- coding: utf-8 -*- 
 2 # 
 3 # Copyright (C) 2003-2009 Edgewall Software 
 4 # Copyright (C) 2003-2007 Jonas Borgström <jonas@edgewall.com> 
 5 # All rights reserved. 
 6 # 
 7 # This software is licensed as described in the file COPYING, which 
 8 # you should have received as part of this distribution. The terms 
 9 # are also available at http://trac.edgewall.org/wiki/TracLicense. 
 10 # 
 11 # This software consists of voluntary contributions made by many 
 12 # individuals. For the exact contribution history, see the revision 
 13 # history and logs, available at http://trac.edgewall.org/log/. 
 14 # 
 15 # Author: Jonas Borgström <jonas@edgewall.com> 
 16 
 17 import os.path  
 18 import setuptools 
 19 import sys 
 20 from urlparse import urlsplit 
 21 
 22 from trac  import db_default  
 23 from trac .admin  import AdminCommandError , IAdminCommandProvider  
 24 from trac .cache  import CacheManager  
 25 from trac .config  import * 
 26 from trac .core  import Component , ComponentManager, implements , Interface , \ 
 27  ExtensionPoint , TracError  
 28 from trac .db .api  import DatabaseManager , get_read_db , with_transaction  
 29 from trac .util  import copytree , create_file , get_pkginfo , makedirs  
 30 from trac .util .compat  import any, sha1 
 31 from trac .util .concurrency  import threading 
 32 from trac .util .text  import exception_to_unicode , path_to_unicode , printerr , \ 
 33  printout  
 34 from trac .util .translation  import _ , N_ 
 35 from trac .versioncontrol  import RepositoryManager  
 36 from trac .web .href  import Href  
 37 
 38 __all__ = ['Environment', 'IEnvironmentSetupParticipant', 'open_environment'] 
39 40 41 - class ISystemInfoProvider (Interface):
42 """Provider of system information, displayed in the "About Trac" page and 43 in internal error reports. 44 """
45 - def get_system_info ():
46 """Yield a sequence of `(name, version)` tuples describing the name and 47 version information of external packages used by a component. 48 """
49
50 51 - class IEnvironmentSetupParticipant (Interface):
52 """Extension point interface for components that need to participate in the 53 creation and upgrading of Trac environments, for example to create 54 additional database tables.""" 55
56 - def environment_created ():
57 """Called when a new Trac environment is created."""
58
60 """Called when Trac checks whether the environment needs to be upgraded. 61 62 Should return `True` if this participant needs an upgrade to be 63 performed, `False` otherwise. 64 """
65
66 - def upgrade_environment (db):
67 """Actually perform an environment upgrade. 68 69 Implementations of this method don't need to commit any database 70 transactions. This is done implicitly for each participant 71 if the upgrade succeeds without an error being raised. 72 73 However, if the `upgrade_environment` consists of small, restartable, 74 steps of upgrade, it can decide to commit on its own after each 75 successful step. 76 """
77
78 79 - class Environment (Component, ComponentManager):
80 """Trac environment manager. 81 82 Trac stores project information in a Trac environment. It consists of a 83 directory structure containing among other things: 84 * a configuration file 85 * an SQLite database (stores tickets, wiki pages...) 86 * project-specific templates and plugins 87 * wiki and ticket attachments 88 """ 89 implements (ISystemInfoProvider) 90 91 required = True 92 93 system_info_providers = ExtensionPoint (ISystemInfoProvider) 94 setup_participants = ExtensionPoint (IEnvironmentSetupParticipant ) 95 96 shared_plugins_dir = PathOption ('inherit', 'plugins_dir', '', 97 """Path to the //shared plugins directory//. 98 99 Plugins in that directory are loaded in addition to those in the 100 directory of the environment `plugins`, with this one taking 101 precedence. 102 103 (''since 0.11'')""") 104 105 base_url = Option ('trac', 'base_url', '', 106 """Reference URL for the Trac deployment. 107 108 This is the base URL that will be used when producing documents that 109 will be used outside of the web browsing context, like for example 110 when inserting URLs pointing to Trac resources in notification 111 e-mails.""") 112 113 base_url_for_redirect = BoolOption ('trac', 'use_base_url_for_redirect', 114 False, 115 """Optionally use `[trac] base_url` for redirects. 116 117 In some configurations, usually involving running Trac behind a HTTP 118 proxy, Trac can't automatically reconstruct the URL that is used to 119 access it. You may need to use this option to force Trac to use the 120 `base_url` setting also for redirects. This introduces the obvious 121 limitation that this environment will only be usable when accessible 122 from that URL, as redirects are frequently used. ''(since 0.10.5)''""") 123 124 secure_cookies = BoolOption ('trac', 'secure_cookies', False, 125 """Restrict cookies to HTTPS connections. 126 127 When true, set the `secure` flag on all cookies so that they are 128 only sent to the server on HTTPS connections. Use this if your Trac 129 instance is only accessible through HTTPS. (''since 0.11.2'')""") 130 131 project_name = Option ('project', 'name', 'My Project', 132 """Name of the project.""") 133 134 project_description = Option ('project', 'descr', 'My example project', 135 """Short description of the project.""") 136 137 project_url = Option ('project', 'url', '', 138 """URL of the main project web site, usually the website in which 139 the `base_url` resides. This is used in notification e-mails.""") 140 141 project_admin = Option ('project', 'admin', '', 142 """E-Mail address of the project's administrator.""") 143 144 project_admin_trac_url = Option ('project', 'admin_trac_url', '.', 145 """Base URL of a Trac instance where errors in this Trac should be 146 reported. 147 148 This can be an absolute or relative URL, or '.' to reference this 149 Trac instance. An empty value will disable the reporting buttons. 150 (''since 0.11.3'')""") 151 152 project_footer = Option ('project', 'footer', 153 N_('Visit the Trac open source project at<br />' 154 '<a href="http://trac.edgewall.org/">' 155 'http://trac.edgewall.org/</a>'), 156 """Page footer text (right-aligned).""") 157 158 project_icon = Option ('project', 'icon', 'common/trac.ico', 159 """URL of the icon of the project.""") 160 161 log_type = Option ('logging', 'log_type', 'none', 162 """Logging facility to use. 163 164 Should be one of (`none`, `file`, `stderr`, `syslog`, `winlog`).""") 165 166 log_file = Option ('logging', 'log_file', 'trac.log', 167 """If `log_type` is `file`, this should be a path to the log-file. 168 Relative paths are resolved relative to the `log` directory of the 169 environment.""") 170 171 log_level = Option ('logging', 'log_level', 'DEBUG', 172 """Level of verbosity in log. 173 174 Should be one of (`CRITICAL`, `ERROR`, `WARN`, `INFO`, `DEBUG`).""") 175 176 log_format = Option ('logging', 'log_format', None, 177 """Custom logging format. 178 179 If nothing is set, the following will be used: 180 181 Trac[$(module)s] $(levelname)s: $(message)s 182 183 In addition to regular key names supported by the Python logger library 184 (see http://docs.python.org/library/logging.html), one could use: 185 - $(path)s the path for the current environment 186 - $(basename)s the last path component of the current environment 187 - $(project)s the project name 188 189 Note the usage of `$(...)s` instead of `%(...)s` as the latter form 190 would be interpreted by the ConfigParser itself. 191 192 Example: 193 `($(thread)d) Trac[$(basename)s:$(module)s] $(levelname)s: $(message)s` 194 195 ''(since 0.10.5)''""") 196
197 - def __init__ (self, path, create=False, options=[]):
198 """Initialize the Trac environment. 199 200 @param path: the absolute path to the Trac environment 201 @param create: if `True`, the environment is created and populated with 202 default data; otherwise, the environment is expected to 203 already exist. 204 @param options: A list of `(section, name, value)` tuples that define 205 configuration options 206 """ 207 ComponentManager.__init__ (self) 208 209 self.path = path 210 self.systeminfo = [] 211 self._href = self._abs_href = None 212 213 if create : 214 self.create (options ) 215 else: 216 self.verify () 217 self.setup_config () 218 219 if create : 220 for setup_participant in self.setup_participants : 221 setup_participant.environment_created ()
222
223 - def get_systeminfo (self):
224 """Return a list of `(name, version)` tuples describing the name and 225 version information of external packages used by Trac and plugins. 226 """ 227 info = self.systeminfo[:] 228 for provider in self.system_info_providers : 229 info.extend(provider.get_system_info () or []) 230 info.sort(key=lambda (name , version ): (name != 'Trac', name .lower())) 231 return info
232 233 # ISystemInfoProvider methods 234
235 - def get_system_info (self):
236 from trac import core , __version__ as VERSION 237 yield 'Trac', get_pkginfo (core ).get ('version', VERSION) 238 yield 'Python', sys.version 239 yield 'setuptools', setuptools.__version__ 240 from trac .util .datefmt import pytz 241 if pytz is not None: 242 yield 'pytz', pytz.__version__
243
244 - def component_activated (self, component):
245 """Initialize additional member variables for components. 246 247 Every component activated through the `Environment` object gets three 248 member variables: `env` (the environment object), `config` (the 249 environment configuration) and `log` (a logger object).""" 250 component.env = self 251 component.config = self.config 252 component.log = self.log
253
254 - def _component_name (self, name_or_class):
255 name = name_or_class 256 if not isinstance(name_or_class, basestring): 257 name = name_or_class.__module__ + '.' + name_or_class.__name__ 258 return name .lower()
259 260 @property
261 - def _component_rules (self):
262 try: 263 return self._rules 264 except AttributeError: 265 self._rules = {} 266 for name , value in self.config .options ('components'): 267 if name .endswith('.*'): 268 name = name [:-2] 269 self._rules[name .lower()] = value.lower() in ('enabled', 'on') 270 return self._rules
271
272 - def is_component_enabled (self, cls):
273 """Implemented to only allow activation of components that are not 274 disabled in the configuration. 275 276 This is called by the `ComponentManager` base class when a component is 277 about to be activated. If this method returns `False`, the component 278 does not get activated. If it returns `None`, the component only gets 279 activated if it is located in the `plugins` directory of the 280 enironment. 281 """ 282 component_name = self._component_name(cls) 283 284 # Disable the pre-0.11 WebAdmin plugin 285 # Please note that there's no recommendation to uninstall the 286 # plugin because doing so would obviously break the backwards 287 # compatibility that the new integration administration 288 # interface tries to provide for old WebAdmin extensions 289 if component_name.startswith('webadmin.'): 290 self.log .info('The legacy TracWebAdmin plugin has been ' 291 'automatically disabled, and the integrated ' 292 'administration interface will be used ' 293 'instead.') 294 return False 295 296 rules = self._component_rules 297 cname = component_name 298 while cname: 299 enabled = rules .get (cname) 300 if enabled is not None: 301 return enabled 302 idx = cname.rfind('.') 303 if idx < 0: 304 break 305 cname = cname[:idx] 306 307 # By default, all components in the trac package except 308 # trac.test are enabled 309 return component_name.startswith('trac.') and \ 310 not component_name.startswith('trac.test.') or None
311
312 - def enable_component (self, cls):
313 """Enable a component or module.""" 314 self._component_rules[self._component_name(cls)] = True
315
316 - def verify (self):
317 """Verify that the provided path points to a valid Trac environment 318 directory.""" 319 fd = open (os.path .join (self.path , 'VERSION'), 'r') 320 try: 321 assert fd.read (26) == 'Trac Environment Version 1' 322 finally: 323 fd.close ()
324
325 - def get_db_cnx (self):
326 """Return a database connection from the connection pool (deprecated) 327 328 Use `with_transaction` for obtaining a writable database connection 329 and `get_read_db` for anything else. 330 """ 331 return get_read_db (self)
332
333 - def with_transaction (self, db=None):
334 """Decorator for transaction functions. 335 336 See `trac.db.api.with_transaction` for detailed documentation.""" 337 return with_transaction (self, db )
338
339 - def get_read_db (self):
340 """Return a database connection for read purposes. 341 342 See `trac.db.api.get_read_db` for detailed documentation.""" 343 return get_read_db (self)
344
345 - def shutdown (self, tid=None):
346 """Close the environment.""" 347 RepositoryManager (self).shutdown (tid) 348 DatabaseManager (self).shutdown (tid) 349 if tid is None: 350 self.log .removeHandler(self._log_handler) 351 self._log_handler.flush() 352 self._log_handler.close () 353 del self._log_handler
354
355 - def get_repository (self, reponame=None, authname=None):
356 """Return the version control repository with the given name, or the 357 default repository if `None`. 358 359 The standard way of retrieving repositories is to use the methods 360 of `RepositoryManager`. This method is retained here for backward 361 compatibility. 362 363 @param reponame: the name of the repository 364 @param authname: the user name for authorization (not used anymore, 365 left here for compatibility with 0.11) 366 """ 367 return RepositoryManager (self).get_repository (reponame)
368
369 - def create (self, options=[]):
370 """Create the basic directory structure of the environment, initialize 371 the database and populate the configuration file with default values. 372 373 If options contains ('inherit', 'file'), default values will not be 374 loaded; they are expected to be provided by that file or other options. 375 """ 376 # Create the directory structure 377 if not os.path .exists (self.path ): 378 os.mkdir(self.path ) 379 os.mkdir(self.get_log_dir ()) 380 os.mkdir(self.get_htdocs_dir ()) 381 os.mkdir(os.path .join (self.path , 'plugins')) 382 383 # Create a few files 384 create_file (os.path .join (self.path , 'VERSION'), 385 'Trac Environment Version 1\n') 386 create_file (os.path .join (self.path , 'README'), 387 'This directory contains a Trac environment.\n' 388 'Visit http://trac.edgewall.org/ for more information.\n') 389 390 # Setup the default configuration 391 os.mkdir(os.path .join (self.path , 'conf')) 392 create_file (os.path .join (self.path , 'conf', 'trac.ini.sample')) 393 config = Configuration (os.path .join (self.path , 'conf', 'trac.ini')) 394 for section, name , value in options : 395 config .set (section, name , value) 396 config .save () 397 self.setup_config () 398 if not any((section, option) == ('inherit', 'file') 399 for section, option, value in options ): 400 self.config .set_defaults (self) 401 self.config .save () 402 403 # Create the database 404 DatabaseManager (self).init_db ()
405
406 - def get_version (self, db=None, initial=False):
407 """Return the current version of the database. 408 If the optional argument `initial` is set to `True`, the version 409 of the database used at the time of creation will be returned. 410 411 In practice, for database created before 0.11, this will return `False` 412 which is "older" than any db version number. 413 414 :since 0.11: 415 """ 416 if not db : 417 db = self.get_db_cnx () 418 cursor = db .cursor () 419 cursor .execute ("SELECT value FROM system " 420 "WHERE name='%sdatabase_version'" % 421 (initial and 'initial_' or '')) 422 row = cursor .fetchone () 423 return row and int(row[0])
424
425 - def setup_config (self):
426 """Load the configuration file.""" 427 self.config = Configuration (os.path .join (self.path , 'conf', 428 'trac.ini')) 429 self.setup_log () 430 from trac .loader import load_components 431 plugins_dir = self.shared_plugins_dir 432 load_components (self, plugins_dir and (plugins_dir,))
433
434 - def get_templates_dir (self):
435 """Return absolute path to the templates directory.""" 436 return os.path .join (self.path , 'templates')
437
438 - def get_htdocs_dir (self):
439 """Return absolute path to the htdocs directory.""" 440 return os.path .join (self.path , 'htdocs')
441
442 - def get_log_dir (self):
443 """Return absolute path to the log directory.""" 444 return os.path .join (self.path , 'log')
445
446 - def setup_log (self):
447 """Initialize the logging sub-system.""" 448 from trac .log import logger_handler_factory 449 logtype = self.log_type 450 logfile = self.log_file 451 if logtype == 'file' and not os.path .isabs(logfile ): 452 logfile = os.path .join (self.get_log_dir (), logfile ) 453 format = self.log_format 454 logid = 'Trac.%s' % sha1(self.path ).hexdigest() 455 if format : 456 format = format .replace ('$(', '%(') \ 457 .replace ('%(path)s', self.path ) \ 458 .replace ('%(basename)s', os.path .basename(self.path )) \ 459 .replace ('%(project)s', self.project_name ) 460 self.log , self._log_handler = logger_handler_factory ( 461 logtype, logfile , self.log_level , logid, format =format ) 462 from trac import core , __version__ as VERSION 463 self.log .info('-' * 32 + ' environment startup [Trac %s] ' + '-' * 32, 464 get_pkginfo (core ).get ('version', VERSION))
465
466 - def get_known_users (self, cnx=None):
467 """Generator that yields information about all known users, i.e. users 468 that have logged in to this Trac environment and possibly set their name 469 and email. 470 471 This function generates one tuple for every user, of the form 472 (username, name, email) ordered alpha-numerically by username. 473 474 @param cnx: the database connection; if ommitted, a new connection is 475 retrieved 476 """ 477 if not cnx : 478 cnx = self.get_db_cnx () 479 cursor = cnx .cursor () 480 cursor .execute ("SELECT DISTINCT s.sid, n.value, e.value " 481 "FROM session AS s " 482 " LEFT JOIN session_attribute AS n ON (n.sid=s.sid " 483 " and n.authenticated=1 AND n.name = 'name') " 484 " LEFT JOIN session_attribute AS e ON (e.sid=s.sid " 485 " AND e.authenticated=1 AND e.name = 'email') " 486 "WHERE s.authenticated=1 ORDER BY s.sid") 487 for username , name , email in cursor : 488 yield username , name , email
489
490 - def backup (self, dest=None):
491 """Create a backup of the database. 492 493 @param dest: Destination file; if not specified, the backup is stored in 494 a file called db_name.trac_version.bak 495 """ 496 return DatabaseManager (self).backup (dest)
497
498 - def needs_upgrade (self):
499 """Return whether the environment needs to be upgraded.""" 500 db = self.get_db_cnx () 501 for participant in self.setup_participants : 502 if participant.environment_needs_upgrade (db ): 503 self.log .warning('Component %s requires environment upgrade', 504 participant) 505 return True 506 return False
507
508 - def upgrade (self, backup=False, backup_dest=None):
509 """Upgrade database. 510 511 @param backup: whether or not to backup before upgrading 512 @param backup_dest: name of the backup file 513 @return: whether the upgrade was performed 514 """ 515 upgraders = [] 516 db = self.get_read_db () 517 for participant in self.setup_participants : 518 if participant.environment_needs_upgrade (db ): 519 upgraders.append(participant) 520 if not upgraders: 521 return 522 523 if backup : 524 self.backup (backup_dest) 525 526 for participant in upgraders: 527 self.log .info("%s.%s upgrading...", participant.__module__, 528 participant.__class__.__name__) 529 with_transaction (self)(participant.upgrade_environment ) 530 # Database schema may have changed, so close all connections 531 DatabaseManager (self).shutdown () 532 return True
533 534 @property
535 - def href (self):
536 """The application root path""" 537 if not self._href: 538 self._href = Href (urlsplit(self.abs_href .base)[2]) 539 return self._href
540 541 @property
542 - def abs_href (self):
543 """The application URL""" 544 if not self._abs_href: 545 if not self.base_url : 546 self.log .warn('base_url option not set in configuration, ' 547 'generated links may be incorrect') 548 self._abs_href = Href ('') 549 else: 550 self._abs_href = Href (self.base_url ) 551 return self._abs_href
552
553 554 - class EnvironmentSetup (Component):
555 """Manage automatic environment upgrades.""" 556 557 required = True 558 559 implements (IEnvironmentSetupParticipant ) 560 561 # IEnvironmentSetupParticipant methods 562
563 - def environment_created (self):
564 """Insert default data into the database.""" 565 @self.env .with_transaction () 566 def do_db_populate(db): 567 cursor = db .cursor () 568 for table, cols, vals in db_default .get_data (db ): 569 cursor .executemany ("INSERT INTO %s (%s) VALUES (%s)" 570 % (table, ','.join (cols), 571 ','.join (['%s' for c in cols])), 572 vals)
573 self._update_sample_config()
574
575 - def environment_needs_upgrade (self, db):
576 dbver = self.env .get_version (db ) 577 if dbver == db_default .db_version : 578 return False 579 elif dbver > db_default .db_version : 580 raise TracError (_ ('Database newer than Trac version')) 581 self.log .info("Trac database schema version is %d, should be %d", 582 dbver, db_default .db_version ) 583 return True
584
585 - def upgrade_environment (self, db):
586 """Each db version should have its own upgrade module, named 587 upgrades/dbN.py, where 'N' is the version number (int). 588 """ 589 cursor = db .cursor () 590 dbver = self.env .get_version () 591 for i in range(dbver + 1, db_default .db_version + 1): 592 name = 'db%i' % i 593 try: 594 upgrades = __import__('upgrades', globals(), locals(), [name ]) 595 script = getattr(upgrades , name ) 596 except AttributeError: 597 raise TracError (_ ('No upgrade module for version %(num)i ' 598 '(%(version)s.py)', num=i , version =name )) 599 script.do_upgrade (self.env , i , cursor ) 600 cursor .execute (""" 601 UPDATE system SET value=%s WHERE name='database_version' 602 """, (i ,)) 603 self.log .info('Upgraded database version from %d to %d', i - 1, i ) 604 db .commit () 605 self._update_sample_config()
606 607 # Internal methods 608
609 - def _update_sample_config (self):
610 filename = os.path .join (self.env .path , 'conf', 'trac.ini.sample') 611 if not os.path .isfile (filename ): 612 return 613 config = Configuration (filename ) 614 for section, default_options in config .defaults ().iteritems(): 615 for name , value in default_options.iteritems(): 616 config .set (section, name , value) 617 try: 618 config .save () 619 self.log .info('Wrote sample configuration file with the new ' 620 'settings and their default values: %s', 621 filename ) 622 except IOError, e : 623 self.log .warn('Couldn\'t write sample configuration file (%s)', e , 624 exc_info=True)
625 626 627 env_cache = {} 628 env_cache_lock = threading.Lock()
629 630 - def open_environment (env_path=None, use_cache=False):
631 """Open an existing environment object, and verify that the database is up 632 to date. 633 634 @param env_path: absolute path to the environment directory; if ommitted, 635 the value of the `TRAC_ENV` environment variable is used 636 @param use_cache: whether the environment should be cached for subsequent 637 invocations of this function 638 @return: the `Environment` object 639 """ 640 if not env_path: 641 env_path = os.getenv('TRAC_ENV') 642 if not env_path: 643 raise TracError (_ ('Missing environment variable "TRAC_ENV". ' 644 'Trac requires this variable to point to a valid ' 645 'Trac environment.')) 646 647 env_path = os.path .normcase(os.path .normpath(env_path)) 648 if use_cache: 649 env_cache_lock .acquire() 650 try: 651 env = env_cache .get (env_path) 652 if env and env .config .parse_if_needed (): 653 # The environment configuration has changed, so shut it down 654 # and remove it from the cache so that it gets reinitialized 655 env .log .info('Reloading environment due to configuration ' 656 'change') 657 env .shutdown () 658 del env_cache [env_path] 659 env = None 660 if env is None: 661 env = env_cache .setdefault(env_path, open_environment (env_path)) 662 else: 663 CacheManager (env ).reset_metadata () 664 finally: 665 env_cache_lock .release() 666 else: 667 env = Environment (env_path) 668 needs_upgrade = False 669 try: 670 needs_upgrade = env .needs_upgrade () 671 except Exception, e : # e.g. no database connection 672 env .log .error ("Exception caught while checking for upgrade: %s", 673 exception_to_unicode (e , traceback=True)) 674 if needs_upgrade : 675 raise TracError (_ ('The Trac Environment needs to be upgraded.\n\n' 676 'Run "trac-admin %(path)s upgrade"', 677 path =env_path)) 678 679 return env
680
681 682 - class EnvironmentAdmin (Component):
683 """trac-admin command provider for environment administration.""" 684 685 implements (IAdminCommandProvider ) 686 687 # IAdminCommandProvider methods 688
689 - def get_admin_commands (self):
690 yield ('deploy', '<directory>', 691 'Extract static resources from Trac and all plugins', 692 None, self._do_deploy) 693 yield ('hotcopy', '<backupdir>', 694 'Make a hot backup copy of an environment', 695 None, self._do_hotcopy) 696 yield ('upgrade', '', 697 'Upgrade database to current version', 698 None, self._do_upgrade)
699
700 - def _do_deploy (self, dest):
701 target = os.path .normpath(dest) 702 chrome_target = os.path .join (target, 'htdocs') 703 script_target = os.path .join (target, 'cgi-bin') 704 705 # Copy static content 706 makedirs (target, overwrite=True) 707 makedirs (chrome_target, overwrite=True) 708 from trac .web .chrome import Chrome 709 printout (_ ("Copying resources from:")) 710 for provider in Chrome (self.env ).template_providers : 711 paths = list(provider.get_htdocs_dirs () or []) 712 if not len(paths): 713 continue 714 printout (' %s.%s' % (provider.__module__, 715 provider.__class__.__name__)) 716 for key, root in paths: 717 source = os.path .normpath(root) 718 printout (' ', source) 719 if os.path .exists (source): 720 dest = os.path .join (chrome_target, key) 721 copytree (source, dest, overwrite=True) 722 723 # Create and copy scripts 724 makedirs (script_target, overwrite=True) 725 printout (_ ("Creating scripts.")) 726 data = {'env': self.env , 'executable': sys.executable} 727 for script in ('cgi', 'fcgi', 'wsgi'): 728 dest = os.path .join (script_target, 'trac.' + script) 729 template = Chrome (self.env ).load_template ('deploy_trac.' + script, 730 'text') 731 stream = template.generate(**data ) 732 out = file(dest, 'w') 733 try: 734 stream.render ('text', out=out, encoding='utf-8') 735 finally: 736 out.close ()
737
738 - def _do_hotcopy (self, dest):
739 if os.path .exists (dest): 740 raise TracError (_ ("hotcopy can't overwrite existing '%(dest)s'", 741 dest=path_to_unicode (dest))) 742 import shutil 743 744 # Bogus statement to lock the database while copying files 745 cnx = self.env .get_db_cnx () 746 cursor = cnx .cursor () 747 cursor .execute ("UPDATE system SET name=NULL WHERE name IS NULL") 748 749 try: 750 printout (_ ('Hotcopying %(src)s to %(dst)s ...', 751 src=path_to_unicode (self.env .path ), 752 dst =path_to_unicode (dest))) 753 db_str = self.env .config .get ('trac', 'database') 754 prefix, db_path = db_str.split(':', 1) 755 if prefix == 'sqlite': 756 # don't copy the journal (also, this would fail on Windows) 757 db = os.path .join (self.env .path , os.path .normpath(db_path)) 758 skip = [db + '-journal', db + '-stmtjrnl'] 759 else: 760 skip = [] 761 try: 762 copytree (self.env .path , dest, symlinks=1, skip=skip) 763 retval = 0 764 except shutil.Error , e : 765 retval = 1 766 printerr (_ ('The following errors happened while copying ' 767 'the environment:')) 768 for (src, dst , err) in e .args [0]: 769 if src in err: 770 printerr (' %s' % err) 771 else: 772 printerr (" %s: '%s'" % (err, path_to_unicode (src))) 773 finally: 774 # Unlock database 775 cnx .rollback () 776 777 printout (_ ("Hotcopy done.")) 778 return retval
779
780 - def _do_upgrade (self, no_backup=None):
781 if no_backup not in (None, '-b', '--no-backup'): 782 raise AdminCommandError (_ ("Invalid arguments"), show_usage=True) 783 784 if not self.env .needs_upgrade (): 785 printout (_ ("Database is up to date, no upgrade necessary.")) 786 return 787 788 try: 789 self.env .upgrade (backup =no_backup is None) 790 except TracError , e : 791 raise TracError (_ ("Backup failed: %(msg)s.\nUse '--no-backup' to " 792 "upgrade without doing a backup.", 793 msg=unicode(e ))) 794 795 # Remove wiki-macros if it is empty and warn if it isn't 796 wiki_macros = os.path .join (self.env .path , 'wiki-macros') 797 try: 798 entries = os.listdir(wiki_macros) 799 except OSError: 800 pass 801 else: 802 if entries: 803 printerr (_ ("Warning: the wiki-macros directory in the " 804 "environment is non-empty, but Trac\n" 805 "doesn't load plugins from there anymore. " 806 "Please remove it by hand.")) 807 else: 808 try: 809 os.rmdir(wiki_macros) 810 except OSError, e : 811 printerr (_ ("Error while removing wiki-macros: %(err)s\n" 812 "Trac doesn't load plugins from wiki-macros " 813 "anymore. Please remove it by hand.", 814 err=exception_to_unicode (e ))) 815 816 printout (_ ("Upgrade done.\n\n" 817 "You may want to upgrade the Trac documentation now by " 818 "running:\n\n trac-admin %(path)s wiki upgrade", 819 path =path_to_unicode (self.env .path )))
820
Trees Indices Help
Trac
Generated by Epydoc 3.0.1 on Mon Feb 13 23:37:29 2023 http://epydoc.sourceforge.net

AltStyle によって変換されたページ (->オリジナル) /