mirror of
				https://github.com/psycopg/psycopg2.git
				synced 2025-10-31 15:57:31 +03:00 
			
		
		
		
	Refactoring of the pg_config detection code in setup.py
Pull all state and path searching into it's own class.
This commit is contained in:
		
							parent
							
								
									816b5dda33
								
							
						
					
					
						commit
						f3526d0630
					
				
							
								
								
									
										268
									
								
								setup.py
									
									
									
									
									
								
							
							
						
						
									
										268
									
								
								setup.py
									
									
									
									
									
								
							|  | @ -45,7 +45,6 @@ Operating System :: Unix | ||||||
| # Note: The setup.py must be compatible with both Python 2 and 3 | # Note: The setup.py must be compatible with both Python 2 and 3 | ||||||
| 
 | 
 | ||||||
| import os | import os | ||||||
| import os.path |  | ||||||
| import sys | import sys | ||||||
| import re | import re | ||||||
| import subprocess | import subprocess | ||||||
|  | @ -54,7 +53,6 @@ from distutils.errors import DistutilsFileError | ||||||
| from distutils.command.build_ext import build_ext | from distutils.command.build_ext import build_ext | ||||||
| from distutils.sysconfig import get_python_inc | from distutils.sysconfig import get_python_inc | ||||||
| from distutils.ccompiler import get_default_compiler | from distutils.ccompiler import get_default_compiler | ||||||
| from distutils.dep_util import newer_group |  | ||||||
| from distutils.util import get_platform | from distutils.util import get_platform | ||||||
| try: | try: | ||||||
|     from distutils.msvc9compiler import MSVCCompiler |     from distutils.msvc9compiler import MSVCCompiler | ||||||
|  | @ -85,21 +83,137 @@ version_flags   = ['dt', 'dec'] | ||||||
| 
 | 
 | ||||||
| PLATFORM_IS_WINDOWS = sys.platform.lower().startswith('win') | PLATFORM_IS_WINDOWS = sys.platform.lower().startswith('win') | ||||||
| 
 | 
 | ||||||
| def get_pg_config(kind, pg_config): | 
 | ||||||
|     try: | class PostgresConfig(): | ||||||
|       p = subprocess.Popen([pg_config, "--" + kind], |     def __init__(self): | ||||||
|                            stdin=subprocess.PIPE, |         self.pg_config_exe = self.autodetect_pg_config_path() | ||||||
|                            stdout=subprocess.PIPE, |         if self.pg_config_exe is None: | ||||||
|                            stderr=subprocess.PIPE) |             sys.stderr.write("""\ | ||||||
|     except OSError: | Error: pg_config executable not found. | ||||||
|         raise Warning("Unable to find 'pg_config' file in '%s'" % pg_config) | 
 | ||||||
|     p.stdin.close() | Please add the directory containing pg_config to the PATH | ||||||
|     r = p.stdout.readline().strip() | or specify the full executable path with the option: | ||||||
|     if not r: | 
 | ||||||
|         raise Warning(p.stderr.readline()) |     python setup.py build_ext --pg-config /path/to/pg_config build ... | ||||||
|     if not isinstance(r, str): | 
 | ||||||
|         r = r.decode('ascii') | or with the pg_config option in 'setup.cfg'. | ||||||
|     return r | """) | ||||||
|  |             sys.exit(1) | ||||||
|  | 
 | ||||||
|  |     def query(self, attr_name): | ||||||
|  |         """Spawn the pg_config executable, querying for the given config | ||||||
|  |         name, and return the printed value, sanitized. """ | ||||||
|  |         try: | ||||||
|  |             pg_config_process = subprocess.Popen( | ||||||
|  |                 [self.pg_config_exe, "--" + attr_name], | ||||||
|  |                 stdin=subprocess.PIPE, | ||||||
|  |                 stdout=subprocess.PIPE, | ||||||
|  |                 stderr=subprocess.PIPE) | ||||||
|  |         except OSError: | ||||||
|  |             raise Warning("Unable to find 'pg_config' file in '%s'" % | ||||||
|  |                           self.pg_config_exe) | ||||||
|  |         pg_config_process.stdin.close() | ||||||
|  |         result = pg_config_process.stdout.readline().strip() | ||||||
|  |         if not result: | ||||||
|  |             raise Warning(pg_config_process.stderr.readline()) | ||||||
|  |         if not isinstance(result, str): | ||||||
|  |             result = result.decode('ascii') | ||||||
|  |         return result | ||||||
|  | 
 | ||||||
|  |     def autodetect_pg_config_path(self): | ||||||
|  |         """Find and return the path to the pg_config executable.""" | ||||||
|  |         if PLATFORM_IS_WINDOWS: | ||||||
|  |             return self.autodetect_pg_config_path_windows() | ||||||
|  |         else: | ||||||
|  |             return self.autodetect_pg_config_path_posix() | ||||||
|  | 
 | ||||||
|  |     def autodetect_pg_config_path_posix(self): | ||||||
|  |         """Return pg_config from the current PATH""" | ||||||
|  |         exename = 'pg_config' | ||||||
|  |         for dir in os.environ['PATH'].split(os.pathsep): | ||||||
|  |             fn = os.path.join(dir, exename) | ||||||
|  |             if os.path.isfile(fn): | ||||||
|  |                 return fn | ||||||
|  |         return None | ||||||
|  | 
 | ||||||
|  |     def autodetect_pg_config_path_windows(self): | ||||||
|  |         """Attempt several different ways of finding the pg_config | ||||||
|  |         executable on Windows, and return its full path, if found.""" | ||||||
|  |         # Find the first PostgreSQL installation listed in the registry and | ||||||
|  |         # return the full path to its pg_config utility. | ||||||
|  |         # | ||||||
|  |         # This autodetection is performed *only* if the following conditions | ||||||
|  |         # hold: | ||||||
|  |         # | ||||||
|  |         # 1) The pg_config utility is not already available on the PATH: | ||||||
|  |         if os.popen('pg_config').close() is None:  # .close()->None == success | ||||||
|  |             return None | ||||||
|  |         # 2) The user has not specified any of the following settings in | ||||||
|  |         #    setup.cfg: | ||||||
|  |         #     - pg_config | ||||||
|  |         #     - include_dirs | ||||||
|  |         #     - library_dirs | ||||||
|  |         for setting_name in ('pg_config', 'include_dirs', 'library_dirs'): | ||||||
|  |             try: | ||||||
|  |                 val = parser.get('build_ext', setting_name) | ||||||
|  |             except configparser.NoOptionError: | ||||||
|  |                 pass | ||||||
|  |             else: | ||||||
|  |                 if val.strip() != '': | ||||||
|  |                     return None | ||||||
|  |         # end of guard conditions | ||||||
|  | 
 | ||||||
|  |         try: | ||||||
|  |             import winreg | ||||||
|  |         except ImportError: | ||||||
|  |             import _winreg as winreg | ||||||
|  | 
 | ||||||
|  |         pg_inst_base_dir = None | ||||||
|  |         pg_config_path = None | ||||||
|  | 
 | ||||||
|  |         reg = winreg.ConnectRegistry(None, winreg.HKEY_LOCAL_MACHINE) | ||||||
|  |         try: | ||||||
|  |             pg_inst_list_key = winreg.OpenKey(reg, | ||||||
|  |                 'SOFTWARE\\PostgreSQL\\Installations' | ||||||
|  |               ) | ||||||
|  |         except EnvironmentError: | ||||||
|  |             pg_inst_list_key = None | ||||||
|  | 
 | ||||||
|  |         if pg_inst_list_key is not None: | ||||||
|  |             try: | ||||||
|  |                 # Determine the name of the first subkey, if any: | ||||||
|  |                 try: | ||||||
|  |                     first_sub_key_name = winreg.EnumKey(pg_inst_list_key, 0) | ||||||
|  |                 except EnvironmentError: | ||||||
|  |                     first_sub_key_name = None | ||||||
|  | 
 | ||||||
|  |                 if first_sub_key_name is not None: | ||||||
|  |                     pg_first_inst_key = winreg.OpenKey(reg, | ||||||
|  |                         'SOFTWARE\\PostgreSQL\\Installations\\' | ||||||
|  |                         + first_sub_key_name | ||||||
|  |                       ) | ||||||
|  |                     try: | ||||||
|  |                         pg_inst_base_dir = winreg.QueryValueEx( | ||||||
|  |                             pg_first_inst_key, 'Base Directory' | ||||||
|  |                           )[0] | ||||||
|  |                     finally: | ||||||
|  |                         winreg.CloseKey(pg_first_inst_key) | ||||||
|  |             finally: | ||||||
|  |                 winreg.CloseKey(pg_inst_list_key) | ||||||
|  | 
 | ||||||
|  |         if pg_inst_base_dir and os.path.exists(pg_inst_base_dir): | ||||||
|  |             pg_config_path = os.path.join(pg_inst_base_dir, 'bin', | ||||||
|  |                 'pg_config.exe' | ||||||
|  |               ) | ||||||
|  |             # Support unicode paths, if this version of Python provides the | ||||||
|  |             # necessary infrastructure: | ||||||
|  |             if sys.version_info[0] < 3 \ | ||||||
|  |             and hasattr(sys, 'getfilesystemencoding'): | ||||||
|  |                 pg_config_path = pg_config_path.encode( | ||||||
|  |                     sys.getfilesystemencoding()) | ||||||
|  | 
 | ||||||
|  |         return pg_config_path | ||||||
|  | 
 | ||||||
| 
 | 
 | ||||||
| class psycopg_build_ext(build_ext): | class psycopg_build_ext(build_ext): | ||||||
|     """Conditionally complement the setup.cfg options file. |     """Conditionally complement the setup.cfg options file. | ||||||
|  | @ -126,6 +240,10 @@ class psycopg_build_ext(build_ext): | ||||||
|     boolean_options = build_ext.boolean_options[:] |     boolean_options = build_ext.boolean_options[:] | ||||||
|     boolean_options.extend(('use-pydatetime', 'have-ssl', 'static-libpq')) |     boolean_options.extend(('use-pydatetime', 'have-ssl', 'static-libpq')) | ||||||
| 
 | 
 | ||||||
|  |     def __init__(self, *args, **kwargs): | ||||||
|  |         build_ext.__init__(self, *args, **kwargs) | ||||||
|  |         self.pg_config = PostgresConfig() | ||||||
|  | 
 | ||||||
|     def initialize_options(self): |     def initialize_options(self): | ||||||
|         build_ext.initialize_options(self) |         build_ext.initialize_options(self) | ||||||
|         self.use_pg_dll = 1 |         self.use_pg_dll = 1 | ||||||
|  | @ -134,7 +252,6 @@ class psycopg_build_ext(build_ext): | ||||||
|         self.use_pydatetime = 1 |         self.use_pydatetime = 1 | ||||||
|         self.have_ssl = have_ssl |         self.have_ssl = have_ssl | ||||||
|         self.static_libpq = static_libpq |         self.static_libpq = static_libpq | ||||||
|         self.pg_config = None |  | ||||||
| 
 | 
 | ||||||
|     def get_compiler(self): |     def get_compiler(self): | ||||||
|         """Return the name of the C compiler used to compile extensions. |         """Return the name of the C compiler used to compile extensions. | ||||||
|  | @ -153,9 +270,6 @@ class psycopg_build_ext(build_ext): | ||||||
|             name = get_default_compiler() |             name = get_default_compiler() | ||||||
|         return name |         return name | ||||||
| 
 | 
 | ||||||
|     def get_pg_config(self, kind): |  | ||||||
|         return get_pg_config(kind, self.pg_config) |  | ||||||
| 
 |  | ||||||
|     def get_export_symbols(self, ext): |     def get_export_symbols(self, ext): | ||||||
|         # Fix MSVC seeing two of the same export symbols. |         # Fix MSVC seeing two of the same export symbols. | ||||||
|         if self.get_compiler().lower().startswith('msvc'): |         if self.get_compiler().lower().startswith('msvc'): | ||||||
|  | @ -248,38 +362,24 @@ class psycopg_build_ext(build_ext): | ||||||
|     def finalize_options(self): |     def finalize_options(self): | ||||||
|         """Complete the build system configuation.""" |         """Complete the build system configuation.""" | ||||||
|         build_ext.finalize_options(self) |         build_ext.finalize_options(self) | ||||||
|         if self.pg_config is None: |  | ||||||
|             self.pg_config = self.autodetect_pg_config_path() |  | ||||||
|         if self.pg_config is None: |  | ||||||
|             sys.stderr.write("""\ |  | ||||||
| Error: pg_config executable not found. |  | ||||||
| 
 |  | ||||||
| Please add the directory containing pg_config to the PATH |  | ||||||
| or specify the full executable path with the option: |  | ||||||
| 
 |  | ||||||
|     python setup.py build_ext --pg-config /path/to/pg_config build ... |  | ||||||
| 
 |  | ||||||
| or with the pg_config option in 'setup.cfg'. |  | ||||||
| """) |  | ||||||
|             sys.exit(1) |  | ||||||
| 
 | 
 | ||||||
|         self.include_dirs.append(".") |         self.include_dirs.append(".") | ||||||
|         if self.static_libpq: |         if self.static_libpq: | ||||||
|             if not self.link_objects: self.link_objects = [] |             if not self.link_objects: self.link_objects = [] | ||||||
|             self.link_objects.append( |             self.link_objects.append( | ||||||
|                     os.path.join(self.get_pg_config("libdir"), "libpq.a")) |                     os.path.join(self.pg_config.query("libdir"), "libpq.a")) | ||||||
|         else: |         else: | ||||||
|             self.libraries.append("pq") |             self.libraries.append("pq") | ||||||
| 
 | 
 | ||||||
|         try: |         try: | ||||||
|             self.library_dirs.append(self.get_pg_config("libdir")) |             self.library_dirs.append(self.pg_config.query("libdir")) | ||||||
|             self.include_dirs.append(self.get_pg_config("includedir")) |             self.include_dirs.append(self.pg_config.query("includedir")) | ||||||
|             self.include_dirs.append(self.get_pg_config("includedir-server")) |             self.include_dirs.append(self.pg_config.query("includedir-server")) | ||||||
|             try: |             try: | ||||||
|                 # Here we take a conservative approach: we suppose that |                 # Here we take a conservative approach: we suppose that | ||||||
|                 # *at least* PostgreSQL 7.4 is available (this is the only |                 # *at least* PostgreSQL 7.4 is available (this is the only | ||||||
|                 # 7.x series supported by psycopg 2) |                 # 7.x series supported by psycopg 2) | ||||||
|                 pgversion = self.get_pg_config("version").split()[1] |                 pgversion = self.pg_config.query("version").split()[1] | ||||||
|             except: |             except: | ||||||
|                 pgversion = "7.4.0" |                 pgversion = "7.4.0" | ||||||
| 
 | 
 | ||||||
|  | @ -305,94 +405,6 @@ or with the pg_config option in 'setup.cfg'. | ||||||
|         if hasattr(self, "finalize_" + sys.platform): |         if hasattr(self, "finalize_" + sys.platform): | ||||||
|             getattr(self, "finalize_" + sys.platform)() |             getattr(self, "finalize_" + sys.platform)() | ||||||
| 
 | 
 | ||||||
|     def autodetect_pg_config_path(self): |  | ||||||
|         if PLATFORM_IS_WINDOWS: |  | ||||||
|             return self.autodetect_pg_config_path_windows() |  | ||||||
|         else: |  | ||||||
|             return self.autodetect_pg_config_path_posix() |  | ||||||
| 
 |  | ||||||
|     def autodetect_pg_config_path_posix(self): |  | ||||||
|         exename = 'pg_config' |  | ||||||
|         for dir in os.environ['PATH'].split(os.pathsep): |  | ||||||
|             fn = os.path.join(dir, exename) |  | ||||||
|             if os.path.isfile(fn): |  | ||||||
|                 return fn |  | ||||||
| 
 |  | ||||||
|     def autodetect_pg_config_path_windows(self): |  | ||||||
|         # Find the first PostgreSQL installation listed in the registry and |  | ||||||
|         # return the full path to its pg_config utility. |  | ||||||
|         # |  | ||||||
|         # This autodetection is performed *only* if the following conditions |  | ||||||
|         # hold: |  | ||||||
|         # |  | ||||||
|         # 1) The pg_config utility is not already available on the PATH: |  | ||||||
|         if os.popen('pg_config').close() is None: # .close()->None == success |  | ||||||
|             return None |  | ||||||
|         # 2) The user has not specified any of the following settings in |  | ||||||
|         #    setup.cfg: |  | ||||||
|         #     - pg_config |  | ||||||
|         #     - include_dirs |  | ||||||
|         #     - library_dirs |  | ||||||
|         for settingName in ('pg_config', 'include_dirs', 'library_dirs'): |  | ||||||
|             try: |  | ||||||
|                 val = parser.get('build_ext', settingName) |  | ||||||
|             except configparser.NoOptionError: |  | ||||||
|                 pass |  | ||||||
|             else: |  | ||||||
|                 if val.strip() != '': |  | ||||||
|                     return None |  | ||||||
|         # end of guard conditions |  | ||||||
| 
 |  | ||||||
|         try: |  | ||||||
|             import winreg |  | ||||||
|         except ImportError: |  | ||||||
|             import _winreg as winreg |  | ||||||
| 
 |  | ||||||
|         pg_inst_base_dir = None |  | ||||||
|         pg_config_path = None |  | ||||||
| 
 |  | ||||||
|         reg = winreg.ConnectRegistry(None, winreg.HKEY_LOCAL_MACHINE) |  | ||||||
|         try: |  | ||||||
|             pg_inst_list_key = winreg.OpenKey(reg, |  | ||||||
|                 'SOFTWARE\\PostgreSQL\\Installations' |  | ||||||
|               ) |  | ||||||
|         except EnvironmentError: |  | ||||||
|             pg_inst_list_key = None |  | ||||||
| 
 |  | ||||||
|         if pg_inst_list_key is not None: |  | ||||||
|             try: |  | ||||||
|                 # Determine the name of the first subkey, if any: |  | ||||||
|                 try: |  | ||||||
|                     first_sub_key_name = winreg.EnumKey(pg_inst_list_key, 0) |  | ||||||
|                 except EnvironmentError: |  | ||||||
|                     first_sub_key_name = None |  | ||||||
| 
 |  | ||||||
|                 if first_sub_key_name is not None: |  | ||||||
|                     pg_first_inst_key = winreg.OpenKey(reg, |  | ||||||
|                         'SOFTWARE\\PostgreSQL\\Installations\\' |  | ||||||
|                         + first_sub_key_name |  | ||||||
|                       ) |  | ||||||
|                     try: |  | ||||||
|                         pg_inst_base_dir = winreg.QueryValueEx( |  | ||||||
|                             pg_first_inst_key, 'Base Directory' |  | ||||||
|                           )[0] |  | ||||||
|                     finally: |  | ||||||
|                         winreg.CloseKey(pg_first_inst_key) |  | ||||||
|             finally: |  | ||||||
|                 winreg.CloseKey(pg_inst_list_key) |  | ||||||
| 
 |  | ||||||
|         if pg_inst_base_dir and os.path.exists(pg_inst_base_dir): |  | ||||||
|             pg_config_path = os.path.join(pg_inst_base_dir, 'bin', |  | ||||||
|                 'pg_config.exe' |  | ||||||
|               ) |  | ||||||
|             # Support unicode paths, if this version of Python provides the |  | ||||||
|             # necessary infrastructure: |  | ||||||
|             if sys.version_info[0] < 3 \ |  | ||||||
|             and hasattr(sys, 'getfilesystemencoding'): |  | ||||||
|                 pg_config_path = pg_config_path.encode( |  | ||||||
|                     sys.getfilesystemencoding()) |  | ||||||
| 
 |  | ||||||
|         return pg_config_path |  | ||||||
| 
 | 
 | ||||||
| # let's start with macro definitions (the ones not already in setup.cfg) | # let's start with macro definitions (the ones not already in setup.cfg) | ||||||
| define_macros = [] | define_macros = [] | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue
	
	Block a user