Hi,

This is a revised partial version of Magnus' patch to pg_regress.  The
only thing this patch does is remove the dependency on sed, by having
pg_regress itself generate the .sql and .out files from the .source
files.

The motivator behind this patch is allowing the Visual C++ environment
be in the buildfarm, so while I personally think it's a dumb thing to do
;-) I think the end is worthwhile.

pg_regress now needs to have the source dir in a VPATH build, to know
where to find the source files to process.  So a new --srcdir switch was
added.

I tested it in a VPATH and a normal build, and regression test still
pass.  This is mostly Magnus' code: I merely stripped out the parts
unrelated to this change, and reworked the code a little.  So the
possible bugs are likely mine.

I also changed the Makefile so that the source file list is not
explicit, but rather a $(wildcard) thing.  This is because now
pg_regress also gets the file list using a wildcard sort of thing.  (The
file list is only used in the "clean" target, so it's likely to get
desynchronized if it has to be updated manually).

Magnus' original patch is in the queue:
http://momjian.us/mhonarc/patches/msg00000.html

-- 
Alvaro Herrera                                http://www.CommandPrompt.com/
The PostgreSQL Company - Command Prompt, Inc.
Index: src/include/port.h
===================================================================
RCS file: /home/alvherre/Code/cvs/pgsql/src/include/port.h,v
retrieving revision 1.108
diff -c -p -r1.108 port.h
*** src/include/port.h	11 Jan 2007 02:39:52 -0000	1.108
--- src/include/port.h	18 Jan 2007 17:12:47 -0000
*************** extern void get_man_path(const char *my_
*** 46,51 ****
--- 46,55 ----
  extern bool get_home_path(char *ret_path);
  extern void get_parent_directory(char *path);
  
+ /* port/dirmod.c */
+ extern char **pgfnames(char *path);
+ extern void pgfnames_cleanup(char **filenames);
+ 
  /*
   *	is_absolute_path
   *
Index: src/port/dirmod.c
===================================================================
RCS file: /home/alvherre/Code/cvs/pgsql/src/port/dirmod.c,v
retrieving revision 1.46
diff -c -p -r1.46 dirmod.c
*** src/port/dirmod.c	5 Jan 2007 22:20:02 -0000	1.46
--- src/port/dirmod.c	18 Jan 2007 21:35:11 -0000
*************** pgsymlink(const char *oldpath, const cha
*** 287,298 ****
  
  
  /*
!  * fnames
   *
!  * return a list of the names of objects in the argument directory
   */
! static char **
! fnames(char *path)
  {
  	DIR		   *dir;
  	struct dirent *file;
--- 287,300 ----
  
  
  /*
!  * pgfnames
   *
!  * return a list of the names of objects in the argument directory.  Caller
!  * must call pgfnames_cleanup later to free the memory allocated by this
!  * function.
   */
! char **
! pgfnames(char *path)
  {
  	DIR		   *dir;
  	struct dirent *file;
*************** fnames(char *path)
*** 357,368 ****
  
  
  /*
!  *	fnames_cleanup
   *
   *	deallocate memory used for filenames
   */
! static void
! fnames_cleanup(char **filenames)
  {
  	char	  **fn;
  
--- 359,370 ----
  
  
  /*
!  *	pgfnames_cleanup
   *
   *	deallocate memory used for filenames
   */
! void
! pgfnames_cleanup(char **filenames)
  {
  	char	  **fn;
  
*************** rmtree(char *path, bool rmtopdir)
*** 394,400 ****
  	 * we copy all the names out of the directory before we start modifying
  	 * it.
  	 */
! 	filenames = fnames(path);
  
  	if (filenames == NULL)
  		return false;
--- 396,402 ----
  	 * we copy all the names out of the directory before we start modifying
  	 * it.
  	 */
! 	filenames = pgfnames(path);
  
  	if (filenames == NULL)
  		return false;
*************** rmtree(char *path, bool rmtopdir)
*** 415,421 ****
  			if (!rmtree(filepath, true))
  			{
  				/* we already reported the error */
! 				fnames_cleanup(filenames);
  				return false;
  			}
  		}
--- 417,423 ----
  			if (!rmtree(filepath, true))
  			{
  				/* we already reported the error */
! 				pgfnames_cleanup(filenames);
  				return false;
  			}
  		}
*************** rmtree(char *path, bool rmtopdir)
*** 433,439 ****
  			goto report_and_fail;
  	}
  
! 	fnames_cleanup(filenames);
  	return true;
  
  report_and_fail:
--- 435,441 ----
  			goto report_and_fail;
  	}
  
! 	pgfnames_cleanup(filenames);
  	return true;
  
  report_and_fail:
*************** report_and_fail:
*** 444,449 ****
  	fprintf(stderr, _("could not remove file or directory \"%s\": %s\n"),
  			filepath, strerror(errno));
  #endif
! 	fnames_cleanup(filenames);
  	return false;
  }
--- 446,451 ----
  	fprintf(stderr, _("could not remove file or directory \"%s\": %s\n"),
  			filepath, strerror(errno));
  #endif
! 	pgfnames_cleanup(filenames);
  	return false;
  }
Index: src/test/regress/GNUmakefile
===================================================================
RCS file: /home/alvherre/Code/cvs/pgsql/src/test/regress/GNUmakefile,v
retrieving revision 1.63
diff -c -p -r1.63 GNUmakefile
*** src/test/regress/GNUmakefile	5 Jan 2007 22:20:03 -0000	1.63
--- src/test/regress/GNUmakefile	18 Jan 2007 21:37:01 -0000
*************** endif
*** 40,46 ****
  # stuff to pass into build of pg_regress
  EXTRADEFS = '-DHOST_TUPLE="$(host_tuple)"' \
  	'-DMAKEPROG="$(MAKE)"' \
! 	'-DSHELLPROG="$(SHELL)"'
  
  ##
  ## Prepare for tests
--- 40,47 ----
  # stuff to pass into build of pg_regress
  EXTRADEFS = '-DHOST_TUPLE="$(host_tuple)"' \
  	'-DMAKEPROG="$(MAKE)"' \
! 	'-DSHELLPROG="$(SHELL)"' \
! 	'-DDLSUFFIX="$(DLSUFFIX)"'
  
  ##
  ## Prepare for tests
*************** $(NAME)$(DLSUFFIX): $(shlib)
*** 83,96 ****
  	rm -f $(NAME)$(DLSUFFIX)
  	$(LN_S) $(shlib) $(NAME)$(DLSUFFIX)
  
! # Build test input and expected files
! 
! file_list := copy create_function_1 create_function_2 misc constraints tablespace
  input_files  := $(foreach file, $(file_list), sql/$(file).sql)
  output_files := $(foreach file, $(file_list), expected/$(file).out)
  
- all: $(input_files) $(output_files)
- 
  ifneq ($(PORTNAME),win32)
  abs_srcdir := $(shell cd $(srcdir) && pwd)
  abs_builddir := $(shell pwd)
--- 84,95 ----
  	rm -f $(NAME)$(DLSUFFIX)
  	$(LN_S) $(shlib) $(NAME)$(DLSUFFIX)
  
! # Test input and expected files.  These are created by pg_regress itself, so we
! # don't have a rule to create them.  We do need rules to clean them however.
! file_list := $(subst .source,, $(notdir $(wildcard $(top_srcdir)/$(subdir)/input/*.source)))
  input_files  := $(foreach file, $(file_list), sql/$(file).sql)
  output_files := $(foreach file, $(file_list), expected/$(file).out)
  
  ifneq ($(PORTNAME),win32)
  abs_srcdir := $(shell cd $(srcdir) && pwd)
  abs_builddir := $(shell pwd)
*************** abs_srcdir := $(shell cd $(srcdir) && pw
*** 99,120 ****
  abs_builddir := $(shell pwd -W)
  endif
  
- testtablespace := $(abs_builddir)/testtablespace
- 
- 
- define sed-command
- sed -e 's,@abs_srcdir@,$(abs_srcdir),g' \
-     -e 's,@abs_builddir@,$(abs_builddir),g' \
-     -e 's,@testtablespace@,$(testtablespace),g' \
-     -e 's/@DLSUFFIX@/$(DLSUFFIX)/g' $< >$@
- endef
- 
- $(input_files): sql/%.sql: input/%.source
- 	$(sed-command)
- 
- $(output_files): expected/%.out: output/%.source
- 	$(sed-command)
- 
  # When doing a VPATH build, copy over the remaining .sql and .out
  # files so that the driver script can find them.  We have to use an
  # absolute path for the targets, because otherwise make will try to
--- 98,103 ----
*************** all-spi:
*** 148,154 ****
  check: all
  	-rm -rf ./testtablespace
  	mkdir ./testtablespace
! 	./pg_regress --temp-install=./tmp_check --top-builddir=$(top_builddir) --temp-port=$(TEMP_PORT) --schedule=$(srcdir)/parallel_schedule --multibyte=$(MULTIBYTE) --load-language=plpgsql $(MAXCONNOPT) $(NOLOCALE)
  
  installcheck: all
  	-rm -rf ./testtablespace
--- 131,137 ----
  check: all
  	-rm -rf ./testtablespace
  	mkdir ./testtablespace
! 	./pg_regress --temp-install=./tmp_check --top-builddir=$(top_builddir) --srcdir=$(abs_srcdir) --temp-port=$(TEMP_PORT) --schedule=$(srcdir)/parallel_schedule --multibyte=$(MULTIBYTE) --load-language=plpgsql $(MAXCONNOPT) $(NOLOCALE)
  
  installcheck: all
  	-rm -rf ./testtablespace
Index: src/test/regress/pg_regress.c
===================================================================
RCS file: /home/alvherre/Code/cvs/pgsql/src/test/regress/pg_regress.c,v
retrieving revision 1.25
diff -c -p -r1.25 pg_regress.c
*** src/test/regress/pg_regress.c	5 Jan 2007 22:20:03 -0000	1.25
--- src/test/regress/pg_regress.c	18 Jan 2007 20:43:14 -0000
*************** static char *psqldir = NULL;
*** 95,100 ****
--- 95,101 ----
  static char *hostname = NULL;
  static int	port = -1;
  static char *user = NULL;
+ static char *srcdir = NULL;
  
  /* internal variables */
  static const char *progname;
*************** static int	success_count = 0;
*** 111,116 ****
--- 112,122 ----
  static int	fail_count = 0;
  static int	fail_ignore_count = 0;
  
+ static bool
+ directory_exists(const char *dir);
+ static void
+ make_directory(const char *dir);
+ 
  static void
  header(const char *fmt,...)
  /* This extension allows gcc to check the format string for consistency with
*************** string_matches_pattern(const char *str, 
*** 331,336 ****
--- 337,477 ----
  }
  
  /*
+  * Replace all occurances of a string in a string with a different string.
+  * NOTE: Assumes there is enough room in the target buffer!
+  */
+ static void
+ replace_string(char *string, char *replace, char *replacement)
+ {
+ 	char *ptr;
+ 
+ 	while ((ptr = strstr(string, replace)) != NULL) 
+ 	{
+ 		char *dup = strdup(string);
+ 
+ 		strncpy(string, dup, ptr - string);
+ 		string[ptr - string] = 0;
+ 		strcat(string, replacement);
+ 		strcat(string, dup + (ptr - string) + strlen(replace));
+ 		free(dup);
+ 	}
+ }
+ 
+ /*
+  * Convert *.source found in the "source" directory, replacing certain tokens
+  * in the file contents with their intended values, and put the resulting files
+  * in the "dest" directory, replacing the ".source" prefix in their names with
+  * the given suffix.
+  */
+ static void
+ convert_sourcefiles_in(char *source, char *dest, char *suffix)
+ {
+ 	char abs_srcdir[MAXPGPATH];
+ 	char abs_builddir[MAXPGPATH];
+ 	char testtablespace[MAXPGPATH];
+ 	char indir[MAXPGPATH];
+ 	char **name;
+ 	char **names;
+ #ifdef WIN32
+ 	char *c;
+ #endif
+ 
+ 	if (!getcwd(abs_builddir, sizeof(abs_builddir)))
+ 	{
+ 		fprintf(stderr, _("%s: could not get current directory: %s\n"),
+ 			progname, strerror(errno));
+ 		exit_nicely(2);
+ 	}
+ 
+ 	/*
+ 	 * in a VPATH build, use the provided source directory; otherwise, use
+ 	 * the current directory.
+ 	 */
+ 	if (srcdir)
+ 		strcpy(abs_srcdir, srcdir);
+ 	else
+ 		strcpy(abs_srcdir, abs_builddir);
+ 
+ 	snprintf(indir, MAXPGPATH, "%s/%s", abs_srcdir, source);
+ 	names = pgfnames(indir);
+ 	if (!names)
+ 		/* Error logged in pgfnames */
+ 		exit_nicely(2);
+ 
+ #ifdef WIN32
+ 	/* in Win32, replace backslashes with forward slashes */
+ 	for (c = abs_builddir; *c; c++)
+ 		if (*c == '\\')
+ 			*c = '/';
+ 	for (c = abs_srcdir; *c; c++)
+ 		if (*c == '\\')
+ 			*c = '/';
+ #endif
+ 
+ 	/* try to create the test tablespace dir if it doesn't exist */
+ 	snprintf(testtablespace, MAXPGPATH, "%s/testtablespace", abs_builddir);
+ 	if (directory_exists(testtablespace))
+ 		rmtree(testtablespace, true);
+ 	make_directory(testtablespace);
+ 
+ 	/* finally loop on each file and do the replacement */
+ 	for (name = names; *name; name++)
+ 	{
+ 		char	srcfile[MAXPGPATH];
+ 		char	destfile[MAXPGPATH];
+ 		char	prefix[MAXPGPATH];
+ 		FILE   *infile,
+ 			   *outfile;
+ 		char	line[1024];
+ 
+ 		/* reject filenames not finishing in ".source" */
+ 		if (strlen(*name) < 8)
+ 			continue;
+ 		if (strcmp(*name + strlen(*name) - 7, ".source") != 0)
+ 			continue;
+ 
+ 		/* build the full actual paths to open */
+ 		snprintf(prefix, strlen(*name) - 6, "%s", *name);
+ 		snprintf(srcfile, MAXPGPATH, "%s/%s", indir, *name);
+ 		snprintf(destfile, MAXPGPATH, "%s/%s.%s", dest, prefix, suffix);
+ 
+ 		infile = fopen(srcfile, "r");
+ 		if (!infile)
+ 		{
+ 			fprintf(stderr, _("%s: could not open file \"%s\" for reading: %s\n"),
+ 					progname, srcfile, strerror(errno));
+ 			exit_nicely(2);
+ 		}
+ 		outfile = fopen(destfile, "w");
+ 		if (!outfile)
+ 		{
+ 			fprintf(stderr, _("%s: could not open file \"%s\" for writing: %s\n"),
+ 				progname, destfile, strerror(errno));
+ 			exit_nicely(2);
+ 		}
+ 		while (fgets(line, sizeof(line), infile))
+ 		{
+ 			replace_string(line, "@abs_srcdir@", abs_srcdir);
+ 			replace_string(line, "@abs_builddir@", abs_builddir);
+ 			replace_string(line, "@testtablespace@", testtablespace);
+ 			replace_string(line, "@DLSUFFIX@", DLSUFFIX);
+ 			fputs(line, outfile);
+ 		}
+ 		fclose(infile);
+ 		fclose(outfile);
+ 	}
+ 	
+     pgfnames_cleanup(names);
+ }
+ 
+ static void
+ convert_sourcefiles(void)
+ {
+ 	convert_sourcefiles_in("input", "sql", "sql");
+ 	convert_sourcefiles_in("output", "expected", "out");
+ }
+ 
+ /*
   * Scan resultmap file to find which platform-specific expected files to use.
   *
   * The format of each line of the file is
*************** initialize_environment(void)
*** 593,598 ****
--- 734,740 ----
  			printf(_("(using postmaster on Unix socket, default port)\n"));
  	}
  
+ 	convert_sourcefiles();
  	load_resultmap();
  }
  
*************** help(void)
*** 1322,1327 ****
--- 1464,1470 ----
  	printf(_("  --outputdir=DIR           place output files in DIR (default \".\")\n"));
  	printf(_("  --schedule=FILE           use test ordering schedule from FILE\n"));
  	printf(_("                            (may be used multiple times to concatenate)\n"));
+ 	printf(_("  --srcdir=DIR              absolute path to source directory (for VPATH builds)\n"));
  	printf(_("  --temp-install=DIR        create a temporary installation in DIR\n"));
  	printf(_("  --no-locale               use C locale\n"));
  	printf(_("\n"));
*************** main(int argc, char *argv[])
*** 1369,1374 ****
--- 1512,1518 ----
  		{"port", required_argument, NULL, 14},
  		{"user", required_argument, NULL, 15},
  		{"psqldir", required_argument, NULL, 16},
+ 		{"srcdir", required_argument, NULL, 17},
  		{NULL, 0, NULL, 0}
  	};
  
*************** main(int argc, char *argv[])
*** 1461,1466 ****
--- 1605,1613 ----
  				if (strlen(optarg))
  					psqldir = strdup(optarg);
  				break;
+ 			case 17:
+ 				srcdir = strdup(optarg);
+ 				break;
  			default:
  				/* getopt_long already emitted a complaint */
  				fprintf(stderr, _("\nTry \"%s -h\" for more information.\n"),
---------------------------(end of broadcast)---------------------------
TIP 5: don't forget to increase your free space map settings

Reply via email to