virtualenv/res/lib/lib_create_env.py
changeset 93 7b6bcc33783f
parent 91 86694f53cf8c
child 98 a14feef87fd7
equal deleted inserted replaced
92:78230b6c7b38 93:7b6bcc33783f
    24     'HTTPLIB2': { 'setup': 'python-httplib2', 'url':'http://code.google.com/p/httplib2/downloads/detail?name=httplib2-0.7.4.tar.gz&can=2&q=', 'local':"httplib2-0.7.4.tar.gz"},
    24     'HTTPLIB2': { 'setup': 'python-httplib2', 'url':'http://code.google.com/p/httplib2/downloads/detail?name=httplib2-0.7.4.tar.gz&can=2&q=', 'local':"httplib2-0.7.4.tar.gz"},
    25     'DJANGO-OAUTH-PLUS': { 'setup': 'django-oauth-plus', 'url':'http://bitbucket.org/david/django-oauth-plus/get/f314f018e473.gz', 'local':"django-oauth-plus.tar.gz"},
    25     'DJANGO-OAUTH-PLUS': { 'setup': 'django-oauth-plus', 'url':'http://bitbucket.org/david/django-oauth-plus/get/f314f018e473.gz', 'local':"django-oauth-plus.tar.gz"},
    26     'MYSQL': { 'setup': 'mysql-python', 'url': 'http://sourceforge.net/projects/mysql-python/files/mysql-python/1.2.3/MySQL-python-1.2.3.tar.gz/download', 'local':"MySQL-python-1.2.3.tar.gz"},
    26     'MYSQL': { 'setup': 'mysql-python', 'url': 'http://sourceforge.net/projects/mysql-python/files/mysql-python/1.2.3/MySQL-python-1.2.3.tar.gz/download', 'local':"MySQL-python-1.2.3.tar.gz"},
    27     'OPENID': {'setup':'openid', 'url':'http://pypi.python.org/packages/source/p/python-openid/python-openid-2.2.5.tar.gz', 'local':"python-openid-2.2.5.tar.gz"},
    27     'OPENID': {'setup':'openid', 'url':'http://pypi.python.org/packages/source/p/python-openid/python-openid-2.2.5.tar.gz', 'local':"python-openid-2.2.5.tar.gz"},
    28     'DJANGO_OPENID_CONSUMER': {'setup':'django_openid_consumer', 'url':'http://pypi.python.org/packages/source/d/django-openid-consumer/django-openid-consumer-0.1.1.tar.gz', 'local':"django-openid-consumer-0.1.1.tar.gz"},
    28     'DJANGO_OPENID_CONSUMER': {'setup':'django_openid_consumer', 'url':'http://pypi.python.org/packages/source/d/django-openid-consumer/django-openid-consumer-0.1.1.tar.gz', 'local':"django-openid-consumer-0.1.1.tar.gz"},
       
    29     'SETUPTOOLS-HG': {'setup':'setuptools_hg', 'url':'https://bitbucket.org/jezdez/setuptools_hg/get/v0.4.tar.gz', 'local':"setuptools_hg-0.4.tar.gz"},
    29     'SOCIAL_AUTH': {'setup':'social_auth', 'url':'https://github.com/omab/django-social-auth/tarball/v0.3.10', 'local':"omab-django-social-auth-v0.3.10-modified.tar.gz"},
    30     'SOCIAL_AUTH': {'setup':'social_auth', 'url':'https://github.com/omab/django-social-auth/tarball/v0.3.10', 'local':"omab-django-social-auth-v0.3.10-modified.tar.gz"},
    30     'SOUTH': { 'setup': 'South', 'url':'http://www.aeracode.org/releases/south/south-0.7.5.tar.gz', 'local':"south-0.7.5.tar.gz"},
    31     'SOUTH': { 'setup': 'South', 'url':'http://www.aeracode.org/releases/south/south-0.7.5.tar.gz', 'local':"south-0.7.5.tar.gz"},
    31     'DJANGO_GUARDIAN' : { 'setup': 'django-guardian', 'url':'http://pypi.python.org/packages/source/d/django-guardian/django-guardian-1.0.3.tar.gz', 'local':"django-guardian-1.0.3.tar.gz"},
    32     'DJANGO_GUARDIAN' : { 'setup': 'django-guardian', 'url':'http://pypi.python.org/packages/source/d/django-guardian/django-guardian-1.0.3.tar.gz', 'local':"django-guardian-1.0.3.tar.gz"},
    32     'SORL_THUMBNAIL' : { 'setup': 'sorl-thumbnail', 'url':'http://pypi.python.org/packages/source/s/sorl-thumbnail/sorl-thumbnail-11.12.tar.gz', 'local':"sorl-thumbnail-v10.12.1.tar.gz"},
    33     'SORL_THUMBNAIL' : { 'setup': 'sorl-thumbnail', 'url':'http://pypi.python.org/packages/source/s/sorl-thumbnail/sorl-thumbnail-11.12.tar.gz', 'local':"sorl-thumbnail-v10.12.1.tar.gz"},
    33     'LIBJPEG': {'setup': None, 'url':'jpegsrc.v8d.tar.gz', 'local':'jpegsrc.v8d.tar.gz'},
    34     'LIBJPEG': {'setup': None, 'url':'jpegsrc.v8d.tar.gz', 'local':'jpegsrc.v8d.tar.gz'},
    65         self.__init_url(urls)
    66         self.__init_url(urls)
    66         self.NORMAL_INSTALL = normal_installs
    67         self.NORMAL_INSTALL = normal_installs
    67 
    68 
    68     def get_src_base_path(self, fpath):
    69     def get_src_base_path(self, fpath):
    69         return os.path.abspath(os.path.join(self.src_base, fpath)).replace("\\","/")
    70         return os.path.abspath(os.path.join(self.src_base, fpath)).replace("\\","/")
    70     
    71 
    71     def __add_package_def(self, key, setup, url, local):
    72     def __add_package_def(self, key, setup, url, local):
    72         self.URLS[key] = {'setup':setup, 'url':url, 'local':self.get_src_base_path(local)}
    73         self.URLS[key] = {'setup':setup, 'url':url, 'local':self.get_src_base_path(local)}
    73 
    74 
    74     def __init_url(self, urls):
    75     def __init_url(self, urls):
    75         for key, url_dict in urls.items():
    76         for key, url_dict in urls.items():
    81 def ensure_dir(dir, logger):
    82 def ensure_dir(dir, logger):
    82     if not os.path.exists(dir):
    83     if not os.path.exists(dir):
    83         logger.notify('Creating directory %s' % dir)
    84         logger.notify('Creating directory %s' % dir)
    84         os.makedirs(dir)
    85         os.makedirs(dir)
    85 
    86 
    86 def extend_parser(parser):    
    87 def extend_parser(parser):
    87     parser.add_option(
    88     parser.add_option(
    88         '--index-url',
    89         '--index-url',
    89         metavar='INDEX_URL',
    90         metavar='INDEX_URL',
    90         dest='index_url',
    91         dest='index_url',
    91         default='http://pypi.python.org/simple/',
    92         default='http://pypi.python.org/simple/',
   106 def adjust_options(options, args):
   107 def adjust_options(options, args):
   107     pass
   108     pass
   108 
   109 
   109 
   110 
   110 def install_pylucene(option_str, extra_env, res_source_key, home_dir, lib_dir, tmp_dir, src_dir, res_env, logger, call_subprocess, filter_python_develop):
   111 def install_pylucene(option_str, extra_env, res_source_key, home_dir, lib_dir, tmp_dir, src_dir, res_env, logger, call_subprocess, filter_python_develop):
   111     
   112 
   112     logger.notify("Get Pylucene from %s " % res_env.URLS['PYLUCENE'][res_source_key])
   113     logger.notify("Get Pylucene from %s " % res_env.URLS['PYLUCENE'][res_source_key])
   113     pylucene_src = os.path.join(src_dir,"pylucene.tar.gz")
   114     pylucene_src = os.path.join(src_dir,"pylucene.tar.gz")
   114     if res_source_key == 'local':
   115     if res_source_key == 'local':
   115         shutil.copy(res_env.URLS['PYLUCENE'][res_source_key], pylucene_src)
   116         shutil.copy(res_env.URLS['PYLUCENE'][res_source_key], pylucene_src)
   116     else:
   117     else:
   117         urllib.urlretrieve(res_env.URLS['PYLUCENE'][res_source_key], pylucene_src)
   118         urllib.urlretrieve(res_env.URLS['PYLUCENE'][res_source_key], pylucene_src)
   118     tf = tarfile.open(pylucene_src,'r:gz')
   119     tf = tarfile.open(pylucene_src,'r:gz')
   119     pylucene_base_path = os.path.join(src_dir,"pylucene") 
   120     pylucene_base_path = os.path.join(src_dir,"pylucene")
   120     logger.notify("Extract Pylucene to %s " % pylucene_base_path)
   121     logger.notify("Extract Pylucene to %s " % pylucene_base_path)
   121     tf.extractall(pylucene_base_path)
   122     tf.extractall(pylucene_base_path)
   122     tf.close()
   123     tf.close()
   123     
   124 
   124     pylucene_src_path = os.path.join(pylucene_base_path, os.listdir(pylucene_base_path)[0])
   125     pylucene_src_path = os.path.join(pylucene_base_path, os.listdir(pylucene_base_path)[0])
   125     jcc_src_path = os.path.abspath(os.path.join(pylucene_src_path,"jcc"))
   126     jcc_src_path = os.path.abspath(os.path.join(pylucene_src_path,"jcc"))
   126     
   127 
   127     #install jcc
   128     #install jcc
   128 
   129 
   129     #patch for linux
   130     #patch for linux
   130     if system_str == 'Linux' :
   131     if system_str == 'Linux' :
   131         olddir = os.getcwd()
   132         olddir = os.getcwd()
   152                     cwd=jcc_src_path,
   153                     cwd=jcc_src_path,
   153                     filter_stdout=filter_python_develop,
   154                     filter_stdout=filter_python_develop,
   154                     show_stdout=True,
   155                     show_stdout=True,
   155                     extra_env={'JCC_JDK' : '/usr/lib/jvm/java-7-openjdk-i386/'})
   156                     extra_env={'JCC_JDK' : '/usr/lib/jvm/java-7-openjdk-i386/'})
   156     #install pylucene
   157     #install pylucene
   157     
   158 
   158     logger.notify("Install pylucene")
   159     logger.notify("Install pylucene")
   159     #modify makefile
   160     #modify makefile
   160     makefile_path = os.path.join(pylucene_src_path,"Makefile")
   161     makefile_path = os.path.join(pylucene_src_path,"Makefile")
   161     logger.notify("Modify makefile %s " % makefile_path)
   162     logger.notify("Modify makefile %s " % makefile_path)
   162     shutil.move( makefile_path, makefile_path+"~" )
   163     shutil.move( makefile_path, makefile_path+"~" )
   164     destination= open( makefile_path, "w" )
   165     destination= open( makefile_path, "w" )
   165     source= open( makefile_path+"~", "r" )
   166     source= open( makefile_path+"~", "r" )
   166     destination.write("PREFIX_PYTHON="+os.path.abspath(home_dir)+"\n")
   167     destination.write("PREFIX_PYTHON="+os.path.abspath(home_dir)+"\n")
   167     destination.write("ANT=ant\n")
   168     destination.write("ANT=ant\n")
   168     destination.write("PYTHON=$(PREFIX_PYTHON)/bin/python\n")
   169     destination.write("PYTHON=$(PREFIX_PYTHON)/bin/python\n")
   169     
   170 
   170     if system_str == "Darwin":
   171     if system_str == "Darwin":
   171         if sys.version_info >= (2,6):
   172         if sys.version_info >= (2,6):
   172             destination.write("JCC=$(PYTHON) -m jcc.__main__ --shared --arch x86_64 --arch i386\n")
   173             destination.write("JCC=$(PYTHON) -m jcc.__main__ --shared --arch x86_64 --arch i386\n")
   173         else:
   174         else:
   174             destination.write("JCC=$(PYTHON) -m jcc --shared --arch x86_64 --arch i386\n")
   175             destination.write("JCC=$(PYTHON) -m jcc --shared --arch x86_64 --arch i386\n")
   199     call_subprocess(['make', 'install'],
   200     call_subprocess(['make', 'install'],
   200                     cwd=os.path.abspath(pylucene_src_path),
   201                     cwd=os.path.abspath(pylucene_src_path),
   201                     filter_stdout=filter_python_develop,
   202                     filter_stdout=filter_python_develop,
   202                     show_stdout=True,
   203                     show_stdout=True,
   203                     extra_env={'JCC_JDK' : '/usr/lib/jvm/java-7-openjdk-i386/'})
   204                     extra_env={'JCC_JDK' : '/usr/lib/jvm/java-7-openjdk-i386/'})
   204     
   205 
   205 
   206 
   206 def install_psycopg2(option_str, extra_env, res_source_key, home_dir, lib_dir, tmp_dir, src_dir, res_env, logger, call_subprocess, filter_python_develop):
   207 def install_psycopg2(option_str, extra_env, res_source_key, home_dir, lib_dir, tmp_dir, src_dir, res_env, logger, call_subprocess, filter_python_develop):
   207     psycopg2_src = os.path.join(src_dir,"psycopg2.zip")
   208     psycopg2_src = os.path.join(src_dir,"psycopg2.zip")
   208     shutil.copy(res_env.URLS['PSYCOPG2'][res_source_key], psycopg2_src)
   209     shutil.copy(res_env.URLS['PSYCOPG2'][res_source_key], psycopg2_src)
   209     #extract psycopg2
   210     #extract psycopg2
   210     zf = zipfile.ZipFile(psycopg2_src)
   211     zf = zipfile.ZipFile(psycopg2_src)
   211     psycopg2_base_path = os.path.join(src_dir,"psycopg2")
   212     psycopg2_base_path = os.path.join(src_dir,"psycopg2")
   212     zf.extractall(psycopg2_base_path)
   213     zf.extractall(psycopg2_base_path)
   213     zf.close()
   214     zf.close()
   214     
   215 
   215     psycopg2_src_path = os.path.join(psycopg2_base_path, os.listdir(psycopg2_base_path)[0])
   216     psycopg2_src_path = os.path.join(psycopg2_base_path, os.listdir(psycopg2_base_path)[0])
   216     shutil.copytree(os.path.join(psycopg2_src_path, 'psycopg2'), os.path.abspath(os.path.join(home_dir, 'Lib/site-packages', 'psycopg2')))
   217     shutil.copytree(os.path.join(psycopg2_src_path, 'psycopg2'), os.path.abspath(os.path.join(home_dir, 'Lib/site-packages', 'psycopg2')))
   217     shutil.copy(os.path.join(psycopg2_src_path, 'psycopg2-2.0.14-py2.6.egg-info'), os.path.abspath(os.path.join(home_dir, 'Lib/site-packages', 'site-packages')))
   218     shutil.copy(os.path.join(psycopg2_src_path, 'psycopg2-2.0.14-py2.6.egg-info'), os.path.abspath(os.path.join(home_dir, 'Lib/site-packages', 'site-packages')))
   218 
   219 
   219 def gen_install_comp_lib(lib_name, lib_key, configure_options=[]):
   220 def gen_install_comp_lib(lib_name, lib_key, configure_options=[]):
   220     
   221 
   221     def install_lib(option_str, extra_env, res_source_key, home_dir, lib_dir, tmp_dir, src_dir, res_env, logger, call_subprocess, filter_python_develop):
   222     def install_lib(option_str, extra_env, res_source_key, home_dir, lib_dir, tmp_dir, src_dir, res_env, logger, call_subprocess, filter_python_develop):
   222         lib_src = os.path.join(src_dir,lib_name+".tar.gz")
   223         lib_src = os.path.join(src_dir,lib_name+".tar.gz")
   223         shutil.copy(res_env.URLS[lib_key][res_source_key], lib_src)
   224         shutil.copy(res_env.URLS[lib_key][res_source_key], lib_src)
   224         tf = tarfile.open(lib_src,'r:gz')
   225         tf = tarfile.open(lib_src,'r:gz')
   225         lib_base_path = os.path.join(src_dir, lib_name) 
   226         lib_base_path = os.path.join(src_dir, lib_name)
   226         logger.notify("Extract %s to %s " % (lib_name,lib_base_path))
   227         logger.notify("Extract %s to %s " % (lib_name,lib_base_path))
   227         tf.extractall(lib_base_path)
   228         tf.extractall(lib_base_path)
   228         tf.close()
   229         tf.close()
   229         
   230 
   230         lib_src_path = os.path.join(lib_base_path, os.listdir(lib_base_path)[0])
   231         lib_src_path = os.path.join(lib_base_path, os.listdir(lib_base_path)[0])
   231     
   232 
   232         logger.notify("libjpeg configure")
   233         logger.notify("libjpeg configure")
   233         call_subprocess(['configure', '--prefix='+os.path.abspath(home_dir)] + configure_options,
   234         call_subprocess(['configure', '--prefix='+os.path.abspath(home_dir)] + configure_options,
   234                         cwd=os.path.abspath(lib_src_path),
   235                         cwd=os.path.abspath(lib_src_path),
   235                         filter_stdout=filter_python_develop,
   236                         filter_stdout=filter_python_develop,
   236                         show_stdout=True)
   237                         show_stdout=True)
   237         
   238 
   238         logger.notify("libjpeg make")
   239         logger.notify("libjpeg make")
   239         call_subprocess(['make'],
   240         call_subprocess(['make'],
   240                         cwd=os.path.abspath(lib_src_path),
   241                         cwd=os.path.abspath(lib_src_path),
   241                         filter_stdout=filter_python_develop,
   242                         filter_stdout=filter_python_develop,
   242                         show_stdout=True)
   243                         show_stdout=True)
   243     
   244 
   244         logger.notify("zlib make install")
   245         logger.notify("zlib make install")
   245         call_subprocess(['make', 'install'],
   246         call_subprocess(['make', 'install'],
   246                         cwd=os.path.abspath(lib_src_path),
   247                         cwd=os.path.abspath(lib_src_path),
   247                         filter_stdout=filter_python_develop,
   248                         filter_stdout=filter_python_develop,
   248                         show_stdout=True)
   249                         show_stdout=True)
   250 
   251 
   251 install_libjpeg = gen_install_comp_lib("libjpeg", "LIBJPEG", ['--enable-shared'])
   252 install_libjpeg = gen_install_comp_lib("libjpeg", "LIBJPEG", ['--enable-shared'])
   252 install_zlib = gen_install_comp_lib("zlib", "ZLIB", [])
   253 install_zlib = gen_install_comp_lib("zlib", "ZLIB", [])
   253 
   254 
   254 
   255 
   255     
   256 
   256     
   257 
   257 
   258 
   258 def lib_generate_install_methods(path_locations, src_base, Logger, call_subprocess, normal_installs, urls=None):
   259 def lib_generate_install_methods(path_locations, src_base, Logger, call_subprocess, normal_installs, urls=None):
   259     
   260 
   260     all_urls = URLS.copy()
   261     all_urls = URLS.copy()
   261     if urls is not None:
   262     if urls is not None:
   262         all_urls.update(urls)
   263         all_urls.update(urls)
   263         
   264 
   264     res_env = ResourcesEnv(src_base, all_urls, normal_installs)
   265     res_env = ResourcesEnv(src_base, all_urls, normal_installs)
   265 
   266 
   266     def filter_python_develop(line):
   267     def filter_python_develop(line):
   267         if not line.strip():
   268         if not line.strip():
   268             return Logger.DEBUG
   269             return Logger.DEBUG
   270                        'Moving ', 'Adding ', 'running ', 'writing ', 'Creating ',
   271                        'Moving ', 'Adding ', 'running ', 'writing ', 'Creating ',
   271                        'creating ', 'Copying ']:
   272                        'creating ', 'Copying ']:
   272             if line.startswith(prefix):
   273             if line.startswith(prefix):
   273                 return Logger.DEBUG
   274                 return Logger.DEBUG
   274         return Logger.NOTIFY
   275         return Logger.NOTIFY
   275     
   276 
   276     
   277 
   277     def normal_install(key, method, option_str, extra_env, res_source_key, home_dir, tmp_dir, res_env, logger, call_subprocess):
   278     def normal_install(key, method, option_str, extra_env, res_source_key, home_dir, tmp_dir, res_env, logger, call_subprocess):
   278         logger.notify("Install %s from %s with %s" % (key,res_env.URLS[key][res_source_key],method))
   279         logger.notify("Install %s from %s with %s" % (key,res_env.URLS[key][res_source_key],method))
   279         if method == 'pip':
   280         if method == 'pip':
   280             if sys.platform == 'win32':
   281             if sys.platform == 'win32':
   281                 args = [os.path.abspath(os.path.join(home_dir, 'Scripts', 'pip')), 'install', res_env.URLS[key][res_source_key]]
   282                 args = [os.path.abspath(os.path.join(home_dir, 'Scripts', 'pip')), 'install', res_env.URLS[key][res_source_key]]
   297                 args.insert(1,option_str)
   298                 args.insert(1,option_str)
   298             call_subprocess(args,
   299             call_subprocess(args,
   299                     cwd=os.path.abspath(tmp_dir),
   300                     cwd=os.path.abspath(tmp_dir),
   300                     filter_stdout=filter_python_develop,
   301                     filter_stdout=filter_python_develop,
   301                     show_stdout=True,
   302                     show_stdout=True,
   302                     extra_env=extra_env)            
   303                     extra_env=extra_env)
   303  
   304 
   304     
   305 
   305     def after_install(options, home_dir):
   306     def after_install(options, home_dir):
   306         
   307 
   307         global logger
   308         global logger
   308         
   309 
   309         verbosity = options.verbose - options.quiet
   310         verbosity = options.verbose - options.quiet
   310         logger = Logger([(Logger.level_for_integer(2-verbosity), sys.stdout)])
   311         logger = Logger([(Logger.level_for_integer(2-verbosity), sys.stdout)])
   311 
   312 
   312         
   313 
   313         home_dir, lib_dir, inc_dir, bin_dir = path_locations(home_dir)
   314         home_dir, lib_dir, inc_dir, bin_dir = path_locations(home_dir)
   314         base_dir = os.path.dirname(home_dir)
   315         base_dir = os.path.dirname(home_dir)
   315         src_dir = os.path.join(home_dir, 'src')
   316         src_dir = os.path.join(home_dir, 'src')
   316         tmp_dir = os.path.join(home_dir, 'tmp')
   317         tmp_dir = os.path.join(home_dir, 'tmp')
   317         ensure_dir(src_dir, logger)
   318         ensure_dir(src_dir, logger)
   318         ensure_dir(tmp_dir, logger)
   319         ensure_dir(tmp_dir, logger)
   319         system_str = platform.system()
   320         system_str = platform.system()
   320         
   321 
   321         res_source_key = options.type_install
   322         res_source_key = options.type_install
   322         
   323 
   323         ignore_packages = []
   324         ignore_packages = []
   324         
   325 
   325         if options.ignore_packages :
   326         if options.ignore_packages :
   326             ignore_packages = options.ignore_packages.split(",")
   327             ignore_packages = options.ignore_packages.split(",")
   327         
   328 
   328         logger.indent += 2
   329         logger.indent += 2
   329         try:    
   330         try:
   330             for key, method, option_str, extra_env in res_env.NORMAL_INSTALL:
   331             for key, method, option_str, extra_env in res_env.NORMAL_INSTALL:
   331                 if key not in ignore_packages:
   332                 if key not in ignore_packages:
   332                     if callable(method):
   333                     if callable(method):
   333                         method(option_str, extra_env, res_source_key, home_dir, lib_dir, tmp_dir, src_dir, res_env, logger, call_subprocess, filter_python_develop)
   334                         method(option_str, extra_env, res_source_key, home_dir, lib_dir, tmp_dir, src_dir, res_env, logger, call_subprocess, filter_python_develop)
   334                     else:
   335                     else:
   335                         normal_install(key, method, option_str, extra_env, res_source_key, home_dir, tmp_dir, res_env, logger, call_subprocess)
   336                         normal_install(key, method, option_str, extra_env, res_source_key, home_dir, tmp_dir, res_env, logger, call_subprocess)
   336                             
   337 
   337             logger.notify("Clear source dir")
   338             logger.notify("Clear source dir")
   338             shutil.rmtree(src_dir)
   339             shutil.rmtree(src_dir)
   339     
   340 
   340         finally:
   341         finally:
   341             logger.indent -= 2
   342             logger.indent -= 2
   342         script_dir = join(base_dir, bin_dir)
   343         script_dir = join(base_dir, bin_dir)
   343         logger.notify('Run "%s Package" to install new packages that provide builds'
   344         logger.notify('Run "%s Package" to install new packages that provide builds'
   344                       % join(script_dir, 'easy_install'))
   345                       % join(script_dir, 'easy_install'))
   345     
   346 
   346 
   347 
   347     return adjust_options, extend_parser, after_install
   348     return adjust_options, extend_parser, after_install