def insert(self): """Insert a new component. """ assert not self.exists, "Cannot insert existing component" self.name = simplify_whitespace(self.name) if not self.name: raise TracError(_("Invalid component name.")) with self.env.db_transaction as db: self.env.log.debug("Creating new component '%s'", self.name) db( """INSERT INTO component (name,owner,description) VALUES (%s,%s,%s) """, (self.name, self.owner, self.description)) self._old_name = self.name TicketSystem(self.env).reset_ticket_fields()
def delete(self, resources_to=None): """ override the delete method so that we can move references to this object to a new product """ if resources_to is not None: new_product = Product(self._env, resources_to) if not new_product._exists: sdata = {'new_table': resources_to} sdata.update(self._meta) raise TracError( '%(object_name)s %(new_table)s does not exist' % sdata) super(Product, self).delete() #find and update all resources that should move where = {'product_id': self._data['prefix']} for prm in ProductResourceMap.select(self._env, where=where): prm._data['product_id'] = resources_to prm.update()
def _do_upgrade(self, no_backup=None): if no_backup not in (None, '-b', '--no-backup'): raise AdminCommandError(_("Invalid arguments"), show_usage=True) if not self.env.needs_upgrade(): printout(_("Database is up to date, no upgrade necessary.")) return try: self.env.upgrade(backup=no_backup is None) except TracError, e: raise TracError( _( "Backup failed: %(msg)s.\nUse '--no-backup' to " "upgrade without doing a backup.", msg=unicode(e)))
def _upgrade_db(self, db): try: from trac.db import DatabaseManager db_backend, _ = DatabaseManager(self.env)._get_connector() cursor = db.cursor() cursor.execute(""" DELETE FROM session_attribute WHERE name = %s """, ("breadcrumbs list",) ) except Exception, e: db.rollback() self.log.error(e, exc_info=True) raise TracError(str(e))
def setup_log(self): self.log = logging.getLogger('trac.test') level = self.log_level.upper() level_as_int = trac.log.LOG_LEVEL_MAP.get(level) self.log.setLevel(level_as_int) handler_cls = logging.handlers.BufferingHandler if not self.log.handlers: log_handler = handler_cls(sys.maxsize) # Never flush implicitly. formatter = logging.Formatter(self.log_format) log_handler.setFormatter(formatter) self.log.addHandler(log_handler) elif len(self.log.handlers) == 1 and \ isinstance(self.log.handlers[0], handler_cls): self.log.handlers[0].flush() # Reset buffer. else: raise TracError("Logger has unexpected handler(s).")
def _get_file(self, filename): # Open file and get its size file = open(filename, 'rb') size = os.fstat(file.fileno())[6] # Check non-emtpy file. if size == 0: raise TracError('Can\'t upload empty file.') # Try to normalize the filename to unicode NFC if we can. # Files uploaded from OS X might be in NFD. filename = unicodedata.normalize('NFC', to_unicode(filename, 'utf-8')) filename = filename.replace('\\', '/').replace(':', '/') filename = os.path.basename(filename) return file, filename, size
def expand_macro(self, formatter, name, content): if content: arg = content.strip().split() doc = getattr(TracAdmin, "_help_" + arg[0], None) if doc is None: cmd_mgr = AdminCommandManager(self.env) doc = cmd_mgr.get_command_help(arg) if not doc: raise TracError( _('Unknown trac-admin command "%(command)s"', command=content)) else: doc = TracAdmin.all_docs(self.env) buf = StringIO.StringIO() TracAdmin.print_doc(doc, buf, long=True) return html.PRE(buf.getvalue().decode('utf-8'), class_='wiki')
def backup(self, dest_file): """Simple SQLite-specific backup of the database. @param dest_file: Destination file basename """ import shutil db_str = self.config.get('trac', 'database') try: db_str = db_str[:db_str.index('?')] except ValueError: pass db_name = os.path.join(self.env.path, db_str[7:]) shutil.copy(db_name, dest_file) if not os.path.exists(dest_file): raise TracError(_("No destination file created")) return dest_file
def __setitem__(self, name, value): """Log ticket modifications so the table ticket_change can be updated """ if name in self.values and self.values[name] == value: return if name not in self._old: # Changed field self._old[name] = self.values.get(name) elif self._old[name] == value: # Change of field reverted del self._old[name] if value: if isinstance(value, list): raise TracError(_("Multi-values fields not supported yet")) field = [field for field in self.fields if field['name'] == name] if field and field[0].get('type') != 'textarea': value = value.strip() self.values[name] = value
def restore_component_registry(self): """Restore the component registry. The component registry must have been cleared and saved using the `clear_component_registry` method. :since: 1.0.11 :since 1.3.2: Deprecated and will be removed in 1.5.1. Create components in `setUpClass` and remove them in `tearDownClass` using `ComponentMeta.deregister`. """ if self._old_registry is None: raise TracError("The clear_component_registry method must be " "called first.") ComponentMeta._registry = self._old_registry ComponentMeta._components = self._old_components
def create_header(key, name, charset): """Create an appropriate email Header.""" maxlength = MAXHEADERLEN-(len(key)+2) # Do not sent ridiculous short headers if maxlength < 10: raise TracError(_("Header length is too short")) # when it matches mime-encoding, encode as mime even if only # ascii characters if not _mime_encoding_re.search(name): try: tmp = name.encode('ascii') return Header(tmp, 'ascii', maxlinelen=maxlength) except UnicodeEncodeError: pass return Header(name.encode(charset.output_codec), charset, maxlinelen=maxlength)
def upgrade_environment(self, db=None): """Each schema version should have its own upgrade module, named upgrades/dbN.py, where 'N' is the version number (int). """ db_mgr = DatabaseManager(self.env) schema_ver = self.get_schema_version() with self.env.db_transaction as db: # Is this a new installation? if not schema_ver: # Perform a single-step install: Create plugin schema and # insert default data into the database. connector = db_mgr.get_connector()[0] for table in db_default.schema: for stmt in connector.to_sql(table): db(stmt) for table, cols, vals in db_default.get_data(db): db.executemany( "INSERT INTO %s (%s) VALUES (%s)" % (table, ','.join(cols), ','.join(['%s'] * len(cols))), vals) else: # Perform incremental upgrades. for i in range(schema_ver + 1, db_default.schema_version + 1): name = 'db%i' % i try: upgrades = __import__('tractags.upgrades', globals(), locals(), [name]) script = getattr(upgrades, name) except AttributeError: raise TracError( _( "No upgrade module for version " "%(num)i (%(version)s.py)", num=i, version=name)) cursor = db.cursor() script.do_upgrade(self.env, i, cursor) db( """UPDATE `system` SET value=%s WHERE name='tags_version' """, (db_default.schema_version, )) self.log.info("Upgraded TracTags db schema from version %d to %d", schema_ver, db_default.schema_version) TicketTagProvider(self.env)._fetch_tkt_tags() self.log.info("Synchronized ticket attributes to tags table")
def do_transaction(db): cursor = db.cursor() invalidate = False # -- check that we're populating the cache for the correct # repository repository_dir = metadata.get(CACHE_REPOSITORY_DIR) if repository_dir: # directory part of the repo name can vary on case insensitive # fs if os.path.normcase(repository_dir) \ != os.path.normcase(self.name): self.log.info("'repository_dir' has changed from %r to %r", repository_dir, self.name) raise TracError( _( "The repository directory has changed, " "you should resynchronize the " "repository with: trac-admin $ENV " "repository resync '%(reponame)s'", reponame=self.reponame or '(default)')) elif repository_dir is None: # self.log.info('Storing initial "repository_dir": %s', self.name) cursor.execute( """ INSERT INTO repository (id,name,value) VALUES (%s,%s,%s) """, (self.id, CACHE_REPOSITORY_DIR, self.name)) invalidate = True else: # 'repository_dir' cleared by a resync self.log.info('Resetting "repository_dir": %s', self.name) cursor.execute( """ UPDATE repository SET value=%s WHERE id=%s AND name=%s """, (self.name, self.id, CACHE_REPOSITORY_DIR)) invalidate = True # -- insert a 'youngeset_rev' for the repository if necessary if metadata.get(CACHE_YOUNGEST_REV) is None: cursor.execute( """ INSERT INTO repository (id,name,value) VALUES (%s,%s,%s) """, (self.id, CACHE_YOUNGEST_REV, '')) invalidate = True if invalidate: del self.metadata
def get_changes(self, old_path, old_rev, new_path, new_rev, ignore_ancestry=0): # TODO: handle renames/copies, ignore_ancestry old_path = self.normalize_path(old_path) new_path = self.normalize_path(new_path) if old_path != new_path: raise TracError(_("Not supported in git_fs")) old_rev = self.normalize_rev(old_rev) new_rev = self.normalize_rev(new_rev) if old_rev == new_rev: return def get_tree(rev): results = self.git.ls_tree(rev, target_path, recursive=True) return {result[4]: result for result in results} def is_dir(mode): return mode.startswith('04') target_path = old_path.strip('/') old_tree = get_tree(old_rev) new_tree = get_tree(new_rev) with self.git.get_historian(old_rev, target_path) as old_historian: with self.git.get_historian(new_rev, target_path) as new_historian: for chg in self.git.diff_tree(old_rev, new_rev, target_path): mode1, mode2, obj1, obj2, action, path, path2 = chg kind = Node.DIRECTORY \ if is_dir(mode2) or is_dir(mode1) \ else Node.FILE change = GitChangeset.action_map[action] old_node = self._get_node(path, old_rev, old_tree.get(path, False), old_historian) \ if change != Changeset.ADD else None new_node = self._get_node(path, new_rev, new_tree.get(path, False), new_historian) \ if change != Changeset.DELETE else None yield old_node, new_node, kind, change
def process_request(self, req): """Override for TicketModule process_request""" ticketid = req.args.get('id') productid = req.args.get('productid', '') ticket = Ticket(self.env, ticketid) if ticketid: if (req.path_info == '/products/' + productid + '/newticket' or req.path_info == '/products'): raise TracError(_("id can't be set for a new ticket request.")) ticket = Ticket(self.env, ticketid) if productid and ticket['product'] != req.args.get('product', ''): msg = "Ticket %(id)s in product '%(prod)' does not exist." raise ResourceNotFound(_(msg, id=ticketid, prod=productid), _("Invalid ticket number")) return self._process_ticket_request(req) return self._process_newticket_request(req)
def upgrade_environment(self, db): self.log.debug("Upgrading download plugin environment") cursor = db.cursor() # Get current database schema version db_version = self._get_db_version(cursor) # Perform incremental upgrades try: for I in range(db_version + 1, last_db_version + 1): script_name = 'db%i' % (I) module = __import__('tracdownloads.db.%s' % (script_name), globals(), locals(), ['do_upgrade']) module.do_upgrade(self.env, cursor) db.commit() except: raise TracError("Upgrading download plugin environment failed") finally: cursor.close()
def _remove_membership_req(self, username): user = get_userstore().getUser(username) if not user: raise TracError('User cannot be found with name: "%s"' % username) query = """ DELETE FROM membership_request WHERE project_key = %s AND user_key = %s """ with admin_transaction() as cursor: try: cursor.execute(query, (self.project.id, user.id)) except: self.env.log.exception( "Exception. MembershipApi._remove_membership_req query failed. '''%s'''" % query)
def get_changeset(self, rev): self.log.debug('get_changeset(%r)' % rev) if isinstance(rev, int): change = rev else: from p4trac.util import toUnicode rev = toUnicode(rev) if rev.startswith(u'@'): rev = rev[1:] try: change = int(rev) except ValueError: raise TracError(u"Invalid changeset number '%s'" % rev) return PerforceChangeset(change, self._repos, self.log, self._job_prefix_length)
def process_request(self, req): """ Handles the request :param req: Request :return: json """ if req.method != 'POST': raise TracError('Invalid request') req.perm.require('TIMELINE_VIEW') userstore = get_userstore() watchstore = CQDEWatchlistStore() action = req.args.get('action') project_id = 0 # Determine project id from URL match = REQ_REGEXP.match(req.path_info) if match: project_id = int(match.group('pid')) # Load userinfo user = userstore.getUser(req.authname) uid = user.id if user else None #load project project = Project.get(id=project_id) # Start following if action == 'watch': watchstore.watch_project(uid, project_id) # Notify listeners. for listener in self.project_change_listeners: try: listener.project_watchers(project) except: pass # Stop following elif action == 'unwatch': watchstore.unwatch_project(uid, project_id) goto = req.args.get('goto', req.href('')) return req.redirect(goto)
def insert(self, db=None): """Insert a new version. :since 1.0: the `db` parameter is no longer needed and will be removed in version 1.1.1 """ assert not self.exists, "Cannot insert existing version" self.name = simplify_whitespace(self.name) if not self.name: raise TracError(_("Invalid version name.")) with self.env.db_transaction as db: self.env.log.debug("Creating new version '%s'", self.name) db("INSERT INTO version (name,time,description) VALUES (%s,%s,%s)", (self.name, to_utimestamp(self.time), self.description)) self._old_name = self.name TicketSystem(self.env).reset_ticket_fields()
def delete(self): """Deletes the matching record from the database""" if not self._exists: raise TracError('%(object_name)s does not exist' % self._meta) where, values = fields_to_kv_str(self._env, self._key_fields, self._data) sdata = {'where': where} sdata.update(self._meta) sql = """DELETE FROM %(table_name)s WHERE %(where)s""" % sdata with self._env.db_transaction as db: db(sql, values) self._exists = False TicketSystem(self._env).reset_ticket_fields() ResourceSystem(self._env).resource_deleted(self) self._data = dict([(k, None) for k in self._data.keys()]) self._old_data.update(self._data)
def send(self, from_addr, recipients, message): global local_hostname # Ensure the message complies with RFC2822: use CRLF line endings message = fix_eol(message, CRLF) self.log.info("Sending notification through SMTP at %s:%d to %s", self.smtp_server, self.smtp_port, recipients) try: server = smtplib.SMTP(self.smtp_server, self.smtp_port, local_hostname) local_hostname = server.local_hostname except smtplib.socket.error as e: raise ConfigurationError( tag_("SMTP server connection error (%(error)s). Please " "modify %(option1)s or %(option2)s in your " "configuration.", error=to_unicode(e), option1=tag.code("[notification] smtp_server"), option2=tag.code("[notification] smtp_port"))) # server.set_debuglevel(True) if self.use_tls: server.ehlo() if 'starttls' not in server.esmtp_features: raise TracError(_("TLS enabled but server does not support" " TLS")) server.starttls() server.ehlo() if self.smtp_user: server.login(self.smtp_user.encode('utf-8'), self.smtp_password.encode('utf-8')) start = time_now() server.sendmail(from_addr, recipients, message) t = time_now() - start if t > 5: self.log.warning("Slow mail submission (%.2f s), " "check your mail setup", t) if self.use_tls: # avoid false failure detection when the server closes # the SMTP connection with TLS enabled import socket try: server.quit() except socket.sslerror: pass else: server.quit()
def update_session_id(db): cursor = db.cursor() cursor.execute("SELECT sid FROM session WHERE sid=%s", (new_sid,)) if cursor.fetchone(): raise TracError(_("Session '%(id)s' already exists. " "Please choose a different session ID.", id=new_sid), _("Error renaming session")) self.env.log.debug('Changing session ID %s to %s', self.sid, new_sid) cursor.execute(""" UPDATE session SET sid=%s WHERE sid=%s AND authenticated=0 """, (new_sid, self.sid)) cursor.execute(""" UPDATE session_attribute SET sid=%s WHERE sid=%s and authenticated=0 """, (new_sid, self.sid))
def __init__(self, path, log=None, params={}): if have_pysqlite == 0: raise TracError(_("Cannot load Python bindings for SQLite")) self.cnx = None if path != ':memory:': if not os.access(path, os.F_OK): raise ConfigurationError( _('Database "%(path)s" not found.', path=path)) dbdir = os.path.dirname(path) if not os.access(path, os.R_OK + os.W_OK) or \ not os.access(dbdir, os.R_OK + os.W_OK): raise ConfigurationError( tag_( "The user %(user)s requires read _and_ write permissions " "to the database file %(path)s and the directory it is " "located in.", user=tag.tt(getuser()), path=tag.tt(path))) self._active_cursors = weakref.WeakKeyDictionary() timeout = int(params.get('timeout', 10.0)) self._eager = params.get('cursor', 'eager') == 'eager' # eager is default, can be turned off by specifying ?cursor= if isinstance(path, unicode): # needed with 2.4.0 path = path.encode('utf-8') cnx = sqlite.connect(path, detect_types=sqlite.PARSE_DECLTYPES, isolation_level=None, check_same_thread=sqlite_version < (3, 3, 1), timeout=timeout) # load extensions extensions = params.get('extensions', []) if len(extensions) > 0: cnx.enable_load_extension(True) for ext in extensions: cnx.load_extension(ext) cnx.enable_load_extension(False) cursor = cnx.cursor() _set_journal_mode(cursor, params.get('journal_mode')) _set_synchronous(cursor, params.get('synchronous')) cursor.close() cnx.isolation_level = 'DEFERRED' ConnectionWrapper.__init__(self, cnx, log)
def __init__(self, repos, path, rev, log, ls_tree_info=None, historian=None): self.log = log self.repos = repos self.fs_sha = None # points to either tree or blobs self.fs_perm = None self.fs_size = None if rev: rev = repos.normalize_rev(to_unicode(rev)) else: rev = repos.youngest_rev created_rev = rev kind = Node.DIRECTORY p = path.strip('/') if p: # ie. not the root-tree if not rev: raise NoSuchNode(path, rev) if ls_tree_info is None: ls_tree_info = repos.git.ls_tree(rev, p) if ls_tree_info: ls_tree_info = ls_tree_info[0] if not ls_tree_info: raise NoSuchNode(path, rev) self.fs_perm, k, self.fs_sha, self.fs_size, fname = ls_tree_info # fix-up to the last commit-rev that touched this node created_rev = repos.git.last_change(rev, p, historian) if k == 'tree': pass elif k == 'commit': # FIXME: this is a workaround for missing git submodule # support in the plugin pass elif k == 'blob': kind = Node.FILE else: raise TracError(_("Internal error (got unexpected object " "kind '%(kind)s')", kind=k)) self.created_path = path self.created_rev = created_rev Node.__init__(self, repos, path, rev, kind)
def pre_process_request(self, req, handler): """pre process request filter""" pid = None match = PRODUCT_RE.match(req.path_info) if match: dispatcher = self.env[RequestDispatcher] if dispatcher is None: raise TracError('Unable to load RequestDispatcher.') pid = match.group('pid') if pid: products = Product.select(self.env, where={'prefix': pid}) if pid and len(products) == 1: req.args['productid'] = pid req.args['product'] = products[0].name if handler is self and match.group('pathinfo') not in ('', '/'): # select a new handler environ = req.environ.copy() pathinfo = environ['PATH_INFO'].split('/') pathinfo = '/'.join(pathinfo[:1] + pathinfo[3:]) environ['PATH_INFO'] = pathinfo newreq = Request(environ, lambda *args, **kwds: None) new_handler = None for hndlr in dispatcher.handlers: if hndlr is not self and hndlr.match_request(newreq): new_handler = hndlr req.args.update(newreq.args) break if new_handler is None: if req.path_info.endswith('/'): target = req.path_info.rstrip('/').encode('utf-8') if req.query_string: target += '?' + req.query_string req.redirect(req.href + target, permanent=True) raise HTTPNotFound('No handler matched request to %s', req.path_info) handler = new_handler else: raise ResourceNotFound( _("Product %(id)s does not exist.", id=pid), _("Invalid product id")) return handler
def default(self, line): try: if not self.__env: self._init_env() if self.needs_upgrade is None: self.needs_upgrade = self.__env.needs_upgrade() except TracError as e: raise AdminCommandError(to_unicode(e)) except Exception as e: raise AdminCommandError(exception_to_unicode(e)) args = self.arg_tokenize(line) if args[0] == 'upgrade': self.needs_upgrade = None elif self.needs_upgrade: raise TracError(_('The Trac Environment needs to be upgraded.\n\n' 'Run "trac-admin %(path)s upgrade"', path=self.envname)) return self.cmd_mgr.execute_command(*args)
def insert(self, db=None): """Insert a new component. :since 0.13: the `db` parameter is no longer needed and will be removed in version 0.14 """ assert not self.exists, "Cannot insert existing component" self.name = simplify_whitespace(self.name) if not self.name: raise TracError(_("Invalid component name.")) with self.env.db_transaction as db: self.env.log.debug("Creating new component '%s'", self.name) db("""INSERT INTO component (name,owner,description) VALUES (%s,%s,%s) """, (self.name, self.owner, self.description)) self._old_name = self.name TicketSystem(self.env).reset_ticket_fields()
def show_html_timeline(self, req): """ Returns the HTML output """ content = self.cache.get_global_timeline(req.authname) # Re-render content if not found in cache if not content: try: content = self.render_content_html(req) self.cache.set_global_timeline(req.authname, content) except Exception as e: self.log.exception('Failed to show timeline: %s' % e) raise TracError('Failed to show timeline') data = {'content': HTML(content)} return 'globaltimeline.html', data, None
def do_upgrade(env, db, version, pkg=__package__, new_version=__version__): completed = True i = 1 while completed: try: script_path = '%s.config.config%i' % (pkg, i) module = __import__(script_path, globals(), locals(), ['do_upgrade']) completed = completed and module.do_upgrade(env, db, version) i += 1 except ImportError: break if completed: set_version(db, pkg, new_version) else: raise TracError( "[%s]: Upgrade was not complete! Check log for details..." % __package__)