Пример #1
0
    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()
Пример #2
0
    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
Пример #3
0
    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
Пример #4
0
    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
Пример #5
0
    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()
Пример #6
0
    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()
Пример #7
0
    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()