def initDestinations(self): """Runs the trac initialization script for each destination trac and applies and config values""" for dest_name in self.dests.keys(): inheritFile = [ x[2] for x in self.dests[dest_name]['configs'] if x[0] == 'inherit' and x[1] == 'file' ] if inheritFile: inheritOpt = '--inherit=/var/trac/common/conf/trac.ini' else: inheritOpt = '' initline = "'%s' '%s' '%s' '%s' %s" % (dest_name, \ self.dests[dest_name]['db'], self.dests[dest_name]['repo_type'], self.dests[dest_name]['repo_dir'], inheritOpt) destination = os.path.abspath(self.dests[dest_name]['path']) destAdmin = TracAdmin(destination) destAdmin.do_initenv(initline) self.dests[dest_name]['trac'] = Trac(destination) if self.dests[dest_name]['repo_type'] == 'hg': self.dests[dest_name]['trac']._env.config.set( 'components', 'tracext.hg.*', 'enabled') if self.dests[dest_name].has_key('configs'): for confSection, confName, confValue in self.dests[dest_name][ 'configs']: self.dests[dest_name]['trac']._env.config.set( confSection, confName, confValue) self.dests[dest_name]['trac']._env.config.save()
def build_trac_env(request): """Create a Trac Environment in a tmp dir """ path = tempfile.mkdtemp() ta = TracAdmin() ta.env_set(path) ta.do_initenv(u'ExampleTracEnv sqlite:db/trac.db') env = Environment(path) def fin(): rmtree(path) request.addfinalizer(fin) if request.cls: request.cls.env = env return env
def initDestinations(self): """Runs the trac initialization script for each destination trac and applies and config values""" for dest_name in self.dests.keys(): inheritFile = [x[2] for x in self.dests[dest_name]['configs'] if x[0] == 'inherit' and x[1] == 'file'] if inheritFile: inheritOpt = '--inherit=/var/trac/common/conf/trac.ini' else: inheritOpt = '' initline = "'%s' '%s' '%s' '%s' %s" % (dest_name, \ self.dests[dest_name]['db'], self.dests[dest_name]['repo_type'], self.dests[dest_name]['repo_dir'], inheritOpt) destination = os.path.abspath(self.dests[dest_name]['path']) destAdmin = TracAdmin(destination) destAdmin.do_initenv(initline) self.dests[dest_name]['trac'] = Trac(destination) if self.dests[dest_name]['repo_type'] == 'hg': self.dests[dest_name]['trac']._env.config.set('components', 'tracext.hg.*', 'enabled') if self.dests[dest_name].has_key('configs'): for confSection, confName, confValue in self.dests[dest_name]['configs']: self.dests[dest_name]['trac']._env.config.set(confSection, confName, confValue) self.dests[dest_name]['trac']._env.config.save()
def setup(self, **kwargs): """Do the setup. A kwargs dictionary may be passed to override base options, potentially allowing for multiple environment creation.""" if has_babel: import babel try: locale = get_negotiated_locale([LANG]) locale = locale or babel.Locale.default() except babel.UnknownLocaleError: pass translation.activate(locale) options = dict(self.options) options.update(kwargs) if psycopg2 is None and options.get('dbtype') == 'postgres': print "psycopg2 needs to be installed to initialise a postgresql db" return False environments_path = options['envsdir'] if not os.path.exists(environments_path): os.makedirs(environments_path) new_env = os.path.join(environments_path, options['project']) tracini = os.path.abspath(os.path.join(new_env, 'conf', 'trac.ini')) baseini = os.path.abspath(os.path.join(new_env, 'conf', 'base.ini')) options['inherit'] = baseini options['db'] = self._generate_db_str(options) if 'repo_type' not in options or options['repo_type'] is None: options['repo_type'] = '' if 'repo_path' not in options or options['repo_path'] is None: options['repo_path'] = '' if (len(options['repo_type']) > 0) ^ (len(options['repo_path']) > 0): print "Error: Specifying a repository requires both the "\ "repository-type and the repository-path options." return False digestfile = os.path.abspath(os.path.join(new_env, options['digestfile'])) realm = options['realm'] adminuser = options['adminuser'] adminpass = options['adminpass'] # create base options: accounts_config = dict(ACCOUNTS_CONFIG) accounts_config['account-manager']['htdigest_file'] = digestfile accounts_config['account-manager']['htdigest_realm'] = realm trac = TracAdmin(os.path.abspath(new_env)) if not trac.env_check(): try: trac.do_initenv('%(project)s %(db)s ' '%(repo_type)s %(repo_path)s ' '--inherit=%(inherit)s ' '--nowiki' % options) except SystemExit: print ("Error: Unable to initialise the database" "Traceback for error is above") return False else: print ("Warning: Environment already exists at %s." % new_env) self.writeconfig(tracini, [{'inherit': {'file': baseini},},]) self.writeconfig(baseini, [BASE_CONFIG, accounts_config]) if os.path.exists(digestfile): backupfile(digestfile) htdigest_create(digestfile, adminuser, realm, adminpass) print "Adding TRAC_ADMIN permissions to the admin user %s" % adminuser trac.onecmd('permission add %s TRAC_ADMIN' % adminuser) # get fresh TracAdmin instance (original does not know about base.ini) bloodhound = TracAdmin(os.path.abspath(new_env)) # final upgrade print "Running upgrades" bloodhound.onecmd('upgrade') pages = [] pages.append(pkg_resources.resource_filename('bhdashboard', 'default-pages')) bloodhound.onecmd('wiki load %s' % " ".join(pages)) print "Running wiki upgrades" bloodhound.onecmd('wiki upgrade') print "Running wiki bh upgrades" bloodhound.onecmd('wiki bh-upgrade') print """ You can now start Bloodhound by running: tracd --port=8000 %s And point your browser at http://localhost:8000/%s """ % (os.path.abspath(new_env), options['project']) return True
def install(self): """Installer""" # Utility function to interpreted boolean option value getBool = lambda s: s.strip().lower() in ['true', 'yes'] # Utility function to parse a multi-line/multi-value parameter def cleanMultiParams(v): params = [s.split('|') for s in [l.strip() for l in v.split('\n')] if len(s) > 0] cleaned_params = [] for line in params: cleaned_params.append([row.strip() for row in line]) return cleaned_params # Utility function to transform any string to an ID getId = lambda s: ''.join([c for c in s if c.isalnum()]).lower() options = self.options ################# # eggs from the config options ################ requirements, ws = self.egg.working_set() for dist in pkg_resources.working_set: ws.add(dist) # Add command line scripts trac-admin and tracd into bin entry_points = [('trac-admin', 'trac.admin.console', 'run'), ('tracd', 'trac.web.standalone', 'main')] zc.buildout.easy_install.scripts( entry_points, ws, options['executable'], options['bin-directory'] ) #################### # Init Trac instance #################### # Generate the trac instance, if required location = options['location'] project_name = options.get('project-name', 'My project') project_url = options.get('project-url', 'http://example.com') db = 'sqlite:%s' % os.path.join('db', 'trac.db') if not os.path.exists(location): os.mkdir(location) trac = TracAdmin(location) if not trac.env_check(): trac.do_initenv('"%s" %s' % (project_name, db)) env = trac.env # Remove Trac default example data clean_up = getBool(options.get('remove-examples', 'True')) if clean_up: # Remove default milestones for mil in Milestone.select(env): if mil.name in ['milestone1', 'milestone2', 'milestone3', 'milestone4']: mil.delete() # Remove default components for comp in Component.select(env): if comp.name in ['component1', 'component2']: comp.delete() # Add custom milestones for mil_data in cleanMultiParams(options.get('milestones', '')): mil_name = mil_data[0] try: mil = Milestone(env, name=mil_name) except ResourceNotFound: mil = Milestone(env) mil.name = mil_name mil.insert() # Add custom components for comp_data in cleanMultiParams(options.get('components', '')): comp_name = comp_data[0] try: comp = Component(env, name=comp_name) except ResourceNotFound: comp = Component(env) comp.name = comp_name if len(comp_data) == 2 and comp_data[1] not in [None, '']: comp.owner = comp_data[1] comp.insert() ####################### # Generate the trac.ini ####################### # Read the trac.ini config file trac_ini = os.path.join(location, 'conf', 'trac.ini') parser = ConfigParser.ConfigParser() parser.read([trac_ini]) # Clean-up trac.ini: add missing stuff if 'components' not in parser.sections(): parser.add_section('components') # Force upgrade of informations used during initialization parser.set('project', 'name', project_name) # Set all repositories repos = cleanMultiParams(options.get('repos', None)) repo_names = [getId(r[0]) for r in repos] repo_types = {}.fromkeys([r[1].lower() for r in repos]).keys() if 'repositories' not in parser.sections(): parser.add_section('repositories') for repo in repos: repo_name = getId(repo[0]) repo_type = repo[1] repo_dir = repo[2] repo_url = repo[3] parser.set('repositories', '%s.type' % repo_name, repo_type) parser.set('repositories', '%s.dir' % repo_name, repo_dir) if repo_url not in ['', None]: parser.set('repositories', '%s.url' % repo_name, repo_url) # Set default repository default_repo = getId(options.get('default-repo', None)) if default_repo and default_repo in repo_names: parser.set('repositories', '.alias', default_repo) parser.set('repositories', '.hidden', 'true') # Set repository sync method sync_method = options.get('repos-sync', 'request').strip().lower() svn_repos = [getId(r[0]) for r in repos if r[1] == 'svn'] if sync_method == 'request': parser.set('trac', 'repository_sync_per_request', ', '.join(svn_repos)) # TODO # elif sync_method == 'hook': # do stuff... # Set project description project_descr = options.get('project-description', None) if project_descr: parser.set('project', 'descr', project_descr) parser.set('header_logo', 'alt', project_descr) # Setup logo header_logo = options.get('header-logo', '') header_logo = os.path.realpath(header_logo) if os.path.exists(header_logo): shutil.copyfile(header_logo, os.path.join(location, 'htdocs', 'logo')) parser.set('header_logo', 'src', 'site/logo') parser.set('header_logo', 'link', project_url) # Set footer message parser.set('project', 'footer', options.get('footer-message', 'This Trac instance was generated by <a href="http://pypi.python.org/pypi/pbp.recipe.trac">pbp.recipe.trac</a>.')) # SMTP parameters for name in ('always-bcc', 'always-cc', 'default-domain', 'enabled', 'from', 'from-name', 'password', 'port', 'replyto', 'server', 'subject-prefix', 'user'): param_name = "smtp-%s" % name default_value = None if param_name == "smtp-from-name": default_value = project_name value = options.get(param_name, default_value) if value is not None: parser.set('notification', param_name.replace('-', '_'), value) ############### # Plugins setup ############### # If one repository use Mercurial, hook its plugin if 'hg' in repo_types: parser.set('components', 'tracext.hg.*', 'enabled') # Configure the NavAdd plugin menu_items = cleanMultiParams(options.get('additional-menu-items', '')) item_list = [] for item in menu_items: item_title = item[0] item_url = item[1] item_id = getId(item_title) item_list.append((item_id, item_title, item_url)) if item_list > 0: parser.set('components', 'navadd.*', 'enabled') if 'navadd' not in parser.sections(): parser.add_section('navadd') parser.set('navadd', 'add_items', ','.join([i[0] for i in item_list])) for (uid, title, url) in item_list: parser.set('navadd', '%s.target' % uid, 'mainnav') parser.set('navadd', '%s.title' % uid, title) parser.set('navadd', '%s.url' % uid, url) # Enable and setup time tracking time_tracking = options.get('time-tracking-plugin', 'disabled').strip().lower() == 'enabled' if time_tracking: parser.set('components', 'timingandestimationplugin.*', 'enabled') # Enable and setup the stat plugin stats = options.get('stats-plugin', 'disabled').strip().lower() == 'enabled' if stats: parser.set('components', 'tracstats.*', 'enabled') ####################### # Final upgrades & sync ####################### # Apply custom parameters defined by the user custom_params = cleanMultiParams(options.get('trac-ini-additional', '')) for param in custom_params: if len(param) == 3: section = param[0] if section not in parser.sections(): parser.add_section(section) parser.set(section, param[1], param[2]) # Write the final trac.ini parser.write(open(trac_ini, 'w')) # Reload the environment env.shutdown() trac = TracAdmin(location) env = trac.env # Set custom permissions perm_sys = PermissionSystem(env) for cperm in cleanMultiParams(options.get('permissions', '')): if len(cperm) == 2: user = cperm[0] current_user_perms = perm_sys.get_user_permissions(user) perm_list = [p.upper() for p in cperm[1].split(' ') if len(p)] for perm in perm_list: if perm not in current_user_perms: perm_sys.grant_permission(user, perm) # Upgrade Trac instance to keep it fresh needs_upgrade = env.needs_upgrade() force_upgrade = getBool(options.get('force-instance-upgrade', 'False')) if needs_upgrade or force_upgrade: env.upgrade(backup=True) # Force repository resync repo_resync = getBool(options.get('force-repos-resync', 'False')) if repo_resync: rm = RepositoryManager(env) repositories = rm.get_real_repositories() for repos in sorted(repositories, key=lambda r: r.reponame): repos.sync(clean=True) # Upgrade default wiki pages embedded in Trac instance wiki_upgrade = getBool(options.get('wiki-doc-upgrade', 'False')) if wiki_upgrade: # Got the command below from trac/admin/console.py pages_dir = pkg_resources.resource_filename('trac.wiki', 'default-pages') WikiAdmin(env).load_pages( pages_dir , ignore=['WikiStart', 'checkwiki.py'] , create_only=['InterMapTxt'] ) # Return files that were created by the recipe. The buildout # will remove all returned files upon reinstall. return tuple()
def setup(self, **kwargs): """Do the setup. A kwargs dictionary may be passed to override base options, potentially allowing for multiple environment creation.""" if has_babel: import babel try: locale = get_negotiated_locale([LANG]) locale = locale or babel.Locale.default() except babel.UnknownLocaleError: pass translation.activate(locale) options = dict(self.options) options.update(kwargs) if psycopg2 is None and options.get('dbtype') == 'postgres': print "psycopg2 needs to be installed to initialise a postgresql db" return False elif mysqldb is None and options.get('dbtype') == 'mysql': print "MySQLdb needs to be installed to initialise a mysql db" return False environments_path = options['envsdir'] if not os.path.exists(environments_path): os.makedirs(environments_path) new_env = os.path.join(environments_path, options['project']) tracini = os.path.abspath(os.path.join(new_env, 'conf', 'trac.ini')) baseini = os.path.abspath(os.path.join(new_env, 'conf', 'base.ini')) options['inherit'] = '"' + baseini + '"' options['db'] = self._generate_db_str(options) if 'repo_type' not in options or options['repo_type'] is None: options['repo_type'] = '' if 'repo_path' not in options or options['repo_path'] is None: options['repo_path'] = '' if (len(options['repo_type']) > 0) ^ (len(options['repo_path']) > 0): print "Error: Specifying a repository requires both the "\ "repository-type and the repository-path options." return False custom_prefix = 'default_product_prefix' if custom_prefix in options and options[custom_prefix]: default_product_prefix = options[custom_prefix] else: default_product_prefix = '@' digestfile = os.path.abspath(os.path.join(new_env, options['digestfile'])) realm = options['realm'] adminuser = options['adminuser'] adminpass = options['adminpass'] # create base options: accounts_config = dict(ACCOUNTS_CONFIG) accounts_config['account-manager']['htdigest_file'] = digestfile accounts_config['account-manager']['htdigest_realm'] = realm trac = TracAdmin(os.path.abspath(new_env)) if not trac.env_check(): try: rv = trac.do_initenv('%(project)s %(db)s ' '%(repo_type)s %(repo_path)s ' '--inherit=%(inherit)s ' '--nowiki' % options) if rv == 2: raise SystemExit except SystemExit: print ("Error: Unable to initialise the environment.") return False else: print ("Warning: Environment already exists at %s." % new_env) self.writeconfig(tracini, [{'inherit': {'file': baseini},},]) base_config = dict(BASE_CONFIG) base_config['trac']['environment_factory'] = \ 'multiproduct.hooks.MultiProductEnvironmentFactory' base_config['trac']['request_factory'] = \ 'multiproduct.hooks.ProductRequestFactory' if default_product_prefix != '@': base_config['multiproduct'] = dict( default_product_prefix=default_product_prefix ) self.writeconfig(baseini, [base_config, accounts_config]) if os.path.exists(digestfile): backupfile(digestfile) htdigest_create(digestfile, adminuser, realm, adminpass) print "Adding TRAC_ADMIN permissions to the admin user %s" % adminuser trac.onecmd('permission add %s TRAC_ADMIN' % adminuser) # get fresh TracAdmin instance (original does not know about base.ini) bloodhound = TracAdmin(os.path.abspath(new_env)) # final upgrade print "Running upgrades" bloodhound.onecmd('upgrade') pages = [] pages.append(pkg_resources.resource_filename('bhdashboard', 'default-pages')) pages.append(pkg_resources.resource_filename('bhsearch', 'default-pages')) bloodhound.onecmd('wiki load %s' % " ".join(pages)) print "Running wiki upgrades" bloodhound.onecmd('wiki upgrade') if self.apply_bhwiki_upgrades: print "Running wiki Bloodhound upgrades" bloodhound.onecmd('wiki bh-upgrade') else: print "Skipping Bloodhound wiki upgrades" print "Loading default product wiki" bloodhound.onecmd('product admin %s wiki load %s' % (default_product_prefix, " ".join(pages))) print "Running default product wiki upgrades" bloodhound.onecmd('product admin %s wiki upgrade' % default_product_prefix) if self.apply_bhwiki_upgrades: print "Running default product Bloodhound wiki upgrades" bloodhound.onecmd('product admin %s wiki bh-upgrade' % default_product_prefix) else: print "Skipping default product Bloodhound wiki upgrades" print """ You can now start Bloodhound by running: tracd --port=8000 %s And point your browser at http://localhost:8000/%s """ % (os.path.abspath(new_env), options['project']) return True
def setup(self, **kwargs): """Do the setup. A kwargs dictionary may be passed to override base options, potentially allowing for multiple environment creation.""" options = dict(self.options) options.update(kwargs) if psycopg2 is None and options.get('dbtype') == 'postgres': print "psycopg2 needs to be installed to initialise a postgresql db" return False environments_path = options['envsdir'] if not os.path.exists(environments_path): os.makedirs(environments_path) new_env = os.path.join(environments_path, options['project']) tracini = os.path.abspath(os.path.join(new_env, 'conf', 'trac.ini')) baseini = os.path.abspath(os.path.join(new_env, 'conf', 'base.ini')) options['inherit'] = baseini options['db'] = self._generate_db_str(options) if 'repo_type' not in options or options['repo_type'] is None: options['repo_type'] = '' if 'repo_path' not in options or options['repo_path'] is None: options['repo_path'] = '' digestfile = os.path.abspath( os.path.join(new_env, options['digestfile'])) realm = options['realm'] adminuser = options['adminuser'] adminpass = options['adminpass'] # create base options: accounts_config = dict(ACCOUNTS_CONFIG) accounts_config['account-manager']['htdigest_file'] = digestfile accounts_config['account-manager']['htdigest_realm'] = realm accounts_config['account-manager']['password_file'] = digestfile trac = TracAdmin(os.path.abspath(new_env)) if not trac.env_check(): try: trac.do_initenv('%(project)s %(db)s ' '%(repo_type)s %(repo_path)s ' '--inherit=%(inherit)s ' '--nowiki' % options) except SystemExit: print( "Error: Unable to initialise the database" "Traceback for error is above") return False else: print("Warning: Environment already exists at %s." % new_env) self.writeconfig(tracini, [ { 'inherit': { 'file': baseini }, }, ]) self.writeconfig(baseini, [BASE_CONFIG, accounts_config]) if os.path.exists(digestfile): backupfile(digestfile) htdigest_create(digestfile, adminuser, realm, adminpass) print "Adding TRAC_ADMIN permissions to the admin user %s" % adminuser trac.onecmd('permission add %s TRAC_ADMIN' % adminuser) # get fresh TracAdmin instance (original does not know about base.ini) bloodhound = TracAdmin(os.path.abspath(new_env)) # final upgrade print "Running upgrades" bloodhound.onecmd('upgrade') pages = pkg_resources.resource_filename('bhdashboard', 'default-pages') bloodhound.onecmd('wiki load %s' % pages) print "Running wiki upgrades" bloodhound.onecmd('wiki upgrade') print """ You can now start Bloodhound by running: tracd --port=8000 %s And point your browser at http://localhost:8000/%s """ % (os.path.abspath(new_env), options['project']) return True
def install(self): options = self.options # create our run scripts entry_points = [('trac-admin', 'trac.admin.console', 'run'), ('tracd', 'trac.web.standalone', 'main')] zc.buildout.easy_install.scripts( entry_points, pkg_resources.working_set, options['executable'], options['bin-directory'] ) # create the trac instance location = options['location'] project_name = options.get('project-name', 'trac-project') project_name = '"%s"' % project_name project_url = options.get('project-url', 'http://example.com') if not options.has_key('db-type') or options['db-type'] == 'sqlite': db = 'sqlite:%s' % os.path.join('db', 'trac.db') elif options['db-type'] == 'postgres': db_options = { 'user': options['db-username'], 'pass': options['db-password'], 'host': options.get('db-host', 'localhost'), 'db': options.get('db-name', 'trac'), 'port': options.get('db-port', '5432') } db = 'postgres://%(user)s:%(pass)s@%(host)s:%(port)s/%(db)s' % db_options repos_type = options.get('repos-type', "") repos_path = options.get('repos-path', "") if not os.path.exists(location): os.makedirs(location) print "Creating Trac Instance in: " + location # install the eggs that we need self.egg.install() if self.metamode: # put the config file somewhere so we can inherit it self._write_ini(os.path.join(location, 'base_trac.ini'), db, {'location': location}) instances = self._get_instances() for instance, data in instances.iteritems(): # we need a new location for each project meta_location = os.path.join(self.buildout['buildout']['directory'], 'var', self.name, instance) trac = TracAdmin(meta_location) if not trac.env_check(): repos_type = data.get('repository_type', '') repos_path = data.get('repository-dir', '') # get the database dsn if not data.has_key('db-type') or data['db-type'] == 'sqlite': db = 'sqlite:%s' % os.path.join('db', 'trac.db') elif data['db-type'] == 'postgres': db_options = { 'user': data.get('db-username', 'trac'), 'pass': data.get('db-password', 'trac'), 'host': data.get('db-host', 'localhost'), 'port': data.get('db-port', '5432'), 'db': instance } db = 'postgres://%(user)s:%(pass)s@%(host)s:%(port)s/%(db)s' % db_options env = trac.do_initenv('%s %s %s %s' % (instance, db, repos_type, repos_path)) data.update({'project_name': instance, 'repository-dir': data.get('repository-dir', '')}) data['database_dsn'] = db self.write_custom_config(os.path.join(meta_location, 'conf', 'trac.ini'), os.path.join(location, 'base_trac.ini'), meta = True, meta_vars = data) # add any repositories repo_provider = DbRepositoryProvider(trac.env) repo_provider.add_repository('default', repos_path, repos_type) else: trac = TracAdmin(location) if not trac.env_check(): trac.do_initenv('%s %s %s %s' % (project_name, db, repos_type, repos_path)) self._write_ini(os.path.join(location, 'conf', 'base_trac.ini'), db, self.options) self.write_custom_config(os.path.join(location, 'conf', 'trac.ini'), os.path.join(location, 'conf', 'base_trac.ini')) if options.has_key('wsgi') and options['wsgi'].lower() == 'true': self.install_wsgi(options['location']) if options.has_key('testrunner') and options['testrunner'].lower() == 'true': self.install_testrunner() self.install_htpasswd() # buildout expects a tuple of paths, but we don't have any to add # just return an empty one for now. return tuple()
def install(self): options = self.options # create our run scripts entry_points = [('trac-admin', 'trac.admin.console', 'run'), ('tracd', 'trac.web.standalone', 'main')] zc.buildout.easy_install.scripts( entry_points, pkg_resources.working_set, options['executable'], options['bin-directory'] ) # create the trac instance location = options['location'] project_name = options.get('project-name', 'trac-project') project_name = '"%s"' % project_name project_url = options.get('project-url', 'http://example.com') if not options.has_key('db-type') or options['db-type'] == 'sqlite': db = 'sqlite:%s' % os.path.join('db', 'trac.db') elif options['db-type'] == 'postgres': db_options = { 'user': options['db-username'], 'pass': options['db-password'], 'host': options.get('db-host', 'localhost'), 'port': options.get('db-port', '5432') } db = 'postgres://%(user)s:%(pass)s@%(host)s:%(port)s' % db_options repos_type = options.get('repos-type', "") repos_path = options.get('repos-path', "") if not os.path.exists(location): os.makedirs(location) trac = TracAdmin(location) if not trac.env_check(): trac.do_initenv('%s %s %s %s' % (project_name, db, repos_type, repos_path)) # install the eggs that we need self.egg.install() # move the generated config out of the way so we can inherit it trac_ini = os.path.join(location, 'conf', 'trac.ini') # parse the options to pass into our template template_options = self.options['config-template-options'] template_options = json.loads(template_options) template_options['site_url'] = self.options.get('site-url', "") template_options['log_directory'] = self.options.get('log-directory', "") template_options['trac_location'] = self.options['location'] template_options['database_dsn'] = db self.write_config(trac_ini, self.options['base-config'], template_options) if options.has_key('wsgi') and options['wsgi'].lower() == 'true': self.install_wsgi() if options.has_key('testrunner') and options['testrunner'].lower() == 'true': self.install_testrunner() self.install_htpasswd() # buildout expects a tuple of paths, but we don't have any to add # just return an empty one for now. return tuple()
def install(self): """Installer""" # Utility function to interpreted boolean option value getBool = lambda s: s.strip().lower() in ['true', 'yes'] # Utility function to parse a multi-line/multi-value parameter def cleanMultiParams(v): params = [ s.split('|') for s in [l.strip() for l in v.split('\n')] if len(s) > 0 ] cleaned_params = [] for line in params: cleaned_params.append([row.strip() for row in line]) return cleaned_params # Utility function to transform any string to an ID getId = lambda s: ''.join([c for c in s if c.isalnum()]).lower() options = self.options # Add command line scripts trac-admin and tracd into bin entry_points = [('trac-admin', 'trac.admin.console', 'run'), ('tracd', 'trac.web.standalone', 'main')] zc.buildout.easy_install.scripts(entry_points, pkg_resources.working_set, options['executable'], options['bin-directory']) #################### # Init Trac instance #################### # Generate the trac instance, if required location = options['location'] project_name = options.get('project-name', 'My project') project_url = options.get('project-url', 'http://example.com') db = 'sqlite:%s' % os.path.join('db', 'trac.db') if not os.path.exists(location): os.mkdir(location) trac = TracAdmin(location) if not trac.env_check(): trac.do_initenv('"%s" %s' % (project_name, db)) env = trac.env # Remove Trac default example data clean_up = getBool(options.get('remove-examples', 'True')) if clean_up: # Remove default milestones for mil in Milestone.select(env): if mil.name in [ 'milestone1', 'milestone2', 'milestone3', 'milestone4' ]: mil.delete() # Remove default components for comp in Component.select(env): if comp.name in ['component1', 'component2']: comp.delete() # Add custom milestones for mil_data in cleanMultiParams(options.get('milestones', '')): mil_name = mil_data[0] try: mil = Milestone(env, name=mil_name) except ResourceNotFound: mil = Milestone(env) mil.name = mil_name mil.insert() # Add custom components for comp_data in cleanMultiParams(options.get('components', '')): comp_name = comp_data[0] try: comp = Component(env, name=comp_name) except ResourceNotFound: comp = Component(env) comp.name = comp_name if len(comp_data) == 2 and comp_data[1] not in [None, '']: comp.owner = comp_data[1] comp.insert() ####################### # Generate the trac.ini ####################### # Read the trac.ini config file trac_ini = os.path.join(location, 'conf', 'trac.ini') parser = ConfigParser.ConfigParser() parser.read([trac_ini]) # Clean-up trac.ini: add missing stuff if 'components' not in parser.sections(): parser.add_section('components') # Force upgrade of informations used during initialization parser.set('project', 'name', project_name) # Set all repositories repos = cleanMultiParams(options.get('repos', None)) repo_names = [getId(r[0]) for r in repos] repo_types = {}.fromkeys([r[1].lower() for r in repos]).keys() if 'repositories' not in parser.sections(): parser.add_section('repositories') for repo in repos: repo_name = getId(repo[0]) repo_type = repo[1] repo_dir = repo[2] repo_url = repo[3] parser.set('repositories', '%s.type' % repo_name, repo_type) parser.set('repositories', '%s.dir' % repo_name, repo_dir) if repo_url not in ['', None]: parser.set('repositories', '%s.url' % repo_name, repo_url) # Set default repository default_repo = getId(options.get('default-repo', None)) if default_repo and default_repo in repo_names: parser.set('repositories', '.alias', default_repo) parser.set('repositories', '.hidden', 'true') # Set repository sync method sync_method = options.get('repos-sync', 'request').strip().lower() svn_repos = [getId(r[0]) for r in repos if r[1] == 'svn'] if sync_method == 'request': parser.set('trac', 'repository_sync_per_request', ', '.join(svn_repos)) # TODO # elif sync_method == 'hook': # do stuff... # Set project description project_descr = options.get('project-description', None) if project_descr: parser.set('project', 'descr', project_descr) parser.set('header_logo', 'alt', project_descr) # Setup logo header_logo = options.get('header-logo', '') header_logo = os.path.realpath(header_logo) if os.path.exists(header_logo): shutil.copyfile(header_logo, os.path.join(location, 'htdocs', 'logo')) parser.set('header_logo', 'src', 'site/logo') parser.set('header_logo', 'link', project_url) # Set footer message parser.set( 'project', 'footer', options.get( 'footer-message', 'This Trac instance was generated by <a href="http://pypi.python.org/pypi/pbp.recipe.trac">pbp.recipe.trac</a>.' )) # SMTP parameters for name in ('always-bcc', 'always-cc', 'default-domain', 'enabled', 'from', 'from-name', 'password', 'port', 'replyto', 'server', 'subject-prefix', 'user'): param_name = "smtp-%s" % name default_value = None if param_name == "smtp-from-name": default_value = project_name value = options.get(param_name, default_value) if value is not None: parser.set('notification', param_name.replace('-', '_'), value) ############### # Plugins setup ############### # If one repository use Mercurial, hook its plugin if 'hg' in repo_types: parser.set('components', 'tracext.hg.*', 'enabled') # Configure the NavAdd plugin menu_items = cleanMultiParams(options.get('additional-menu-items', '')) item_list = [] for item in menu_items: item_title = item[0] item_url = item[1] item_id = getId(item_title) item_list.append((item_id, item_title, item_url)) if item_list > 0: parser.set('components', 'navadd.*', 'enabled') if 'navadd' not in parser.sections(): parser.add_section('navadd') parser.set('navadd', 'add_items', ','.join([i[0] for i in item_list])) for (uid, title, url) in item_list: parser.set('navadd', '%s.target' % uid, 'mainnav') parser.set('navadd', '%s.title' % uid, title) parser.set('navadd', '%s.url' % uid, url) # Enable and setup time tracking time_tracking = options.get('time-tracking-plugin', 'disabled').strip().lower() == 'enabled' if time_tracking: parser.set('components', 'timingandestimationplugin.*', 'enabled') # Enable and setup the stat plugin stats = options.get('stats-plugin', 'disabled').strip().lower() == 'enabled' if stats: parser.set('components', 'tracstats.*', 'enabled') ####################### # Final upgrades & sync ####################### # Apply custom parameters defined by the user custom_params = cleanMultiParams(options.get('trac-ini-additional', '')) for param in custom_params: if len(param) == 3: section = param[0] if section not in parser.sections(): parser.add_section(section) parser.set(section, param[1], param[2]) # Write the final trac.ini parser.write(open(trac_ini, 'w')) # Reload the environment env.shutdown() trac = TracAdmin(location) env = trac.env # Set custom permissions perm_sys = PermissionSystem(env) for cperm in cleanMultiParams(options.get('permissions', '')): if len(cperm) == 2: user = cperm[0] current_user_perms = perm_sys.get_user_permissions(user) perm_list = [p.upper() for p in cperm[1].split(' ') if len(p)] for perm in perm_list: if perm not in current_user_perms: perm_sys.grant_permission(user, perm) # Upgrade Trac instance to keep it fresh needs_upgrade = env.needs_upgrade() force_upgrade = getBool(options.get('force-instance-upgrade', 'False')) if needs_upgrade or force_upgrade: env.upgrade(backup=True) # Force repository resync repo_resync = getBool(options.get('force-repos-resync', 'False')) if repo_resync: rm = RepositoryManager(env) repositories = rm.get_real_repositories() for repos in sorted(repositories, key=lambda r: r.reponame): repos.sync(clean=True) # Upgrade default wiki pages embedded in Trac instance wiki_upgrade = getBool(options.get('wiki-doc-upgrade', 'False')) if wiki_upgrade: # Got the command below from trac/admin/console.py pages_dir = pkg_resources.resource_filename( 'trac.wiki', 'default-pages') WikiAdmin(env).load_pages(pages_dir, ignore=['WikiStart', 'checkwiki.py'], create_only=['InterMapTxt']) # Return files that were created by the recipe. The buildout # will remove all returned files upon reinstall. return tuple()