lib/gdk/diagnostic/postgresql.rb (118 lines of code) (raw):

# frozen_string_literal: true module GDK module Diagnostic class Postgresql < Base TITLE = 'PostgreSQL' def success? @success ||= data_dir_version && versions_ok? && can_create_postgres_socket? && valid_ldflags? end def detail return if success? output = [] output << version_problem_message unless versions_ok? output << cant_create_socket_message unless can_create_postgres_socket? output << invalid_ldflags_message unless valid_ldflags? output.join("\n#{diagnostic_detail_break}\n") end private def version_problem_message cmd_version = psql_version || 'unknown' data_version = data_dir_version || 'unknown' <<~MESSAGE `psql` is version #{cmd_version}, but your PostgreSQL data dir is using version #{data_version}. Check that your PATH is pointing to the right PostgreSQL version, or see the PostgreSQL upgrade guide: https://gitlab.com/gitlab-org/gitlab-development-kit/-/blob/main/doc/howto/postgresql.md#upgrade-postgresql MESSAGE end def can_create_postgres_socket? return true if GDK::Postgresql.new.use_tcp? # use a temporary file the same character length as 'postgresql/.s.PGSQL.port' # port max is 65535, so assume 5 characters for the port number # socket_path = config.gdk_root.join('postgresql_.s.PGSQL.XXXXX') socket_path = config.gdk_root.join('postgresql_.s.PGSQL.XXXXX').to_s can_create_socket?(socket_path) end def cant_create_socket_message <<~MESSAGE GDK directory's character length (#{config.gdk_root.to_s.length}) is too long to support the creation of a UNIX socket for Postgres: #{config.gdk_root} Try using a shorter directory path for GDK or use TCP for Postgres. MESSAGE end def versions_ok? psql_command.success? && psql_version && data_dir_version && versions_match? end def versions_match? if psql_version >= 10 data_dir_version.to_i == psql_version.to_i else # Avoid floating point comparison issues by using rationals data_dir_version.to_r.round(2) == psql_version.to_r.round(2) end end def psql_version return unless psql_command.success? match = psql_command.read_stdout&.match(/psql \(PostgreSQL\) (.*)/) return unless match match[1].to_f end def psql_command @psql_command ||= begin psql = config.postgresql.bin_dir.join('psql') Shellout.new(%W[#{psql} --version]).execute(display_output: false, display_error: false) end end def data_dir_version return unless File.exist?(data_dir_version_filename) @data_dir_version ||= File.read(data_dir_version_filename).to_f end def data_dir_version_filename @data_dir_version_filename ||= File.join(config.postgresql.data_dir, 'PG_VERSION') end def invalid_ldflags_message <<~MESSAGE #{@pgconfig_error} This may indicate a potential issue with the PostgreSQL installation, and we recommend reinstalling PostgreSQL. You can try running the following to reinstall PostgreSQL: #{reinstall_message} MESSAGE end def reinstall_message manager = asdf? ? 'asdf' : 'mise' "#{manager} uninstall postgres #{psql_version} && #{manager} install postgres #{psql_version}" end def asdf? GDK::Dependencies.asdf_available? end def valid_ldflags? return @valid_ldflags if defined?(@valid_ldflags) @valid_ldflags = pg_config_valid? end def pg_config_valid? return true unless pgvector_enabled? unless pg_config_ldflags.include?('-isysroot') @pgconfig_error = 'The `-isysroot` value not present in `pg_config --ldflags`.' return false end isysroot_path = pg_config_ldflags[/-isysroot\s(\S+)/, 1] unless Dir.exist?(isysroot_path) @pgconfig_error = "The `-isysroot` path #{isysroot_path} does not exist." return false end if macos? && !isysroot_path_matches_sdk?(isysroot_path, xcrun_sdk_path) @pgconfig_error = "The `pg_config --ldflags` shows #{isysroot_path}, but `xcrun --show-sdk-path` shows #{xcrun_sdk_path}." return false end true end def pgvector_enabled? config.pgvector.enabled end def isysroot_path_matches_sdk?(isysroot_path, xcrun_sdk_path) File.realpath(isysroot_path) == File.realpath(xcrun_sdk_path) end def macos? RUBY_PLATFORM.include?('darwin') end def pg_config_ldflags @pg_config_ldflags ||= Shellout.new('pg_config --ldflags').execute(display_output: false).read_stdout end def xcrun_sdk_path @xcrun_sdk_path ||= Shellout.new('xcrun --show-sdk-path').execute(display_output: false).read_stdout.to_s end def config GDK.config end end end end