def globally_execute_command(self, *args): offset = 0 max_index = -1 if args and args[0].isdigit(): offset = int(args[0]) if len(args) > 1 and args[1].isdigit(): limit = int(args[1]) max_index = limit + offset args = args[2:] else: args = args[1:] upgrade_check = False env_list = False if args and args[0] == 'upgrade-check': upgrade_check = True elif args and args[0] == 'list-env': env_list = True sys_home_project_name = self.config.get('multiproject', 'sys_home_project_name') for index, row in enumerate(self.projects_iterator(['env_name'], batch_size=10)): env_name, = row if index < offset: continue if max_index != -1 and index >= max_index: break if env_name == sys_home_project_name: continue if env_list: printout("{0:4} env:'{1}'".format(index, env_name)) continue env = None try: env_path = safe_path(self.config.get('multiproject', 'sys_projects_root'), env_name) env = Environment(env_path) except TracError as e: printout(_('ERROR: Opening environment %(env_name)s failed', env_name=env_name)) continue if upgrade_check: if env.needs_upgrade(): printout("[+] {0:4} env:'{1}'".format(index, env_name)) else: printout("[ ] {0:4} env:'{1}'".format(index, env_name)) continue # To setup MultiProject specific things like 'project_identifier' MultiProjectEnvironmentInit(env).environment_needs_upgrade(None) try: command_manager = AdminCommandManager(env) printout(_("{0:4} Run in env:'{1}'".format(index, env_name))) command_manager.execute_command(*args) except AdminCommandError as e: printout(_('ERROR: Executing command in environment %(env_name)s failed: ', env_name=env_name) + str(e))
def getPostgreSQLEnvironment(opts): """ Create an Environment connected to the PostgreSQL database """ dburi = opts.pg_uri env = Environment(opts.tracenv) env.config.set('trac', 'database', dburi) try: cnx = env.get_db_cnx() cur = cnx.cursor() cur.execute("select value from system where name = 'database_version'"); except ProgrammingError: cnx.rollback() DatabaseManager(env).init_db() DatabaseManager(env).shutdown() for x in filter(None, [env.compmgr[cls] for cls in ComponentMeta._registry.get( IEnvironmentSetupParticipant, [])]): if isinstance(x, EnvironmentSetup): x.environment_created() if env.needs_upgrade(): env.upgrade() return env
def getPostgreSQLEnvironment(opts): """ Create an Environment connected to the PostgreSQL database """ dburi = opts.pg_uri env = Environment(opts.tracenv) env.config.set('trac', 'database', dburi) try: cnx = env.get_db_cnx() cur = cnx.cursor() cur.execute("select value from system where name = 'database_version'") except ProgrammingError: cnx.rollback() DatabaseManager(env).init_db() DatabaseManager(env).shutdown() for x in filter(None, [ env.compmgr[cls] for cls in ComponentMeta._registry.get( IEnvironmentSetupParticipant, []) ]): if isinstance(x, EnvironmentSetup): x.environment_created() if env.needs_upgrade(): env.upgrade() return env
class MigrationTestCase(unittest.TestCase): def setUp(self): self.stdout = sys.stdout self.stderr = sys.stderr sys.stdout = sys.stderr = DummyOut() self.path = tempfile.mkdtemp(prefix='trac-migrate-') self.src_path = os.path.join(self.path, 'src') self.dst_path = os.path.join(self.path, 'dst') self.src_env = None self.dst_env = None self._destroy_db() def tearDown(self): sys.stdout = self.stdout sys.stderr = self.stderr if self.src_env: self.src_env.shutdown() if self.dst_env: self.dst_env.shutdown() shutil.rmtree(self.path) def _create_env(self, path, dburi): env = Environment(path, True, [('trac', 'database', dburi), ('trac', 'base_url', 'http://localhost/'), ('project', 'name', u'Pŕójéćŧ Ńáḿé')]) @env.with_transaction() def fn(db): cursor = db.cursor() cursor.execute("UPDATE system SET value='21' " "WHERE name='initial_database_version'") pages_dir = resource_filename('trac.wiki', 'default-pages') WikiAdmin(env).load_pages(pages_dir) att = Attachment(env, 'wiki', 'WikiStart') att.insert('filename.txt', StringIO('test'), 4) env.shutdown() if 'destroying' in inspect.getargspec(EnvironmentStub.__init__)[0]: def _destroy_db(self): EnvironmentStub(destroying=True).destroy_db() else: def _destroy_db(self): EnvironmentStub().destroy_db() def _get_all_records(self, env): def primary(row, columns): if len(columns) == 1: return row[columns[0]] else: return tuple(row[col] for col in columns) db = env.get_read_db() cursor = db.cursor() records = {} for table in db_default.schema: primary_cols = ','.join(db.quote(col) for col in table.key) query = "SELECT * FROM %s ORDER BY %s" % (db.quote(table.name), primary_cols) cursor.execute(query) columns = get_column_names(cursor) rows = {} for row in cursor: row = dict(zip(columns, row)) rows[primary(row, table.key)] = row records[table.name] = rows return records def _generate_module_name(self): return 'tracmigratetest_' + hex_entropy(16) def _build_egg_file(self): module_name = self._generate_module_name() plugin_src = os.path.join(self.path, 'plugin_src') os.mkdir(plugin_src) os.mkdir(os.path.join(plugin_src, module_name)) create_file(os.path.join(plugin_src, 'setup.py'), _setup_py % {'name': module_name}) create_file(os.path.join(plugin_src, module_name, '__init__.py'), _plugin_py) proc = Popen((sys.executable, 'setup.py', 'bdist_egg'), cwd=plugin_src, stdin=PIPE, stdout=PIPE, stderr=PIPE, close_fds=close_fds) stdout, stderr = proc.communicate(input='') for f in (proc.stdin, proc.stdout, proc.stderr): f.close() for filename in glob(os.path.join(plugin_src, 'dist', '*-*.egg')): return filename def _migrate(self, env, path, dburi): TracMigrationCommand(env)._do_migrate(path, dburi) def _migrate_inplace(self, env, dburi): self._migrate(env, '--in-place', dburi) def _compare_records(self, expected, actual): self.assertEqual(expected.keys(), actual.keys()) for table in db_default.schema: name = table.name if name == 'report': self.assertEqual(expected[name].keys(), actual[name].keys()) else: self.assertEqual(expected[name], actual[name]) def _get_options(self, env): config = env.config return [(section, name, self._option_dumps(section, name, value)) for section in sorted(config.sections()) for name, value in sorted(config.options(section)) if not (section == 'trac' and name == 'database')] if hasattr(Option, 'dumps'): def _option_dumps(self, section, name, value): try: option = Option.registry[(section, name)] value = option.dumps(value) except KeyError: pass return value else: def _option_dumps(self, section, name, value): def dumps(value, option=None): if value is None: return '' if value is True: return 'enabled' if value is False: return 'disabled' if isinstance(value, unicode): return value if isinstance(value, (list, tuple)) and hasattr(option, 'sep'): return option.sep.join(dumps(v) for v in value) return to_unicode(value) try: option = Option.registry[(section, name)] value = dumps(value, option=option) except KeyError: pass return value def test_migrate_from_sqlite_to_env(self): self._create_env(self.src_path, 'sqlite:db/trac.db') dburi = get_dburi() if dburi == 'sqlite::memory:': dburi = 'sqlite:db/trac.db' self.src_env = Environment(self.src_path) src_options = self._get_options(self.src_env) src_records = self._get_all_records(self.src_env) self._migrate(self.src_env, self.dst_path, dburi) self.dst_env = Environment(self.dst_path) dst_options = self._get_options(self.dst_env) dst_records = self._get_all_records(self.dst_env) self.assertEqual({'name': 'initial_database_version', 'value': '21'}, dst_records['system']['initial_database_version']) self._compare_records(src_records, dst_records) self.assertEqual(src_options, dst_options) att = Attachment(self.dst_env, 'wiki', 'WikiStart', 'filename.txt') self.assertEqual('test', read_file(att.path)) def test_migrate_from_sqlite_inplace(self): self._create_env(self.src_path, 'sqlite:db/trac.db') dburi = get_dburi() if dburi in ('sqlite::memory:', 'sqlite:db/trac.db'): dburi = 'sqlite:db/trac-migrate.db' self.src_env = Environment(self.src_path) src_options = self._get_options(self.src_env) src_records = self._get_all_records(self.src_env) self._migrate_inplace(self.src_env, dburi) self.src_env.shutdown() self.src_env = Environment(self.src_path) dst_options = self._get_options(self.src_env) dst_records = self._get_all_records(self.src_env) self.assertEqual({'name': 'initial_database_version', 'value': '21'}, dst_records['system']['initial_database_version']) self._compare_records(src_records, dst_records) self.assertEqual(src_options, dst_options) def test_migrate_to_sqlite_env(self): dburi = get_dburi() if dburi == 'sqlite::memory:': dburi = 'sqlite:db/trac.db' self._create_env(self.src_path, dburi) self.src_env = Environment(self.src_path) src_options = self._get_options(self.src_env) src_records = self._get_all_records(self.src_env) self._migrate(self.src_env, self.dst_path, 'sqlite:db/trac.db') self.dst_env = Environment(self.dst_path) dst_options = self._get_options(self.dst_env) dst_records = self._get_all_records(self.dst_env) self.assertEqual({'name': 'initial_database_version', 'value': '21'}, dst_records['system']['initial_database_version']) self._compare_records(src_records, dst_records) self.assertEqual(src_options, dst_options) att = Attachment(self.dst_env, 'wiki', 'WikiStart', 'filename.txt') self.assertEqual('test', read_file(att.path)) def test_migrate_to_sqlite_inplace(self): dburi = get_dburi() if dburi in ('sqlite::memory:', 'sqlite:db/trac.db'): dburi = 'sqlite:db/trac-migrate.db' self._create_env(self.src_path, dburi) self.src_env = Environment(self.src_path) src_options = self._get_options(self.src_env) src_records = self._get_all_records(self.src_env) self._migrate_inplace(self.src_env, 'sqlite:db/trac.db') self.src_env.shutdown() self.src_env = Environment(self.src_path) dst_options = self._get_options(self.src_env) dst_records = self._get_all_records(self.src_env) self.assertEqual({'name': 'initial_database_version', 'value': '21'}, dst_records['system']['initial_database_version']) self._compare_records(src_records, dst_records) self.assertEqual(src_options, dst_options) def _test_migrate_with_plugin_to_sqlite_env(self): self.src_env = Environment(self.src_path) self.assertTrue(self.src_env.needs_upgrade()) self.src_env.upgrade() self.assertFalse(self.src_env.needs_upgrade()) src_options = self._get_options(self.src_env) src_records = self._get_all_records(self.src_env) self._migrate(self.src_env, self.dst_path, 'sqlite:db/trac.db') self.dst_env = Environment(self.dst_path) self.assertFalse(self.dst_env.needs_upgrade()) self.assertFalse(os.path.exists(os.path.join(self.dst_path, 'log', 'created'))) self.assertTrue(os.path.exists(os.path.join(self.dst_path, 'log', 'upgraded'))) dst_options = self._get_options(self.dst_env) dst_records = self._get_all_records(self.dst_env) self.assertEqual({'name': 'initial_database_version', 'value': '21'}, dst_records['system']['initial_database_version']) self._compare_records(src_records, dst_records) self.assertEqual(src_options, dst_options) att = Attachment(self.dst_env, 'wiki', 'WikiStart', 'filename.txt') self.assertEqual('test', read_file(att.path)) def test_migrate_with_plugin_py_to_sqlite_env(self): dburi = get_dburi() if dburi == 'sqlite::memory:': dburi = 'sqlite:db/trac.db' self._create_env(self.src_path, dburi) plugin_name = self._generate_module_name() + '.py' create_file(os.path.join(self.src_path, 'plugins', plugin_name), _plugin_py) self._test_migrate_with_plugin_to_sqlite_env() def _extract_zipfile(self, zipfile, destdir): z = ZipFile(zipfile) try: for entry in z.namelist(): if entry.endswith('/'): # is a directory continue names = entry.split('/') content = z.read(entry) filename = os.path.join(destdir, *names) dirname = os.path.dirname(filename) if not os.path.isdir(dirname): os.makedirs(dirname) create_file(filename, content, 'wb') finally: z.close() def test_migrate_with_plugin_egg_to_sqlite_env(self): dburi = get_dburi() if dburi == 'sqlite::memory:': dburi = 'sqlite:db/trac.db' self._create_env(self.src_path, dburi) self._extract_zipfile(self._build_egg_file(), os.path.join(self.src_path, 'plugins', 'tracmigratetest.egg')) self._test_migrate_with_plugin_to_sqlite_env()
class ConvertDatabaseTestCase(unittest.TestCase): stdout = None stderr = None @classmethod def setUpClass(cls): cls.stdout = sys.stdout cls.stderr = sys.stderr cls.devnull = io.open(os.devnull, 'wb') sys.stdout = sys.stderr = cls.devnull @classmethod def tearDownClass(cls): cls.devnull.close() sys.stdout = cls.stdout sys.stderr = cls.stderr def setUp(self): self.path = mkdtemp() self.src_path = os.path.join(self.path, 'src') self.dst_path = os.path.join(self.path, 'dst') self.src_env = None self.dst_env = None self._destroy_db() def tearDown(self): if self.src_env: self.src_env.shutdown() if self.dst_env: self.dst_env.shutdown() rmtree(self.path) def _create_env(self, path, dburi): env = Environment(path, True, [('trac', 'database', dburi), ('trac', 'base_url', 'http://localhost/'), ('project', 'name', u'Pŕójéćŧ Ńáḿé')]) dbm = DatabaseManager(env) dbm.set_database_version(21, 'initial_database_version') att = Attachment(env, 'wiki', 'WikiStart') att.insert('filename.txt', io.BytesIO('test'), 4) env.shutdown() if 'destroying' in inspect.getargspec(EnvironmentStub.__init__)[0]: def _destroy_db(self): EnvironmentStub(path=self.path, destroying=True).destroy_db() else: def _destroy_db(self): EnvironmentStub(path=self.path).destroy_db() def _get_all_records(self, env): def primary(row, columns): if len(columns) == 1: return row[columns[0]] else: return tuple(row[col] for col in columns) records = {} with env.db_query as db: cursor = db.cursor() for table in db_default.schema: primary_cols = ','.join(db.quote(col) for col in table.key) query = "SELECT * FROM %s ORDER BY %s" \ % (db.quote(table.name), primary_cols) cursor.execute(query) columns = get_column_names(cursor) rows = {} for row in cursor: row = dict(zip(columns, row)) rows[primary(row, table.key)] = row records[table.name] = rows return records def _generate_module_name(self): return 'trac_convert_db_' + hex_entropy(16) def _build_egg_file(self): module_name = self._generate_module_name() plugin_src = os.path.join(self.path, 'plugin_src') os.mkdir(plugin_src) os.mkdir(os.path.join(plugin_src, module_name)) create_file(os.path.join(plugin_src, 'setup.py'), _setup_py % {'name': module_name}) create_file(os.path.join(plugin_src, module_name, '__init__.py'), _plugin_py) proc = Popen((sys.executable, 'setup.py', 'bdist_egg'), cwd=plugin_src, stdin=PIPE, stdout=PIPE, stderr=PIPE, close_fds=close_fds) proc.communicate(input='') for f in (proc.stdin, proc.stdout, proc.stderr): f.close() for filename in glob(os.path.join(plugin_src, 'dist', '*-*.egg')): return filename def _convert_db(self, env, dburi, path): EnvironmentAdmin(env)._do_convert_db(dburi, path) def _convert_db_inplace(self, env, dburi): self._convert_db(env, dburi, None) def _compare_records(self, expected, actual): self.assertEqual(expected.keys(), actual.keys()) for table in db_default.schema: name = table.name if name == 'report': self.assertEqual(expected[name].keys(), actual[name].keys()) else: self.assertEqual(expected[name], actual[name]) def _get_options(self, env): config = env.config return [(section, name, self._option_dumps(section, name, value)) for section in sorted(config.sections()) for name, value in sorted(config.options(section)) if (section, name) != ('trac', 'database')] def _option_dumps(self, section, name, value): try: option = Option.registry[(section, name)] except KeyError: pass else: value = option.dumps(value) return value def test_convert_from_sqlite_to_env(self): self._create_env(self.src_path, 'sqlite:db/trac.db') dburi = get_dburi() if dburi == 'sqlite::memory:': dburi = 'sqlite:db/trac.db' self.src_env = Environment(self.src_path) src_options = self._get_options(self.src_env) src_records = self._get_all_records(self.src_env) self._convert_db(self.src_env, dburi, self.dst_path) self.dst_env = Environment(self.dst_path) dst_options = self._get_options(self.dst_env) dst_records = self._get_all_records(self.dst_env) self.assertEqual({ 'name': 'initial_database_version', 'value': '21' }, dst_records['system']['initial_database_version']) self._compare_records(src_records, dst_records) self.assertEqual(src_options, dst_options) att = Attachment(self.dst_env, 'wiki', 'WikiStart', 'filename.txt') self.assertEqual('test', read_file(att.path)) def test_convert_from_sqlite_inplace(self): self._create_env(self.src_path, 'sqlite:db/trac.db') dburi = get_dburi() if dburi in ('sqlite::memory:', 'sqlite:db/trac.db'): dburi = 'sqlite:db/trac-convert.db' self.src_env = Environment(self.src_path) src_options = self._get_options(self.src_env) src_records = self._get_all_records(self.src_env) self._convert_db_inplace(self.src_env, dburi) self.src_env.shutdown() self.src_env = Environment(self.src_path) dst_options = self._get_options(self.src_env) dst_records = self._get_all_records(self.src_env) self.assertEqual({ 'name': 'initial_database_version', 'value': '21' }, dst_records['system']['initial_database_version']) self._compare_records(src_records, dst_records) self.assertEqual(src_options, dst_options) def test_convert_to_sqlite_env(self): dburi = get_dburi() if dburi == 'sqlite::memory:': dburi = 'sqlite:db/trac.db' self._create_env(self.src_path, dburi) self.src_env = Environment(self.src_path) src_options = self._get_options(self.src_env) src_records = self._get_all_records(self.src_env) self._convert_db(self.src_env, 'sqlite:db/trac.db', self.dst_path) self.dst_env = Environment(self.dst_path) dst_options = self._get_options(self.dst_env) dst_records = self._get_all_records(self.dst_env) self.assertEqual({ 'name': 'initial_database_version', 'value': '21' }, dst_records['system']['initial_database_version']) self._compare_records(src_records, dst_records) self.assertEqual(src_options, dst_options) att = Attachment(self.dst_env, 'wiki', 'WikiStart', 'filename.txt') self.assertEqual('test', read_file(att.path)) def test_convert_to_sqlite_inplace(self): dburi = get_dburi() if dburi in ('sqlite::memory:', 'sqlite:db/trac.db'): dburi = 'sqlite:db/trac-convert.db' self._create_env(self.src_path, dburi) self.src_env = Environment(self.src_path) src_options = self._get_options(self.src_env) src_records = self._get_all_records(self.src_env) self._convert_db_inplace(self.src_env, 'sqlite:db/trac.db') self.src_env.shutdown() self.src_env = Environment(self.src_path) dst_options = self._get_options(self.src_env) dst_records = self._get_all_records(self.src_env) self.assertEqual({ 'name': 'initial_database_version', 'value': '21' }, dst_records['system']['initial_database_version']) self._compare_records(src_records, dst_records) self.assertEqual(src_options, dst_options) def _test_convert_with_plugin_to_sqlite_env(self): self.src_env = Environment(self.src_path) self.assertTrue(self.src_env.needs_upgrade()) self.src_env.upgrade() self.assertFalse(self.src_env.needs_upgrade()) src_options = self._get_options(self.src_env) src_records = self._get_all_records(self.src_env) self._convert_db(self.src_env, 'sqlite:db/trac.db', self.dst_path) self.dst_env = Environment(self.dst_path) self.assertFalse(self.dst_env.needs_upgrade()) self.assertFalse( os.path.exists(os.path.join(self.dst_env.log_dir, 'created'))) self.assertTrue( os.path.exists(os.path.join(self.dst_env.log_dir, 'upgraded'))) dst_options = self._get_options(self.dst_env) dst_records = self._get_all_records(self.dst_env) self.assertEqual({ 'name': 'initial_database_version', 'value': '21' }, dst_records['system']['initial_database_version']) self._compare_records(src_records, dst_records) self.assertEqual(src_options, dst_options) att = Attachment(self.dst_env, 'wiki', 'WikiStart', 'filename.txt') self.assertEqual('test', read_file(att.path)) def test_convert_with_plugin_py_to_sqlite_env(self): dburi = get_dburi() if dburi == 'sqlite::memory:': dburi = 'sqlite:db/trac.db' self._create_env(self.src_path, dburi) plugin_name = self._generate_module_name() + '.py' create_file(os.path.join(self.src_path, 'plugins', plugin_name), _plugin_py) self._test_convert_with_plugin_to_sqlite_env() def test_convert_with_plugin_egg_to_sqlite_env(self): dburi = get_dburi() if dburi == 'sqlite::memory:': dburi = 'sqlite:db/trac.db' self._create_env(self.src_path, dburi) extract_zipfile( self._build_egg_file(), os.path.join(self.src_path, 'plugins', 'trac_convert_db_test.egg')) self._test_convert_with_plugin_to_sqlite_env()
class EnvironmentTestCase(unittest.TestCase): def setUp(self): env_path = tempfile.mkdtemp(prefix='trac-tempenv-') self.env = Environment(env_path, create=True) self.env.config.set('trac', 'base_url', 'http://trac.edgewall.org/some/path') self.env.config.save() def tearDown(self): self.env.shutdown() # really closes the db connections shutil.rmtree(self.env.path) def test_db_exc(self): db_exc = self.env.db_exc self.assertTrue(hasattr(db_exc, 'IntegrityError')) self.assertIs(db_exc, self.env.db_exc) def test_abs_href(self): abs_href = self.env.abs_href self.assertEqual('http://trac.edgewall.org/some/path', abs_href()) self.assertIs(abs_href, self.env.abs_href) def test_href(self): href = self.env.href self.assertEqual('/some/path', href()) self.assertIs(href, self.env.href) def test_get_version(self): """Testing env.get_version""" self.assertEqual(db_default.db_version, self.env.get_version()) self.assertEqual(db_default.db_version, self.env.database_version) self.assertEqual(db_default.db_version, self.env.database_initial_version) def test_get_known_users(self): """Testing env.get_known_users""" with self.env.db_transaction as db: db.executemany("INSERT INTO session VALUES (%s,%s,0)", [('123', 0), ('tom', 1), ('joe', 1), ('jane', 1)]) db.executemany( "INSERT INTO session_attribute VALUES (%s,%s,%s,%s)", [('123', 0, 'email', '*****@*****.**'), ('tom', 1, 'name', 'Tom'), ('tom', 1, 'email', '*****@*****.**'), ('joe', 1, 'email', '*****@*****.**'), ('jane', 1, 'name', 'Jane')]) users = {} for username, name, email in self.env.get_known_users(): users[username] = (name, email) self.assertTrue('anonymous' not in users) self.assertEqual(('Tom', '*****@*****.**'), users['tom']) self.assertEqual((None, '*****@*****.**'), users['joe']) self.assertEqual(('Jane', None), users['jane']) def test_is_component_enabled(self): self.assertEqual(True, Environment.required) self.assertEqual(True, self.env.is_component_enabled(Environment)) self.assertEqual(False, EnvironmentStub.required) self.assertEqual(None, self.env.is_component_enabled(EnvironmentStub)) def test_dumped_values_in_tracini(self): parser = RawConfigParser() filename = self.env.config.filename self.assertEqual([filename], parser.read(filename)) self.assertEqual('#cc0,#0c0,#0cc,#00c,#c0c,#c00', parser.get('revisionlog', 'graph_colors')) self.assertEqual('disabled', parser.get('trac', 'secure_cookies')) def test_dumped_values_in_tracini_sample(self): parser = RawConfigParser() filename = self.env.config.filename + '.sample' self.assertEqual([filename], parser.read(filename)) self.assertEqual('#cc0,#0c0,#0cc,#00c,#c0c,#c00', parser.get('revisionlog', 'graph_colors')) self.assertEqual('disabled', parser.get('trac', 'secure_cookies')) self.assertTrue(parser.has_option('logging', 'log_format')) self.assertEqual('', parser.get('logging', 'log_format')) def test_needs_upgrade_legacy_participant(self): """For backward compatibility with plugin, environment_needs_upgrade with a `db` argument is deprecated but still allowed.""" participants = self.env.setup_participants needs_upgrade = self.env.needs_upgrade() class LegacyParticipant(Component): implements(IEnvironmentSetupParticipant) def environment_created(self): pass def environment_needs_upgrade(self, db): return True def upgrade_environment(self, db): pass self.env.enable_component(LegacyParticipant) self.assertFalse(needs_upgrade) self.assertEqual( len(participants) + 1, len(self.env.setup_participants)) self.assertTrue(self.env.needs_upgrade()) def test_upgrade_legacy_participant(self): """For backward compatibility with plugin, upgrade with a `db` argument is deprecated but still allowed.""" participants = self.env.setup_participants class LegacyParticipant(Component): implements(IEnvironmentSetupParticipant) def environment_created(self): pass def environment_needs_upgrade(self, db): return True def upgrade_environment(self, db): pass self.env.enable_component(LegacyParticipant) self.assertEqual( len(participants) + 1, len(self.env.setup_participants)) self.assertTrue(self.env.needs_upgrade()) self.assertTrue(self.env.upgrade()) def test_invalid_log_level_raises_exception(self): self.env.config.set('logging', 'log_level', 'invalid') self.env.config.save() self.assertEqual('invalid', self.env.config.get('logging', 'log_level')) self.assertRaises(ConfigurationError, open_environment, self.env.path, True) def test_invalid_log_type_raises_exception(self): self.env.config.set('logging', 'log_type', 'invalid') self.env.config.save() self.assertEqual('invalid', self.env.config.get('logging', 'log_type')) self.assertRaises(ConfigurationError, open_environment, self.env.path, True)
class EnvironmentTestCase(unittest.TestCase): stdout = None stderr = None @classmethod def setUpClass(cls): cls.stdout = sys.stdout cls.stderr = sys.stderr cls.devnull = io.open(os.devnull, 'wb') sys.stdout = sys.stderr = cls.devnull @classmethod def tearDownClass(cls): cls.devnull.close() sys.stdout = cls.stdout sys.stderr = cls.stderr def setUp(self): self.env_path = mkdtemp() self.env = Environment(self.env_path, create=True) def tearDown(self): self.env.shutdown() # really closes the db connections rmtree(self.env.path) def test_missing_config_file_raises_trac_error(self): """TracError is raised when config file is missing.""" os.remove(self.env.config_file_path) self.assertRaises(TracError, Environment, self.env.path) def test_database_version(self): """Testing env.database_version""" self.assertEqual(db_default.db_version, self.env.database_version) def test_database_initial_version(self): """Testing env.database_initial_version""" self.assertEqual(db_default.db_version, self.env.database_initial_version) def test_is_component_enabled(self): self.assertTrue(Environment.required) self.assertTrue(self.env.is_component_enabled(Environment)) def test_log_format(self): """Configure the log_format and log to a file at WARNING level.""" self.env.config.set('logging', 'log_type', 'file') self.env.config.set('logging', 'log_level', 'WARNING') self.env.config.set('logging', 'log_format', 'Trac[$(module)s] $(project)s: $(message)s') self.env.config.save() self.env.shutdown() self.env = Environment(self.env_path) # Reload environment self.env.log.warning("The warning message") with open(self.env.log_file_path) as f: log = f.readlines() self.assertEqual("Trac[env] My Project: The warning message\n", log[-1]) def test_dumped_values_in_tracini(self): parser = RawConfigParser() filename = self.env.config.filename self.assertEqual([filename], parser.read(filename)) self.assertEqual('#cc0,#0c0,#0cc,#00c,#c0c,#c00', parser.get('revisionlog', 'graph_colors')) self.assertEqual('disabled', parser.get('trac', 'secure_cookies')) def test_dumped_values_in_tracini_sample(self): parser = RawConfigParser() filename = self.env.config.filename + '.sample' self.assertEqual([filename], parser.read(filename)) self.assertEqual('#cc0,#0c0,#0cc,#00c,#c0c,#c00', parser.get('revisionlog', 'graph_colors')) self.assertEqual('disabled', parser.get('trac', 'secure_cookies')) self.assertTrue(parser.has_option('logging', 'log_format')) self.assertEqual('', parser.get('logging', 'log_format')) def test_invalid_log_level_raises_exception(self): self.env.config.set('logging', 'log_level', 'invalid') self.env.config.save() self.assertEqual('invalid', self.env.config.get('logging', 'log_level')) self.assertRaises(ConfigurationError, open_environment, self.env.path, True) def test_invalid_log_type_raises_exception(self): self.env.config.set('logging', 'log_type', 'invalid') self.env.config.save() self.assertEqual('invalid', self.env.config.get('logging', 'log_type')) self.assertRaises(ConfigurationError, open_environment, self.env.path, True) def test_log_level_not_case_sensitive(self): """[logging] log_level is not case-sensitive.""" self.env.config.set('logging', 'log_level', 'warning') self.env.config.save() self.assertEqual('warning', self.env.config.get('logging', 'log_level')) self.assertEqual('WARNING', self.env.log_level) def test_log_type_not_case_sensitive(self): """[logging] log_type is not case-sensitive.""" self.env.config.set('logging', 'log_type', 'File') self.env.config.save() self.assertEqual('File', self.env.config.get('logging', 'log_type')) self.assertEqual('file', self.env.log_type) def test_upgrade_environment(self): """EnvironmentSetupParticipants are called only if environment_needs_upgrade returns True for the participant. """ class SetupParticipantA(Component): implements(IEnvironmentSetupParticipant) called = False def environment_created(self): pass def environment_needs_upgrade(self): return True def upgrade_environment(self): self.called = True class SetupParticipantB(Component): implements(IEnvironmentSetupParticipant) called = False def environment_created(self): pass def environment_needs_upgrade(self): return False def upgrade_environment(self): self.called = True self.env.enable_component(SetupParticipantA) self.env.enable_component(SetupParticipantB) participant_a = SetupParticipantA(self.env) participant_b = SetupParticipantB(self.env) self.assertTrue(self.env.needs_upgrade()) self.env.upgrade() self.assertTrue(participant_a.called) self.assertFalse(participant_b.called)
def create_project(self, project, templates, vars=None, database=None, repository=None, return_missing=False): """ * project: path name of project * templates: templates to be applied on project creation * vars: variables for interpolation * database: type of database to use * repository: type of repository to use """ ### set variables dirname = os.path.join(self.directory, project) if os.path.isdir(dirname) and os.listdir(dirname): raise ValueError("Project directory %r already exists, " "cowardly refusing to create anything" % dirname) _vars = vars or {} vars = self.vars.copy() vars.update(_vars) vars['project'] = project permissions = dict([(key, value[:]) for key, value in self.permissions.items()]) wiki = self.wiki[:] ### munge configuration # get templates # XXX hack to get the specified DB out of pastescript templates if not database: if isinstance(templates, ProjectTemplates): pastescript_templates = templates.pastescript_templates else: pastescript_templates = ProjectTemplates( *(templates + self.site_templates)).pastescript_templates databases = set([ template.database() for template in pastescript_templates if template.db is not None ]) if databases: assert len(databases) == 1 database = databases.pop() if not database: database = SQLite() _templates = [] _templates.append(database.config()) if repository: _templates.append(repository.config()) if isinstance(templates, ProjectTemplates): if _templates: templates.append(*_templates) else: templates += _templates templates = self.project_templates(templates) # determine the vars/options optdict = templates.vars(self.options) repo_fields = {} if database: vars2dict(optdict, *database.options) if repository: vars2dict(optdict, *repository.options) repo_fields = self.repository_fields(project).get( repository.name, {}) ### interpolate configuration command = create_distro_command(interactive=self.interactive) # check for missing variables missing = templates.missing(vars) missing.update(set(optdict.keys()).difference(vars.keys())) if return_missing: return missing if missing: # use default repo fields if they are missing for field in repo_fields: if field in missing: vars[field] = repo_fields[field] missing.remove(field) # add missing variables to the optdict for missed in missing: if missed not in optdict: optdict[missed] = var(missed, '') if missing: paste_template = Template(project) paste_template._read_vars = dict2vars(optdict) # XXX bad touch paste_template.check_vars(vars, command) # run the pre method of the pastescript templates # XXX should this be done here? command.interactive = False for paste_template in templates.pastescript_templates: paste_template.pre(command, dirname, vars) ### create the database if database: database.setup(**vars) ### create the trac environment options = templates.options_tuples(vars) options.append(('project', 'name', project)) # XXX needed? if self.inherit: options.append(('inherit', 'file', self.inherit)) env = Environment(dirname, create=True, options=options) ### repository setup if repository: repository.setup(**vars) try: repos = env.get_repository() repos.sync() except TracError: pass ### read the generated configuration _conf_file = os.path.join(dirname, 'conf', 'trac.ini') fp = file(_conf_file) _conf = fp.read() fp.close() ### run pastescript templates for paste_template in templates.pastescript_templates: paste_template.write_files(command, dirname, vars) paste_template.post(command, dirname, vars) # read permissions for agent, perm in paste_template.permissions.items(): permissions.setdefault(agent, []).extend(perm) # read wiki directories wiki_dir = paste_template.wiki_dir() if wiki_dir is not None: wiki.append(wiki_dir) # write back munged configuration munger = ConfigMunger(_conf, options) fp = file(_conf_file, 'w') munger.write(fp) fp.close() # TODO: update the inherited file: # * intertrac # trac-admin upgrade the project env = Environment(dirname) if env.needs_upgrade(): env.upgrade() ### trac-admin operations admin = TracLegosAdmin(dirname) # remove the default items admin.delete_all() # load wiki pages admin.load_pages() # default wiki pages for page_dir in wiki: admin.load_pages(page_dir) # add permissions if permissions: admin.add_permissions(permissions)
class EnvironmentTestCase(unittest.TestCase): def setUp(self): env_path = mkdtemp() self.env = Environment(env_path, create=True) self.env.config.save() def tearDown(self): self.env.shutdown() # really closes the db connections shutil.rmtree(self.env.path) def test_missing_config_file_raises_trac_error(self): """TracError is raised when config file is missing.""" os.remove(self.env.config_file_path) self.assertRaises(TracError, Environment, self.env.path) def test_database_version(self): """Testing env.database_version""" self.assertEqual(db_default.db_version, self.env.database_version) def test_database_initial_version(self): """Testing env.database_initial_version""" self.assertEqual(db_default.db_version, self.env.database_initial_version) def test_is_component_enabled(self): self.assertEqual(True, Environment.required) self.assertEqual(True, self.env.is_component_enabled(Environment)) def test_dumped_values_in_tracini(self): parser = RawConfigParser() filename = self.env.config.filename self.assertEqual([filename], parser.read(filename)) self.assertEqual('#cc0,#0c0,#0cc,#00c,#c0c,#c00', parser.get('revisionlog', 'graph_colors')) self.assertEqual('disabled', parser.get('trac', 'secure_cookies')) def test_dumped_values_in_tracini_sample(self): parser = RawConfigParser() filename = self.env.config.filename + '.sample' self.assertEqual([filename], parser.read(filename)) self.assertEqual('#cc0,#0c0,#0cc,#00c,#c0c,#c00', parser.get('revisionlog', 'graph_colors')) self.assertEqual('disabled', parser.get('trac', 'secure_cookies')) self.assertTrue(parser.has_option('logging', 'log_format')) self.assertEqual('', parser.get('logging', 'log_format')) def test_invalid_log_level_raises_exception(self): self.env.config.set('logging', 'log_level', 'invalid') self.env.config.save() self.assertEqual('invalid', self.env.config.get('logging', 'log_level')) self.assertRaises(ConfigurationError, open_environment, self.env.path, True) def test_invalid_log_type_raises_exception(self): self.env.config.set('logging', 'log_type', 'invalid') self.env.config.save() self.assertEqual('invalid', self.env.config.get('logging', 'log_type')) self.assertRaises(ConfigurationError, open_environment, self.env.path, True) def test_upgrade_environment(self): """EnvironmentSetupParticipants are called only if environment_needs_upgrade returns True for the participant. """ class SetupParticipantA(Component): implements(IEnvironmentSetupParticipant) called = False def environment_created(self): pass def environment_needs_upgrade(self): return True def upgrade_environment(self): self.called = True class SetupParticipantB(Component): implements(IEnvironmentSetupParticipant) called = False def environment_created(self): pass def environment_needs_upgrade(self): return False def upgrade_environment(self): self.called = True self.env.enable_component(SetupParticipantA) self.env.enable_component(SetupParticipantB) participant_a = SetupParticipantA(self.env) participant_b = SetupParticipantB(self.env) self.assertTrue(self.env.needs_upgrade()) self.env.upgrade() self.assertTrue(participant_a.called) self.assertFalse(participant_b.called)
def main(args): if len(args) != 3: print >>sys.stderr, _usage() return 127 if args[0] in ("-i", "--in-place"): dest, source, dburi = args else: source, dest, dburi = args try: from trac.env import Environment from tracmigrate.admin import TracMigrationCommand except ImportError, e: print >>sys.stderr, "Requires trac and tracmigrateplugin: %s" % unicode(e) return 126 env = Environment(source) if env.needs_upgrade(): print >>sys.stderr, '''\ The Trac Environment needs to be upgraded. Run "trac-admin %s upgrade"''' % source return 2 return TracMigrationCommand(env)._do_migrate(dest, dburi) if __name__ == "__main__": sys.exit(main(sys.argv[1:]) or 0)
class EnvironmentTestCase(unittest.TestCase): def setUp(self): env_path = tempfile.mkdtemp(prefix='trac-tempenv-') self.env = Environment(env_path, create=True) self.env.config.set('trac', 'base_url', 'http://trac.edgewall.org/some/path') self.env.config.save() def tearDown(self): self.env.shutdown() # really closes the db connections shutil.rmtree(self.env.path) def test_db_exc(self): db_exc = self.env.db_exc self.assertTrue(hasattr(db_exc, 'IntegrityError')) self.assertIs(db_exc, self.env.db_exc) def test_abs_href(self): abs_href = self.env.abs_href self.assertEqual('http://trac.edgewall.org/some/path', abs_href()) self.assertIs(abs_href, self.env.abs_href) def test_href(self): href = self.env.href self.assertEqual('/some/path', href()) self.assertIs(href, self.env.href) def test_get_version(self): """Testing env.get_version""" self.assertEqual(db_default.db_version, self.env.get_version()) self.assertEqual(db_default.db_version, self.env.database_version) self.assertEqual(db_default.db_version, self.env.database_initial_version) def test_is_component_enabled(self): self.assertEqual(True, Environment.required) self.assertEqual(True, self.env.is_component_enabled(Environment)) self.assertEqual(False, EnvironmentStub.required) self.assertEqual(None, self.env.is_component_enabled(EnvironmentStub)) def test_dumped_values_in_tracini(self): parser = RawConfigParser() filename = self.env.config.filename self.assertEqual([filename], parser.read(filename)) self.assertEqual('#cc0,#0c0,#0cc,#00c,#c0c,#c00', parser.get('revisionlog', 'graph_colors')) self.assertEqual('disabled', parser.get('trac', 'secure_cookies')) def test_dumped_values_in_tracini_sample(self): parser = RawConfigParser() filename = self.env.config.filename + '.sample' self.assertEqual([filename], parser.read(filename)) self.assertEqual('#cc0,#0c0,#0cc,#00c,#c0c,#c00', parser.get('revisionlog', 'graph_colors')) self.assertEqual('disabled', parser.get('trac', 'secure_cookies')) self.assertTrue(parser.has_option('logging', 'log_format')) self.assertEqual('', parser.get('logging', 'log_format')) def test_needs_upgrade_legacy_participant(self): """For backward compatibility with plugin, environment_needs_upgrade with a `db` argument is deprecated but still allowed.""" participants = self.env.setup_participants needs_upgrade = self.env.needs_upgrade() class LegacyParticipant(Component): implements(IEnvironmentSetupParticipant) def environment_created(self): pass def environment_needs_upgrade(self, db): return True def upgrade_environment(self, db): pass self.env.enable_component(LegacyParticipant) self.assertFalse(needs_upgrade) self.assertEqual(len(participants) + 1, len(self.env.setup_participants)) self.assertTrue(self.env.needs_upgrade()) def test_upgrade_legacy_participant(self): """For backward compatibility with plugin, upgrade with a `db` argument is deprecated but still allowed.""" participants = self.env.setup_participants class LegacyParticipant(Component): implements(IEnvironmentSetupParticipant) def environment_created(self): pass def environment_needs_upgrade(self, db): return True def upgrade_environment(self, db): pass self.env.enable_component(LegacyParticipant) self.assertEqual(len(participants) + 1, len(self.env.setup_participants)) self.assertTrue(self.env.needs_upgrade()) self.assertTrue(self.env.upgrade()) def test_invalid_log_level_raises_exception(self): self.env.config.set('logging', 'log_level', 'invalid') self.env.config.save() self.assertEqual('invalid', self.env.config.get('logging', 'log_level')) self.assertRaises(ConfigurationError, open_environment, self.env.path, True) def test_invalid_log_type_raises_exception(self): self.env.config.set('logging', 'log_type', 'invalid') self.env.config.save() self.assertEqual('invalid', self.env.config.get('logging', 'log_type')) self.assertRaises(ConfigurationError, open_environment, self.env.path, True)
def create_project(self, project, templates, vars=None, database=None, repository=None, return_missing=False): """ * project: path name of project * templates: templates to be applied on project creation * vars: variables for interpolation * database: type of database to use * repository: type of repository to use """ ### set variables dirname = os.path.join(self.directory, project) if os.path.isdir(dirname) and os.listdir(dirname): raise ValueError("Project directory %r already exists, " "cowardly refusing to create anything" % dirname) _vars = vars or {} vars = self.vars.copy() vars.update(_vars) vars['project'] = project permissions = dict([(key, value[:]) for key, value in self.permissions.items()]) wiki = self.wiki[:] ### munge configuration # get templates # XXX hack to get the specified DB out of pastescript templates if not database: if isinstance(templates, ProjectTemplates): pastescript_templates = templates.pastescript_templates else: pastescript_templates = ProjectTemplates(*(templates + self.site_templates)).pastescript_templates databases = set([ template.database() for template in pastescript_templates if template.db is not None]) if databases: assert len(databases) == 1 database = databases.pop() if not database: database = SQLite() _templates = [] _templates.append(database.config()) if repository: _templates.append(repository.config()) if isinstance(templates, ProjectTemplates): if _templates: templates.append(*_templates) else: templates += _templates templates = self.project_templates(templates) # determine the vars/options optdict = templates.vars(self.options) repo_fields = {} if database: vars2dict(optdict, *database.options) if repository: vars2dict(optdict, *repository.options) repo_fields = self.repository_fields(project).get(repository.name, {}) ### interpolate configuration command = create_distro_command(interactive=self.interactive) # check for missing variables missing = templates.missing(vars) missing.update(set(optdict.keys()).difference(vars.keys())) if return_missing: return missing if missing: # use default repo fields if they are missing for field in repo_fields: if field in missing: vars[field] = repo_fields[field] missing.remove(field) # add missing variables to the optdict for missed in missing: if missed not in optdict: optdict[missed] = var(missed, '') if missing: paste_template = Template(project) paste_template._read_vars = dict2vars(optdict) # XXX bad touch paste_template.check_vars(vars, command) # run the pre method of the pastescript templates # XXX should this be done here? command.interactive = False for paste_template in templates.pastescript_templates: paste_template.pre(command, dirname, vars) ### create the database if database: database.setup(**vars) ### create the trac environment options = templates.options_tuples(vars) options.append(('project', 'name', project)) # XXX needed? if self.inherit: options.append(('inherit', 'file', self.inherit)) env = Environment(dirname, create=True, options=options) ### repository setup if repository: repository.setup(**vars) try: repos = env.get_repository() repos.sync() except TracError: pass ### read the generated configuration _conf_file = os.path.join(dirname, 'conf', 'trac.ini') fp = file(_conf_file) _conf = fp.read() fp.close() ### run pastescript templates for paste_template in templates.pastescript_templates: paste_template.write_files(command, dirname, vars) paste_template.post(command, dirname, vars) # read permissions for agent, perm in paste_template.permissions.items(): permissions.setdefault(agent, []).extend(perm) # read wiki directories wiki_dir = paste_template.wiki_dir() if wiki_dir is not None: wiki.append(wiki_dir) # write back munged configuration munger = ConfigMunger(_conf, options) fp = file(_conf_file, 'w') munger.write(fp) fp.close() # TODO: update the inherited file: # * intertrac # trac-admin upgrade the project env = Environment(dirname) if env.needs_upgrade(): env.upgrade() ### trac-admin operations admin = TracLegosAdmin(dirname) # remove the default items admin.delete_all() # load wiki pages admin.load_pages() # default wiki pages for page_dir in wiki: admin.load_pages(page_dir) # add permissions if permissions: admin.add_permissions(permissions)