# -*- cperl -*- # Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License, version 2.0, # as published by the Free Software Foundation. # # This program is also distributed with certain software (including # but not limited to OpenSSL) that is licensed under separate terms, # as designated in a particular file or component or in included license # documentation. The authors of MySQL hereby grant you an additional # permission to link the program and your derivative works with the # separately licensed software that they have included with MySQL. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License, version 2.0, for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA # # Utility functions to find files in a MySQL source or bindist # package My::Find; use strict; use Carp; use mtr_report; use My::Platform; use base qw(Exporter); our @EXPORT = qw(my_find_bin my_find_dir my_find_file NOT_REQUIRED); my $bin_extension = ".exe" if IS_WINDOWS; # Helper function to be used for fourth parameter to find functions sub NOT_REQUIRED { return 0; } # Find an executable with "name_1...name_n" in paths "path_1...path_n" # and return the full path. # # Example: # my $mysqld_exe= my_find_bin($basedir. # ["sql", "bin"], # ["mysqld", "mysqld-debug"]); # # my $mysql_exe= my_find_bin($basedir, # ["client", "bin"], # "mysql"); # # To check if something exists, use the required parameter set to 0, # the function will return an empty string if the binary is not found. # # my $mysql_exe= my_find_bin($basedir, # ["client", "bin"], # "mysql", NOT_REQUIRED); # # NOTE: # The function honours MTR_VS_CONFIG environment variable. sub my_find_bin { my ($base, $paths, $names, $required) = @_; croak "usage: my_find_bin(, , , [])" unless @_ == 4 or @_ == 3; # Find and return the first executable foreach my $path (my_find_paths($base, $paths, $names, $bin_extension)) { return $path if (-x $path or (IS_WINDOWS and -f $path)); } if (defined $required and $required == NOT_REQUIRED) { # Return empty string to indicate not found return ""; } find_error($base, $paths, $names); } # Find a file with "name_1...name_n" in paths "path_1...path_n" and # return the full path. # # Example: # my $mysqld_exe= my_find_file($basedir. # ["sql", "bin"], # "filename"); # # Also supports NOT_REQUIRED flag # # NOTE: # The function honours MTR_VS_CONFIG environment variable sub my_find_file { my ($base, $paths, $names, $required) = @_; croak "usage: my_find_file(, , , [])" unless @_ == 4 or @_ == 3; # Find and return the first executable foreach my $path (my_find_paths($base, $paths, $names, $bin_extension)) { return $path if (-f $path); } if (defined $required and $required == NOT_REQUIRED) { # Return empty string to indicate not found return ""; } find_error($base, $paths, $names); } # Find the first existing directory in one of the given paths. # # Example: # my $charset_set= my_find_dir($basedir, # ["mysql/share", "share"], # ["charset"]); # # my $charset_set= my_find_dir($basedir, # ['client_release', 'client_debug', # 'client', 'bin']); # # NOTE: # The function honours MTR_VS_CONFIG environment variable sub my_find_dir { my ($base, $paths, $dirs, $optional) = @_; croak "usage: my_find_dir(, [, [, ]])" unless (@_ == 3 or @_ == 2 or @_ == 4); # Find and return the first directory foreach my $path (my_find_paths($base, $paths, $dirs)) { return $path if (-d $path); } return "" if $optional; find_error($base, $paths, $dirs); } sub my_find_paths { my ($base, $paths, $names, $extension) = @_; # Convert the arguments into two normal arrays to ease further mappings. my (@names, @paths); push(@names, ref $names eq "ARRAY" ? @$names : $names); push(@paths, ref $paths eq "ARRAY" ? @$paths : $paths); # User can select to look in a special build dir which is a # subdirectory of any of the paths my @extra_dirs; my $build_dir = $::opt_vs_config || $ENV{MTR_VS_CONFIG} || $ENV{MTR_BUILD_DIR}; push(@extra_dirs, $build_dir) if defined $build_dir; if (defined $extension) { # Append extension to names, if name does not already # have extension map { $_ .= $extension unless /\.(.*)+$/ } @names; } # CMake generator specific (Visual Studio and Xcode have multimode builds). # Add the default extra build dirs unless a specific one has already been # selected. push(@extra_dirs, ("Release", "Relwithdebinfo", "Debug")) if @extra_dirs == 0; # Build cross product of "paths * extra_build_dirs" push( @paths, map { my $path = $_; map { "$path/$_" } @extra_dirs } @paths); # Build cross product of "paths * names" @paths = map { my $path = $_; map { "$path/$_" } @names } @paths; # Prepend base to all paths @paths = map { "$base/$_" } @paths; # Glob all paths to expand wildcards @paths = map { glob("$_") } @paths; # Return the list of paths return @paths; } sub commify { return (@_ == 0) ? '' : (@_ == 1) ? $_[0] : (@_ == 2) ? join(" or ", @_) : join(", ", @_[ 0 .. ($#_ - 1) ], "or $_[-1]"); } sub fnuttify { return map('\'' . $_ . '\'', @_); } sub find_error { my ($base, $paths, $names) = @_; my (@names, @paths); push(@names, ref $names eq "ARRAY" ? @$names : $names); push(@paths, ref $paths eq "ARRAY" ? @$paths : $paths); mtr_verbose("The paths scanned by MTR are:\n", join("\n", fnuttify(my_find_paths($base, $paths, $names))), "\n"); mtr_error("Could not find", commify(fnuttify(@names)), "in scanned directories"); } 1;