Changeset 184 for cleverbox/trunk

Show
Ignore:
Timestamp:
08/13/07 22:18:30 (5 years ago)
Author:
trivoallan
Message:

cleverbox :

  • fixed typo in trac-defaults.ini
  • removed automatic setuptools installation (because it's buggy !)
  • factored projects to their own module
Location:
cleverbox/trunk
Files:
1 added
1 removed
5 modified

Legend:

Unmodified
Added
Removed
  • cleverbox/trunk/assets/trac-defaults.ini

    r143 r184  
    55webadmin.* = enabled 
    66themeengine.* = enabled 
    7 svnhooks.svnhooks 
     7svnhooks.svnhooks = enabled 
  • cleverbox/trunk/cleverbox/client.py

    r182 r184  
    44 
    55import os 
    6 from cleverbox import project 
    76from cleverbox.utils import filesystem 
    87 
     
    155154 
    156155    if enable_client == 'y': 
    157         self._do_client_enable(client_name) 
     156        enable(environment,client_name) 
    158157 
    159158    print 
     
    184183    # Client is enabled, propose disabling it 
    185184    client_disabled = True 
    186     if client_name in self._get_clients('enabled'): 
     185    if client_name in get(environment, 'enabled'): 
    187186        client_disabled = False 
    188187        print "You can not remove an enabled client. Disabling it." 
     
    197196 
    198197    # Disable client 
    199     client_apacheconf = os.path.join( self.env.path, 'clients-available', client_name ) 
     198    client_apacheconf = os.path.join(environment.path, 'clients-available', client_name) 
    200199    os.unlink(client_apacheconf) 
    201200     
     
    214213        raise Exception, 'Client "%s" is already enabled.' % client_name 
    215214 
    216     target = os.path.join(self.env.path, 'clients-available', client_name) 
    217     linkname = os.path.join(self.env.path, 'clients-enabled', client_name) 
     215    target = os.path.join(environment.path, 'clients-available', client_name) 
     216    linkname = os.path.join(environment.path, 'clients-enabled', client_name) 
    218217    os.symlink(target, linkname) 
    219218 
     
    232231        raise Exception, 'Client "%s" is already enabled.' % client_name 
    233232 
    234     linkname = os.path.join(self.env.path, 'clients-enabled', client_name) 
     233    linkname = os.path.join(environment.path, 'clients-enabled', client_name) 
    235234    os.unlink(linkname) 
    236235     
  • cleverbox/trunk/cleverbox/scripts/admin.py

    r182 r184  
    11# -*- coding: utf-8 -*- 
    22 
    3 import shutil, cmd, os, shlex, sys, traceback, re 
    4 import ConfigParser, posix 
    5 from pkg_resources import parse_version 
     3import cmd, os, shlex, sys 
    64from trac import util 
    75from trac.scripts.admin import TracAdmin 
    86from cleverbox.utils import termcolors 
    97from cleverbox.environment import Environment 
    10 from cleverbox import client 
     8from cleverbox import client, project 
    119 
    1210_version = '0.5dev' 
     
    6967        # Set shell prompt 
    7068        self.prompt = "Cleverbox [%s] > " % self.env.path 
    71          
    72         # Read configuration 
    73         # TODO : move to environment.py ? 
    74         self._config = ConfigParser.SafeConfigParser() 
    75         self._config.read(self.env.get_path('cleverbox.ini')) 
    7669 
    7770    def emptyline(self): 
     
    233226 
    234227    def _do_client_add(self, client_name): 
    235         client.create(self.env, client_name) 
     228        client.add(self.env, client_name) 
    236229 
    237230    def _do_client_remove(self, client_name): 
     
    259252    _help_project = [('project list', 'Lists available projects'), 
    260253                    ('project add <client> <name>', 'Adds a project'), 
    261                     ('project remove <client> <name>', 'Deletes a project'), 
    262254                    ('project enable <client> <name>', 'Enables a project'), 
    263255                    ('project disable <client> <name>', 'Disables a project')] 
     
    288280        clients = client.get() 
    289281        for client_name in clients: 
    290             client_projects[client_name] = project.get(environment, client_name) 
     282            client_projects[client_name] = project.get(self.env, client_name) 
    291283 
    292284        print client_projects 
    293285 
    294286 
    295     def _project_exists(self, client_name, project_name, project_status = None): 
    296         return project_name in self._get_projects(client_name, project_status) 
    297  
    298     def _get_projects(self, client_name = None, status = None): 
    299         """ 
    300         TODO : Extend command options in order to provide better filtering (client, enabled / disabled) 
    301         """ 
    302         list_projects = [] 
    303  
    304         # -- List of requested projects 
    305         enabled_projects_dir = 'projects-enabled' 
    306         all_projects_dir     = 'projects-available' 
    307  
    308         list_enabled_projects = os.listdir(os.path.join(self.env.path, enabled_projects_dir)) 
    309         list_all_projects = os.listdir(os.path.join(self.env.path, all_projects_dir)) 
    310  
    311         list_projects = [] 
    312         if (status == None): 
    313             list_projects = list_all_projects 
    314         if (status == 'enabled'): 
    315             list_projects = list_enabled_projects 
    316         if (status == 'disabled'): 
    317             for p in list_all_projects: 
    318                 if p not in list_enabled_projects: 
    319                     list_projects.append(p) 
    320  
    321         # Restrict to requested client 
    322         pattern = re.compile('(\w+)-(.*)') 
    323         if (client_name): 
    324             client_projects = [] 
    325             for project_name in list_projects: 
    326                 matches = pattern.findall(project_name) 
    327                 if (client_name == matches[0][0]): 
    328                     client_projects.append(matches[0][1]) 
    329             list_projects = client_projects 
    330  
    331         return list_projects 
    332  
    333287    def _do_project_disable(self, args): 
    334         if len(args) == 2: 
    335             (client_name, project_name) = args 
    336             if (self._project_exists(client_name, project_name)): 
    337                 try: 
    338                     os.unlink( os.path.join(self.env.path, 'projects-enabled', '%s-%s' % (client_name, project_name)) ) 
    339                     print "Project '%s' has been disabled. Apache needs to be reloaded." % project_name 
    340                 except (IOError, os.error), exception: 
    341                         print "** Project '%s' is already disabled." % project_name 
    342  
    343             else: 
    344                 print "** Client '%s' has no project '%s'" % (client_name, project_name) 
    345         else: 
    346             print "** Invalid syntax" 
     288         
     289        # Check syntax 
     290        if not len(args) == 2: 
    347291            self.do_help('project') 
     292            raise Exception, 'Invalid syntax' 
     293         
     294        # Disable project 
     295        (client_name, project_name) = args 
     296        project.disable(environment, client_name, project_name) 
     297 
    348298 
    349299    def _do_project_enable(self, args): 
    350         if len(args) == 2: 
    351             (client_name, project_name) = args 
    352             if self._project_exists(client_name, project_name): 
    353                 try: 
    354                     target = os.path.join( self.env.path, 
    355                                           'projects-available', 
    356                                           '%s-%s' % (client_name, project_name) ) 
    357                     linkname = os.path.join( self.env.path, 
    358                                           'projects-enabled', 
    359                                           '%s-%s' % (client_name, project_name) ) 
    360                     os.symlink( target, linkname ) 
    361                     print "Project '%s' has been enabled. Apache needs to be reloaded." % project_name 
    362                 except Exception, e: 
    363                     print e 
    364  
    365             else: 
    366                 print "** Client '%s' has no project '%s'" % (client_name, project_name) 
    367         else: 
    368             print "** Invalid syntax" 
     300        if not len(args) == 2: 
    369301            self.do_help('project') 
    370  
    371     def _do_project_remove(self, args): 
    372         print "** TODO : This command has yet to be implemented." 
    373  
     302            raise Exception, 'Invalid syntax' 
     303             
    374304        (client_name, project_name) = args 
    375  
    376         # Confirm deletion 
    377         continue_removal = False 
    378         print "You are about to remove project '%s'." % project_name 
    379         confirm_removal = raw_input('Remove project ? [y/N]> ').strip() or False 
    380         if confirm_removal == 'y': 
    381             continue_removal = True 
    382  
    383         if not continue_removal: 
    384             print "Project '%s' was *not* removed\n" % project_name 
    385             return 
    386  
    387         # Disable project 
    388         if self._project_exists(client_name, project_name, 'enabled'): 
    389             print "You cannot remove an enabled project. Disabling it." 
    390             self._do_project_disable(args) 
    391  
    392         # Delete apache config file 
    393         try: 
    394             linkname = os.path.join( self.env.path, 'projects-available', '%s-%s'% (client_name, project_name) ) 
    395             os.unlink( linkname ) 
    396             print "Project '%s' has been removed" % project_name 
    397             print "Apache configuration needs to be reloaded for this to be effective." 
    398         except (IOError, os.error), exception: 
    399             print "** An error occured. Project was NOT removed. Report the following message to the sysadmin." 
    400             print exception 
    401  
    402     def _do_project_add(self, args): 
    403         if len(args) == 2: 
    404             client_name = args[0] 
    405             project_name = args[1] 
    406  
    407             # Make sure client exists 
    408             if not self._client_exists(client_name): 
    409                 print "Client '%s' does not exist !" % client_name 
    410                 return 
    411             # Make sure project does not already exists 
    412             if self._project_exists(client_name, project_name): 
    413                 print "Client '%s' already has a project named '%s'" % (client_name, project_name) 
    414                 return 
    415  
    416             # Information collection 
    417             collected_infos = { 
    418                 'client'     : client_name, 
    419                 'short_name' : project_name, 
    420                 'full_name'  : None 
    421                 } 
    422  
    423             print 
    424             print "Creating a new project for client '%s'" % client_name 
    425             print "Let's collect some informations about the project :" 
    426             print 
    427             print "  Please enter project's full name." 
    428             print "  This will be displayed in various places and emails." 
    429             print 
    430  
    431             dfn = project_name.capitalize() 
    432             collected_infos['full_name'] = raw_input('Full Name [%s]> ' % dfn).strip() or dfn 
    433  
    434             print 
    435             print "  What configuration profile should be used ?" 
    436             print "  Those reside in %s/profiles/" % self.env.path 
    437             print 
    438  
    439             dp = self.env.config.get('general', 'default_profile') 
    440             collected_infos['profile'] = raw_input('Configuration profile [%s]> ' % dp).strip() or dp 
    441  
    442             # Project creation 
    443             print 
    444             print "Supplied informations verified." 
    445             print "Let's proceed with project creation :" 
    446             print 
    447  
    448             try: 
    449                 # -- Apache configuration file 
    450                 self._project_write_apache_conf( collected_infos ) 
    451  
    452                 # -- Create required dirs 
    453                 self._project_create_dirs( collected_infos ) 
    454  
    455                 # -- SVN repository creation 
    456                 self._project_create_svn_repos( collected_infos ) 
    457  
    458                 # -- Trac environment initialisation 
    459                 self._project_trac_initenv( collected_infos ) 
    460  
    461                 # -- Trac initial permissions 
    462                 self._project_trac_setperms( collected_infos ) 
    463  
    464                 # -- Modifies Trac default conf 
    465                 self._project_trac_defaultconf( collected_infos ) 
    466                  
    467                 # -- Fix perms 
    468                 self._project_fix_perms( collected_infos ) 
    469  
    470             except Exception, e: 
    471                 print "An error occured :" 
    472                 print e 
    473                 traceback.print_exc() 
    474  
    475             # -- Enable client ? 
    476             print "Project has been created. Do you want to enable it ?" 
    477             print 
    478             enable_project = raw_input('Enable project ? [y/N]> ').strip() or False 
    479  
    480             if enable_project.find('y') == 0: 
    481                 self._do_project_enable((client_name, project_name)) 
    482  
    483         else: 
     305        project.enable(environment, client_name, project_name) 
     306 
     307    def _do_project_add(self, args, t): 
     308        if not len(args) == 2: 
    484309            self.do_help('project') 
    485  
    486     def _project_create_dirs(self, infos): 
    487         os.makedirs(os.path.join(self.self.env.config.get('general', 'clients_root'), 
    488                                  infos['client'], 
    489                                  'htdocs', 
    490                                  infos['short_name']), 0775) 
    491  
    492         print "  Creating project's directory layout\n" 
    493  
    494     def _project_write_apache_conf(self, infos): 
    495         """ 
    496         TODO : clients may not be stored in 'clients_root', be careful with that. 
    497         """ 
    498         conf_template = open(os.path.join(self.env.path, 'profiles', infos['profile'], 'project.apache.conf')) 
    499         conf_data = conf_template.read() % {'client_name'      : infos['client'], 
    500                                             'project_name'     : infos['short_name'], 
    501                                             'clients_root'     : self.env.config.get('general', 'clients_root'), 
    502                                             'authbackend_pass' : self.env.config.get('general', 'authbackend_pass'), 
    503                                             'trac_install_dir' : self.env.config.get('trac', 'lib_dir'), 
    504                                             'domain_name'      : self.env.config.get('general', 'domain')} 
    505  
    506         apache_conf_filepath = os.path.join( self.env.path, 'projects-available', '%s-%s' % (infos['client'], infos['short_name']) ) 
    507         f = file(apache_conf_filepath, 'w+') 
    508         f.write(conf_data) 
    509         f.close() 
    510  
    511         print "  Apache configuration written to %s\n" % apache_conf_filepath 
    512  
    513     def _project_create_svn_repos(self, infos): 
    514         repos_path = os.path.join( self.env.config.get('general', 'clients_root'), infos['client'], 'var/svn', infos['short_name'] ) 
    515         create_cmd = 'svnadmin create %s' % repos_path 
    516         (stdin, stdout, stderr) = os.popen3( create_cmd ) 
    517  
    518         err = stderr.read() 
    519         if err: 
    520             raise Exception( err ) 
    521  
    522         print "  Subversion repository created in %s\n" % repos_path 
    523  
    524     def _project_trac_initenv(self, infos): 
    525  
    526         trac_env_path = os.path.join( self.env.config.get('general', 'clients_root'), 
    527                                      infos['client'], 
    528                                      'var/trac', 
    529                                      infos['short_name'] ) 
    530  
    531         svn_path = os.path.join( self.env.config.get('general', 'clients_root'), 
    532                                 infos['client'], 
    533                                 'var/svn', 
    534                                 infos['short_name'] ) 
    535          
    536         cmd_data = { 'env_path'         : trac_env_path, 
    537                      'title'            : '"%s - %s - Trac"' % (infos['client'], infos['short_name']), 
    538                      'db_dsn'           : 'sqlite:db/trac.db', 
    539                      'svn_path'         : svn_path, 
    540                      'templates_path'   : '%s/templates' % self.env.config.get('trac', 'assets_dir'), 
    541                      'trac_install_dir' : self.env.config.get('trac', 'lib_dir')} 
    542  
    543         trac_cmd = '/usr/bin/trac-admin %(env_path)s initenv %(title)s %(db_dsn)s svn %(svn_path)s %(templates_path)s' % cmd_data 
    544          
    545         (stdin, stdout, stderr) = os.popen3( trac_cmd ) 
    546  
    547         err = stderr.read() 
    548         if err: 
    549             err = stdout.read() 
    550             raise Exception( err ) 
    551  
    552         print "  Trac project initialized in %s\n" % trac_env_path 
    553  
    554     def _project_trac_setperms(self, infos): 
    555         trac_env_path = os.path.join( self.env.config.get('general', 'clients_root'), 
    556                                      infos['client'], 
    557                                      'var/trac', 
    558                                      infos['short_name'] ) 
    559  
    560         # Perms for authenticated users 
    561         default_perms = ( 'BROWSER_VIEW', 
    562                           'CHANGESET_VIEW', 
    563                           'FILE_VIEW', 
    564                           'LOG_VIEW', 
    565                           'MILESTONE_VIEW', 
    566                           'REPORT_SQL_VIEW', 
    567                           'REPORT_VIEW', 
    568                           'ROADMAP_VIEW', 
    569                           'SEARCH_VIEW', 
    570                           'TICKET_CREATE', 
    571                           'TICKET_MODIFY', 
    572                           'TICKET_VIEW', 
    573                           'TIMELINE_VIEW', 
    574                           'WIKI_CREATE', 
    575                           'WIKI_MODIFY', 
    576                           'WIKI_VIEW' ) 
    577  
    578         trac_perms_cmd = 'trac-admin %(env_path)s permission %(subcommand)s %(subject)s %(perms)s' 
    579  
    580         # Remove all anonymous permissions 
    581         os.system( trac_perms_cmd % {'env_path'   : trac_env_path, 
    582                                      'subcommand' : 'remove', 
    583                                      'subject'    : 'anonymous', 
    584                                      'perms'      : ' '.join(default_perms)} ) 
    585  
    586         # Grant default permissions 
    587         perms_config = ConfigParser.SafeConfigParser() 
    588         perms_config.read(os.path.join(self.env.path, 'profiles', infos['profile'], 'permissions.ini')) 
    589         for profile in perms_config.options('trac'): 
    590             os.system( trac_perms_cmd % {'env_path'   : trac_env_path, 
    591                                          'subcommand' : 'add', 
    592                                          'subject'    : profile, 
    593                                          'perms'      : perms_config.get('trac', profile)} ) 
    594  
    595         # Let user choose who gets admin rights 
    596         print "  Please enter trac administrator username." 
    597         print "  This user will be granted full privileges on project's Trac instance." 
    598         print 
    599  
    600         dan = infos['short_name'] + '-admin' 
    601         admin_login = raw_input('Admin Login [%s]> ' % dan).strip() or dan 
    602  
    603         os.system( trac_perms_cmd % {'env_path'   : trac_env_path, 
    604                                      'subcommand' : 'add', 
    605                                      'subject'    : admin_login, 
    606                                      'perms'      : 'TRAC_ADMIN'} ) 
    607         print 
    608         print "  Trac initial permissions set (admin rights given to '%s')\n" % admin_login 
    609  
    610     def _project_fix_perms(self, infos): 
    611         """ 
    612         chown -R dev:www-data /$CLIENTSROOT/$CLIENTNAME/var/svn/$PROJECTNAME 
    613         chmod g+w /$CLIENTSROOT/$CLIENTNAME/var/svn/$PROJECTNAME 
    614         chown -R www-data:dev /$CLIENTSROOT/$CLIENTNAME/var/trac/$PROJECTNAME/db 
    615             chown dev:www-data /$CLIENTSROOT/$CLIENTNAME/var/trac/conf/trac.ini 
    616             chmod g+w /$CLIENTSROOT/$CLIENTNAME/var/trac/conf/trac.ini 
    617         """ 
    618  
    619         # Trac DB 
    620         trac_db_path   = os.path.join(self.env.config.get('general', 'clients_root'), 
    621                                       infos['client'], 
    622                                       'var/trac', 
    623                                       infos['short_name'], 
    624                                       'db') 
    625         self._rchown(trac_db_path,  
    626                      get_uid_from_name(self.env.config.get('general', 'apache_user')), 
    627                      get_gid_from_name(self.env.config.get('general', 'ssh_group'))) 
    628  
    629         # Trac attachments 
    630         trac_attachments_path = os.path.join( self.env.config.get('general', 'clients_root'), 
    631                                              infos['client'], 
    632                                              'var/trac', 
    633                                              infos['short_name'], 
    634                                              'attachments' ) 
    635  
    636         self._rchown(trac_attachments_path , 
    637                      get_uid_from_name(self.env.config.get('general', 'apache_user')), 
    638                      get_gid_from_name(self.env.config.get('general', 'ssh_group'))) 
    639  
    640         # Trac conf 
    641         trac_ini_path   = os.path.join( self.env.config.get('general', 'clients_root'), 
    642                                        infos['client'], 
    643                                        'var','trac', 
    644                                        infos['short_name'], 
    645                                        'conf','trac.ini' ) 
    646         os.chmod( trac_ini_path, 0777 )  
    647  
    648         # Subversion repository 
    649         svn_repos_path = os.path.join( self.env.config.get('general', 'clients_root'), 
    650                                       infos['client'], 
    651                                       'var/svn', 
    652                                       infos['short_name'] ) 
    653  
    654         self._rchown(svn_repos_path,  
    655                      get_uid_from_name(self.env.config.get('general', 'apache_user')),  
    656                      get_gid_from_name(self.env.config.get('general', 'ssh_group'))) 
    657          
    658         os.chmod( svn_repos_path, 0775 ) 
    659  
    660         print "  Perms fixed\n" 
    661  
    662     def _project_trac_defaultconf(self, infos): 
    663         """ 
    664         Overrides project's default trac.ini with values provided in configuration profile. 
    665         """ 
    666          
    667         # New defaults 
    668         tracdefaults_config = ConfigParser.SafeConfigParser() 
    669         tracdefaults_config.read(os.path.join(self.env.path, 'profiles', infos['profile'], 'trac-defaults.ini')) 
    670          
    671         # Trac base config file 
    672         project_config_path = os.path.join(self.env.config.get('general', 'clients_root', infos['client'], 'var', 'trac', infos['short_name'], 'conf', 'trac.ini')) 
    673         tracproject_config = ConfigParser.SafeConfigParser() 
    674         tracproject_config.read(project_config_path) 
    675  
    676         # Overriding 
    677         for section in tracdefaults_config.sections(): 
    678             if not tracproject_config.has_section(section): 
    679                 tracproject_config.add_section(section) 
    680             for option in tracdefaults_config.options(section): 
    681                 # Perform variable substituion in each default option 
    682                 # It is probably not very good in term of performances, but we'll wait until someone complains to fix it 
    683                 default_option = tracdefaults_config.get(section, option) % {'client_name'      : infos['client'], 
    684                                                                              'project_name'     : infos['short_name'], 
    685                                                                              'clients_root'     : self.env.config.get('general', 'clients_root'), 
    686                                                                              'authbackend_pass' : self.env.config.get('general', 'authbackend_pass'), 
    687                                                                              'trac_install_dir' : self.env.config.get('trac', 'lib_dir'), 
    688                                                                              'domain_name'      : self.env.config.get('general', 'domain')} 
    689                 tracproject_config.set(section, option, default_option) 
    690  
    691         fp = open(project_config_path, 'w+') 
    692         tracproject_config.write(fp) 
     310            raise Exception, 'Invalid syntax' 
     311 
     312        (client_name, project_name) = args 
     313        project.add(self.env, client_name, project_name) 
    693314 
    694315    def complete_project(self, text, line, begidx, endidx): 
     
    707328    def _complete_project_add(self, args): 
    708329        comp = [] 
    709  
    710330        # "add" subcommand's first argument is client's name 
    711         if not args or (len(args) <= 1 and args[0] not in self._get_clients()): 
    712             comp = self._get_clients() 
     331        if not args or (len(args) <= 1 and args[0] not in client.get(self.env, args[0])): 
     332            comp = client.get(self.env) 
    713333 
    714334        return comp 
     
    718338 
    719339        # "enable" subcommand's first argument is client's name 
    720         if not args or (len(args) <= 1 and args[0] not in self._get_clients()): 
    721             comp = self._get_clients() 
     340        if not args or (len(args) <= 1 and args[0] not in client.get(self.env)): 
     341            comp = client.get(self.env) 
    722342        # "enable" subcommand second argument is project's name 
    723343        else : 
    724             comp = self._get_projects(args[0], 'disabled') 
     344            comp = project.get(self.env, args[0], 'disabled') 
    725345 
    726346        return comp 
     
    730350 
    731351        # "disable" subcommand's first argument is client's name 
    732         if not args or (len(args) <= 1 and args[0] not in self._get_clients()): 
    733             comp = self._get_clients() 
     352        if not args or (len(args) <= 1 and args[0] not in client.get(self.env)): 
     353            comp = client.get(self.env) 
    734354        # "disable" subcommand second argument is project's name 
    735355        else : 
    736             comp = self._get_projects(args[0], 'enabled') 
     356            comp = project.get(self.env, args[0], 'enabled') 
    737357 
    738358        return comp 
     
    742362 
    743363        # "remove" subcommand's first argument is client's name 
    744         if not args or (len(args) <= 1 and args[0] not in self._get_clients()): 
    745             comp = self._get_clients() 
     364        if not args or (len(args) <= 1 and args[0] not in client.get(self.env)): 
     365            comp = client.get(self.env) 
    746366        # "remove" subcommand second argument is project's name 
    747367        else : 
    748             comp = self._get_projects(args[0]) 
     368            comp = project.get(self.env, args[0]) 
    749369 
    750370        return comp 
  • cleverbox/trunk/cleverbox/utils/filesystem.py

    r183 r184  
    1818                    os.chown(direntry, uid, gid) 
    1919                    os.chdir(direntry) 
    20                     self._rchown(direntry, uid, gid) 
     20                    chowntree(direntry, uid, gid) 
    2121                else: 
    2222                    os.chown(direntry, uid, gid) 
  • cleverbox/trunk/setup.py

    r177 r184  
    66It provides an interactive shell for deploying and maintaining instances of both projects. 
    77""" 
    8  
    9 # Automatically install setuptools if needed. 
    10 # User must have internet access 
    11 # See http://peak.telecommunity.com/DevCenter/setuptools#using-setuptools-without-bundling-it 
    12 import ez_setup 
    13 ez_setup.use_setuptools() 
    148 
    159from glob import glob