Skip to content
Browse files

Merge pull request #25 from guedes/custom-templates

Custom templates
  • Loading branch information...
2 parents 91ae5ef + c8c763f commit 917967d8cc5c5dfa25ea6002aebf731983b59e2a @guedes guedes committed Nov 20, 2011
Showing with 1,343 additions and 54 deletions.
  1. +2 −2 META.json
  2. +89 −25 README.md
  3. +56 −20 Rakefile
  4. +7 −3 lib/pgxn_utils/cli.rb
  5. +14 −0 lib/pgxn_utils/no_tasks.rb
  6. +5 −0 lib/pgxn_utils/templates/c/%extension_name%.control.tt
  7. +8 −0 lib/pgxn_utils/templates/c/.gitignore.tt
  8. +1 −0 lib/pgxn_utils/templates/c/.template
  9. +37 −0 lib/pgxn_utils/templates/c/META.json.tt
  10. +24 −0 lib/pgxn_utils/templates/c/Makefile.tt
  11. +80 −0 lib/pgxn_utils/templates/c/README.md.tt
  12. +33 −0 lib/pgxn_utils/templates/c/doc/%extension_name%.md.tt
  13. +17 −0 lib/pgxn_utils/templates/c/sql/%extension_name%.sql.tt
  14. +1 −0 lib/pgxn_utils/templates/c/sql/uninstall_%extension_name%.sql.tt
  15. +26 −0 lib/pgxn_utils/templates/c/src/%extension_name%.c.tt
  16. +9 −0 lib/pgxn_utils/templates/c/test/expected/base.out.tt
  17. +10 −0 lib/pgxn_utils/templates/c/test/sql/base.sql.tt
  18. +5 −0 lib/pgxn_utils/templates/fdw/%extension_name%.control.tt
  19. +8 −0 lib/pgxn_utils/templates/fdw/.gitignore.tt
  20. +1 −0 lib/pgxn_utils/templates/fdw/.template
  21. +37 −0 lib/pgxn_utils/templates/fdw/META.json.tt
  22. +24 −0 lib/pgxn_utils/templates/fdw/Makefile.tt
  23. +80 −0 lib/pgxn_utils/templates/fdw/README.md.tt
  24. +33 −0 lib/pgxn_utils/templates/fdw/doc/%extension_name%.md.tt
  25. +31 −0 lib/pgxn_utils/templates/fdw/sql/%extension_name%.sql.tt
  26. +14 −0 lib/pgxn_utils/templates/fdw/sql/uninstall_%extension_name%.sql.tt
  27. +323 −0 lib/pgxn_utils/templates/fdw/src/%extension_name%_fdw.c.tt
  28. +4 −0 lib/pgxn_utils/templates/fdw/test/expected/base.out.tt
  29. +8 −0 lib/pgxn_utils/templates/fdw/test/sql/base.sql.tt
  30. +4 −0 lib/pgxn_utils/templates/sql/%extension_name%.control.tt
  31. +8 −0 lib/pgxn_utils/templates/sql/.gitignore.tt
  32. +1 −0 lib/pgxn_utils/templates/sql/.template
  33. +27 −0 lib/pgxn_utils/templates/sql/META.json.tt
  34. +28 −0 lib/pgxn_utils/templates/sql/Makefile.tt
  35. +80 −0 lib/pgxn_utils/templates/sql/README.md.tt
  36. +33 −0 lib/pgxn_utils/templates/sql/doc/%extension_name%.md.tt
  37. +31 −0 lib/pgxn_utils/templates/sql/sql/%extension_name%.sql.tt
  38. +21 −0 lib/pgxn_utils/templates/sql/sql/uninstall_%extension_name%.sql.tt
  39. +49 −0 lib/pgxn_utils/templates/sql/test/expected/base.out.tt
  40. +25 −0 lib/pgxn_utils/templates/sql/test/sql/base.sql.tt
  41. +1 −1 lib/pgxn_utils/version.rb
  42. +48 −3 spec/cli_spec.rb
View
4 META.json
@@ -1,7 +1,7 @@
{
"name": "pgxn_utils",
"abstract": "pgxn_utils is a development tool to create PostgreSQL extensions",
- "version": "0.1.3",
+ "version": "0.1.4dev",
"maintainer": "Dickson S. Guedes <guedes@guedesoft.net>",
"license": "postgresql",
"release_status": "stable",
@@ -14,7 +14,7 @@
"provides": {
"pgxn_utils": {
"file": "pgxn_utils",
- "version": "0.1.3"
+ "version": "0.1.4dev"
}
},
"meta-spec": {
View
114 README.md
@@ -4,7 +4,9 @@ pgxn utils
What is it?
--------
-It aims to be a set of task to help PostgreSQL extension's developers to focus more on the problem that they wants to solve than in the structure and files and control files need to PGXS to build the extension.
+It is a set of task that help developers to create PostgreSQL's extensions, putting
+the extension's files in the recomended places and supplying tasks to help bundle
+and release your extension to PGXN.
How to install it?
------------------
@@ -17,7 +19,6 @@ Or you can install it by rubygems:
gem install pgxn_utils
-
How it works?
-------------
@@ -30,6 +31,7 @@ It is all about tasks. Let's see them:
pgxn-utils help [TASK] # Describe available tasks or one specific task
pgxn-utils release filename # Release an extension to PGXN
pgxn-utils skeleton extension_name # Creates an extension skeleton in current directory
+
# Creating a new extension
@@ -38,6 +40,7 @@ It is all about tasks. Let's see them:
create my_cool_extension
create my_cool_extension/my_cool_extension.control
create my_cool_extension/.gitignore
+ create my_cool_extension/.template
create my_cool_extension/META.json
create my_cool_extension/Makefile
create my_cool_extension/README.md
@@ -47,14 +50,20 @@ It is all about tasks. Let's see them:
create my_cool_extension/test/expected/base.out
create my_cool_extension/test/sql/base.sql
-You can start creating an extension with or without version control. By default `pgxn-utils`
-supports [git](http://git-scm.org) but it will not create a repository unless you use `--git`
-option in the skeleton task.
+
+Thats it! Just start coding! ":)
+
+## Git support
+
+You can start a new extension with or without version control. By default `pgxn-utils`
+supports [git](http://git-scm.org) but it will not create a repository unless you
+use `--git` option in the skeleton task.
$ pgxn-utils skeleton my_cool_versioned_extension --git
create my_cool_versioned_extension
create my_cool_versioned_extension/my_cool_versioned_extension.control
create my_cool_versioned_extension/.gitignore
+ create my_cool_versioned_extension/.template
create my_cool_versioned_extension/META.json
create my_cool_versioned_extension/Makefile
create my_cool_versioned_extension/README.md
@@ -66,16 +75,81 @@ option in the skeleton task.
init /tmp/my_cool_versioned_extension
commit initial commit
-Thats it! Just start coding! ":)
+
+
+When you create a new extension with git support in addition to create skeleton,
+`pgxn-utils` will initialize a git repository and create the initial commit.
+
+Once you have your extension in a git repository your `bundle` will use only the
+commited files to create the archive, but if your repository is dirty then `pgxn-utils`
+will hint you to commit or stash your changes, before bundle.
+
+You must be careful with new files not added to repository, because they will NOT
+be archived.
+
+## Default templates
+
+`pgxn-utils` has three templates: `sql`, `c` and `fdw`. If you call `skeleton` without
+specifying a template the `sql` is the default. But if your extension will supply some C
+modules or you will create a FDW, you can create the extension calling `skeleton` with a
+`--template` option.
+
+ $ pgxn-utils skeleton my_cool_c_extension --template=c
+ create my_cool_c_extension
+ create my_cool_c_extension/my_cool_c_extension.control
+ create my_cool_c_extension/.gitignore
+ create my_cool_c_extension/.template
+ create my_cool_c_extension/META.json
+ create my_cool_c_extension/Makefile
+ create my_cool_c_extension/README.md
+ create my_cool_c_extension/doc/my_cool_c_extension.md
+ create my_cool_c_extension/sql/my_cool_c_extension.sql
+ create my_cool_c_extension/sql/uninstall_my_cool_c_extension.sql
+ create my_cool_c_extension/src/my_cool_c_extension.c
+ create my_cool_c_extension/test/expected/base.out
+ create my_cool_c_extension/test/sql/base.sql
+
+
+
+ $ pgxn-utils skeleton my_cool_fdw_extension --template=fdw
+ create my_cool_fdw_extension
+ create my_cool_fdw_extension/my_cool_fdw_extension.control
+ create my_cool_fdw_extension/.gitignore
+ create my_cool_fdw_extension/.template
+ create my_cool_fdw_extension/META.json
+ create my_cool_fdw_extension/Makefile
+ create my_cool_fdw_extension/README.md
+ create my_cool_fdw_extension/doc/my_cool_fdw_extension.md
+ create my_cool_fdw_extension/sql/my_cool_fdw_extension.sql
+ create my_cool_fdw_extension/sql/uninstall_my_cool_fdw_extension.sql
+ create my_cool_fdw_extension/src/my_cool_fdw_extension_fdw.c
+ create my_cool_fdw_extension/test/expected/base.out
+ create my_cool_fdw_extension/test/sql/base.sql
+
+
+The templates contains examples codes and some links to PostgreSQL documentation
+that will try to help you to start coding. SQL and C templates contains some tests
+examples, and the example code will compiles and pass `make installcheck`, but they
+are examples and you must write your own tests and code.
+
+## Custom templates
+
+If you don't like the templates provided by `pgxn-utils` you can create you own
+templates. Just create a directory where you want with at least a META.json or
+META.json.tt file then you can use your directory as argument to the `--template`
+option.
+
+To see how create your own template, you can use, as example, the
+[templates directory](https://github.com/guedes/pgxn-utils/tree/master/lib/pgxn_utils/templates).
# Changing something
-Well suppose you want to change the default maintainer's name and the license, well just do:
+Well suppose you want to change the default maintainer's name and the license, just do:
$ pgxn-utils change my_cool_extension --maintainer "Dickson Guedes" --license bsd
conflict META.json
- Overwrite /tmp/my_cool_extension/META.json? (enter "h" for help) [Ynaqdh] d
- {
+ Overwrite /tmp/my_cool_extension/META.json? (enter "h" for help) [Ynaqdh]
+ {
"name": "my_cool_extension",
"abstract": "A short description",
"description": "A long description",
@@ -103,12 +177,12 @@ Well suppose you want to change the default maintainer's name and the license, w
}
}
Retrying...
- Overwrite /tmp/my_cool_extension/META.json? (enter "h" for help) [Ynaqdh] Y
+ Overwrite /tmp/my_cool_extension/META.json? (enter "h" for help) [Ynaqdh]
force META.json
identical my_cool_extension.control
-It will wait you decide what to do.
+It will wait until you decide what to do.
For all switches that you can use with *change*, type:
@@ -134,8 +208,11 @@ For all switches that you can use with *change*, type:
# Bundling and Releasing!
Well, since you finished your work you can bundle it to send to [PGXN](http://pgxn.org).
+Note that if you have your extension in a git repository `bundle` will use only the
+commited files to create the archive, but if your repository is dirty then `pgxn-utils`
+will hint you to commit or stash your changes, before bundle.
-Bundle it:
+Let's bundle it:
$ pgxn-utils bundle my_cool_extension
create /home/guedes/extensions/my_cool_extension-0.0.1.zip
@@ -151,19 +228,6 @@ and release it:
You can export `PGXN_USER` and `PGXN_PASSWORD` environment variables to avoid
type username and password everytime.
-# Git support
-
-You can start a new extension with git support calling `skeleton` task with
-`--git` flag, then in addition to create skeleton, `pgxn-utils` will initialize
-a git repository and do a initial commit.
-
-Once you have your extension in a git repository your `bundle` will use only the
-commited files to create the archive, but if your repository is dirty then `pgxn-utils`
-will hint you to commit or stash your changes, before bundle.
-
-You must be careful with new files not added to repository, because they will NOT
-be archived.
-
# Working in progress
* improve [git](http://git-scm.org) support
View
76 Rakefile
@@ -22,6 +22,8 @@ end
desc "Generate README.md"
task :generate_readme do
rm_r "/tmp/my_cool_extension" if File.exist?("/tmp/my_cool_extension")
+ rm_r "/tmp/my_cool_c_extension" if File.exist?("/tmp/my_cool_c_extension")
+ rm_r "/tmp/my_cool_fdw_extension" if File.exist?("/tmp/my_cool_fdw_extension")
rm_r "/tmp/my_cool_versioned_extension" if File.exist?("/tmp/my_cool_versioned_extension")
readme = File.new("README.md.new", 'w')
readme.puts <<-README
@@ -31,7 +33,9 @@ pgxn utils
What is it?
--------
-It aims to be a set of task to help PostgreSQL extension's developers to focus more on the problem that they wants to solve than in all structure and files and control files need to PGXS to build the extension.
+It is a set of task that help developers to create PostgreSQL's extensions, putting
+the extension's files in the recomended places and supplying tasks to help bundle
+and release your extension to PGXN.
How to install it?
------------------
@@ -57,14 +61,56 @@ It is all about tasks. Let's see them:
$ pgxn-utils skeleton my_cool_extension
#{format_cmd_output("skeleton my_cool_extension -p /tmp")}
-You can start creating an extension with or without version control. By default `pgxn-utils`
-supports [git](http://git-scm.org) but it will not create a repository unless you use `--git`
-option in the skeleton task.
+Thats it! Just start coding! ":)
+
+## Git support
+
+You can start a new extension with or without version control. By default `pgxn-utils`
+supports [git](http://git-scm.org) but it will not create a repository unless you
+use `--git` option in the skeleton task.
$ pgxn-utils skeleton my_cool_versioned_extension --git
#{format_cmd_output("skeleton my_cool_versioned_extension --git -p /tmp")}
-Thats it! Just start coding! ":)
+
+When you create a new extension with git support in addition to create skeleton,
+`pgxn-utils` will initialize a git repository and create the initial commit.
+
+Once you have your extension in a git repository your `bundle` will use only the
+commited files to create the archive, but if your repository is dirty then `pgxn-utils`
+will hint you to commit or stash your changes, before bundle.
+
+You must be careful with new files not added to repository, because they will NOT
+be archived.
+
+## Default templates
+
+`pgxn-utils` has three templates: `sql`, `c` and `fdw`. If you call `skeleton` without
+specifying a template the `sql` is the default. But if your extension will supply some C
+modules or you will create a FDW, you can create the extension calling `skeleton` with a
+`--template` option.
+
+ $ pgxn-utils skeleton my_cool_c_extension --template=c
+#{format_cmd_output("skeleton my_cool_c_extension --template=c -p /tmp")}
+
+
+ $ pgxn-utils skeleton my_cool_fdw_extension --template=fdw
+#{format_cmd_output("skeleton my_cool_fdw_extension --template=fdw -p /tmp")}
+
+The templates contains examples codes and some links to PostgreSQL documentation
+that will try to help you to start coding. SQL and C templates contains some tests
+examples, and the example code will compiles and pass `make installcheck`, but they
+are examples and you must write your own tests and code.
+
+## Custom templates
+
+If you don't like the templates provided by `pgxn-utils` you can create you own
+templates. Just create a directory where you want with at least a META.json or
+META.json.tt file then you can use your directory as argument to the `--template`
+option.
+
+To see how create your own template, you can use, as example, the
+[templates directory](https://github.com/guedes/pgxn-utils/tree/master/lib/pgxn_utils/templates).
# Changing something
@@ -73,7 +119,7 @@ Well suppose you want to change the default maintainer's name and the license, j
$ pgxn-utils change my_cool_extension --maintainer "Dickson Guedes" --license bsd
#{format_cmd_output("change my_cool_extension -p /tmp --maintainer 'Dickson Guedes' --license bsd")}
-It will wait you decide what to do.
+It will wait until you decide what to do.
For all switches that you can use with *change*, type:
@@ -83,8 +129,11 @@ For all switches that you can use with *change*, type:
# Bundling and Releasing!
Well, since you finished your work you can bundle it to send to [PGXN](http://pgxn.org).
+Note that if you have your extension in a git repository `bundle` will use only the
+commited files to create the archive, but if your repository is dirty then `pgxn-utils`
+will hint you to commit or stash your changes, before bundle.
-Bundle it:
+Let's bundle it:
$ pgxn-utils bundle my_cool_extension
create /home/guedes/extensions/my_cool_extension-0.0.1.zip
@@ -100,19 +149,6 @@ and release it:
You can export `PGXN_USER` and `PGXN_PASSWORD` environment variables to avoid
type username and password everytime.
-# Git support
-
-You can start a new extension with git support calling `skeleton` task with
-`--git` flag, then in addition to create skeleton, `pgxn-utils` will initialize
-a git repository and do a initial commit.
-
-Once you have your extension in a git repository your `bundle` will use only the
-commited files to create the archive, but if your repository is dirty then `pgxn-utils`
-will hint you to commit or stash your changes, before bundle.
-
-You must be careful with new files not added to repository, because they will NOT
-be archived.
-
# Working in progress
* improve [git](http://git-scm.org) support
View
10 lib/pgxn_utils/cli.rb
@@ -24,6 +24,7 @@ class CLI < Thor
method_option :tags, :aliases => "-t", :type => :array, :desc => "Defines extension's tags"
method_option :release_status, :aliases => "-r", :type => :string, :desc => "Initial extension's release status"
method_option :git, :type => :boolean, :default => false, :desc => "Initialize a git repository after create the extension"
+ method_option :template, :type => :string, :default => "sql", :desc => "The template that will be used to create the extension. Expected values are: sql, c, fdw"
def skeleton(extension_name,target=nil)
self.target = options[:target] || target || "."
@@ -36,7 +37,8 @@ def skeleton(extension_name,target=nil)
say "Can't create an extension overwriting an existing directory.", :red
else
self.set_accessors extension_name
- directory "root", extension_name
+
+ directory selected_template, extension_name
init_repository("#{self.target}/#{extension_name}") if options[:git]
end
@@ -61,14 +63,16 @@ def skeleton(extension_name,target=nil)
def change(extension_name=".")
extension_path, extension_name = resolve_extension_path_and_name(extension_name)
+ template_type = File.read("#{extension_path}/.template").chomp
+
self.target = extension_path
self.extension_name = extension_name
set_accessors(extension_name)
if is_extension?(extension_path)
- template "root/META.json.tt", "#{extension_path}/META.json"
- template "root/%extension_name%.control.tt", "#{extension_path}/%extension_name%.control"
+ template "#{template_type}/META.json.tt", "#{extension_path}/META.json"
+ template "#{template_type}/%extension_name%.control.tt", "#{extension_path}/%extension_name%.control"
else
say "'#{extension_name}' doesn't appears to be an extension. Please, supply the extension's name", :red
end
View
14 lib/pgxn_utils/no_tasks.rb
@@ -4,6 +4,20 @@ module NoTasks
include PgxnUtils::Constants
include Grit
+ def selected_template
+ template = options[:template]
+
+ unless [ 'sql', 'c', 'fdw' ].include?(template)
+ if Dir["#{template}/*"].include?("#{template}/META.json") or
+ Dir["#{template}/*"].include?("#{template}/META.json.tt")
+ template = File.expand_path(options[:template])
+ else
+ raise "invalid template: #{template}"
+ end
+ end
+ template
+ end
+
def init_repository(extension_dir)
repo = Repo.init(extension_dir)
original_dir = File.expand_path "."
View
5 lib/pgxn_utils/templates/c/%extension_name%.control.tt
@@ -0,0 +1,5 @@
+# <%= extension_name %> extension
+comment = '<%= abstract %>'
+default_version = '<%= version %>'
+module_pathname = '$libdir/<%= extension_name %>'
+relocatable = true
View
8 lib/pgxn_utils/templates/c/.gitignore.tt
@@ -0,0 +1,8 @@
+results/
+*.so
+tmp/
+*.o
+regression.diffs
+regression.out
+/sql/<%= extension_name =>--*
+!/sql/<%= extension_name =>--*--*.sql
View
1 lib/pgxn_utils/templates/c/.template
@@ -0,0 +1 @@
+c
View
37 lib/pgxn_utils/templates/c/META.json.tt
@@ -0,0 +1,37 @@
+{
+ "name": "<%= extension_name %>",
+ "abstract": "<%= abstract %>",
+ "description": "<%= description %>",
+ "version": "<%= version %>",
+ "maintainer": "<%= maintainer %>",
+ "license": "<%= license %>",
+ "provides": {
+ "<%= extension_name %>": {
+ "abstract": "<%= abstract %>",
+ "file": "sql/<%= extension_name %>.sql",
+ "docfile": "doc/<%= extension_name %>.md",
+ "version": "<%= version %>"
+ }
+ },
+ "release_status": "<%= release_status %>",
+ "resources": {
+ "bugtracker": {
+ "web": "http://change.me"
+ },
+ "repository": {
+ "url": "git://change.me/<%= extension_name %>.git",
+ "web": "http://change.me",
+ "type": "git"
+ }
+ },
+<% if generated_by %>
+ "generated_by": "<%= generated_by %>",
+<% end %>
+<% if tags %>
+ "tags": [ <%= tags.collect { |t| %Q|"#{t}"| }.join(",") %> ],
+<% end %>
+ "meta-spec": {
+ "version": "1.0.0",
+ "url": "http://pgxn.org/meta/spec.txt"
+ }
+}
View
24 lib/pgxn_utils/templates/c/Makefile.tt
@@ -0,0 +1,24 @@
+EXTENSION = <%= extension_name %>
+EXTVERSION = $(shell grep default_version $(EXTENSION).control | sed -e "s/default_version[[:space:]]*=[[:space:]]*'\([^']*\)'/\1/")
+
+DATA = $(filter-out $(wildcard sql/*--*.sql),$(wildcard sql/*.sql))
+DOCS = $(wildcard doc/*.md)
+TESTS = $(wildcard test/sql/*.sql)
+REGRESS = $(patsubst test/sql/%.sql,%,$(TESTS))
+REGRESS_OPTS = --inputdir=test --load-language=plpgsql
+MODULES = $(patsubst %.c,%,$(wildcard src/*.c))
+PG_CONFIG = pg_config
+PG91 = $(shell $(PG_CONFIG) --version | grep -qE " 8\.| 9\.0" && echo no || echo yes)
+
+ifeq ($(PG91),yes)
+all: sql/$(EXTENSION)--$(EXTVERSION).sql
+
+sql/$(EXTENSION)--$(EXTVERSION).sql: sql/$(EXTENSION).sql
+ cp $< $@
+
+DATA = $(wildcard sql/*--*.sql) sql/$(EXTENSION)--$(EXTVERSION).sql
+EXTRA_CLEAN = sql/$(EXTENSION)--$(EXTVERSION).sql
+endif
+
+PGXS := $(shell $(PG_CONFIG) --pgxs)
+include $(PGXS)
View
80 lib/pgxn_utils/templates/c/README.md.tt
@@ -0,0 +1,80 @@
+<%= extension_name %>
+<%= extension_name.gsub(/./,"=") %>
+
+<%= description %>
+
+To build it, just do this:
+
+ make
+ make installcheck
+ make install
+
+If you encounter an error such as:
+
+ "Makefile", line 8: Need an operator
+
+You need to use GNU make, which may well be installed on your system as
+`gmake`:
+
+ gmake
+ gmake install
+ gmake installcheck
+
+If you encounter an error such as:
+
+ make: pg_config: Command not found
+
+Be sure that you have `pg_config` installed and in your path. If you used a
+package management system such as RPM to install PostgreSQL, be sure that the
+`-devel` package is also installed. If necessary tell the build process where
+to find it:
+
+ env PG_CONFIG=/path/to/pg_config make && make installcheck && make install
+
+And finally, if all that fails (and if you're on PostgreSQL 8.1 or lower, it
+likely will), copy the entire distribution directory to the `contrib/`
+subdirectory of the PostgreSQL source tree and try it there without
+`pg_config`:
+
+ env NO_PGXS=1 make && make installcheck && make install
+
+If you encounter an error such as:
+
+ ERROR: must be owner of database regression
+
+You need to run the test suite using a super user, such as the default
+"postgres" super user:
+
+ make installcheck PGUSER=postgres
+
+Once <%= extension_name %> is installed, you can add it to a database. If you're running
+PostgreSQL 9.1.0 or greater, it's a simple as connecting to a database as a
+super user and running:
+
+ CREATE EXTENSION <%= extension_name %>;
+
+If you've upgraded your cluster to PostgreSQL 9.1 and already had <%= extension_name %>
+installed, you can upgrade it to a properly packaged extension with:
+
+ CREATE EXTENSION <%= extension_name %> FROM unpackaged;
+
+For versions of PostgreSQL less than 9.1.0, you'll need to run the
+installation script:
+
+ psql -d mydb -f /path/to/pgsql/share/contrib/<%= extension_name %>.sql
+
+If you want to install <%= extension_name %> and all of its supporting objects into a specific
+schema, use the `PGOPTIONS` environment variable to specify the schema, like
+so:
+
+ PGOPTIONS=--search_path=extensions psql -d mydb -f <%= extension_name %>.sql
+
+Dependencies
+------------
+The `<%= extension_name %>` data type has no dependencies other than PostgreSQL.
+
+Copyright and License
+---------------------
+
+Copyright (c) <%= Time.now.strftime("%Y") %> <%= maintainer %>.
+
View
33 lib/pgxn_utils/templates/c/doc/%extension_name%.md.tt
@@ -0,0 +1,33 @@
+<%= extension_name %>
+<%= extension_name.gsub(/./,"=") %>
+
+Synopsis
+--------
+
+ Show a brief synopsis of the extension.
+
+Description
+-----------
+
+<%= description %>
+
+Usage
+-----
+
+ Show usage.
+
+Support
+-------
+
+ There is issues tracker? Github? Put this information here.
+
+Author
+------
+
+[<%= maintainer %>]
+
+Copyright and License
+---------------------
+
+Copyright (c) <%= Time.now.strftime("%Y") %> <%= maintainer %>.
+
View
17 lib/pgxn_utils/templates/c/sql/%extension_name%.sql.tt
@@ -0,0 +1,17 @@
+/*
+ * Author: <%= maintainer %>
+ * Created at: <%= Time.now %>
+ *
+ */
+
+--
+-- This is a example code genereted automaticaly
+-- by pgxn-utils.
+
+-- This is how you define a C function in PostgreSQL.
+CREATE OR REPLACE FUNCTION <%= extension_name %>(text)
+RETURNS text
+AS '<%= extension_name %>'
+LANGUAGE C IMMUTABLE STRICT;
+
+-- See more: http://www.postgresql.org/docs/current/static/xfunc-c.html
View
1 lib/pgxn_utils/templates/c/sql/uninstall_%extension_name%.sql.tt
@@ -0,0 +1 @@
+DROP FUNCTION <%= extension_name %>(text);
View
26 lib/pgxn_utils/templates/c/src/%extension_name%.c.tt
@@ -0,0 +1,26 @@
+#include "postgres.h"
+#include "fmgr.h"
+/*
+ * You can include more files here if needed.
+ * To use some types, you must include the
+ * correct file here based on:
+ * http://www.postgresql.org/docs/current/static/xfunc-c.html#XFUNC-C-TYPE-TABLE
+ */
+
+PG_MODULE_MAGIC;
+
+PG_FUNCTION_INFO_V1(<%= extension_name %>);
+Datum <%= extension_name %>(PG_FUNCTION_ARGS);
+
+Datum
+<%= extension_name %>(PG_FUNCTION_ARGS)
+{
+ /*
+ * This is an empty body and will return NULL
+ *
+ * You should remove this comment and type
+ * cool code here!
+ */
+
+ PG_RETURN_NULL();
+}
View
9 lib/pgxn_utils/templates/c/test/expected/base.out.tt
@@ -0,0 +1,9 @@
+\set ECHO 0
+-- You should write your tests
+SELECT <%= extension_name %>('test');
+ <%= extension_name %>
+<%= '-' * (extension_name.length + 2) %>
+
+(1 row)
+
+ROLLBACK;
View
10 lib/pgxn_utils/templates/c/test/sql/base.sql.tt
@@ -0,0 +1,10 @@
+\set ECHO 0
+BEGIN;
+\i sql/<%= extension_name %>.sql
+\set ECHO all
+
+-- You should write your tests
+
+SELECT <%= extension_name %>('test');
+
+ROLLBACK;
View
5 lib/pgxn_utils/templates/fdw/%extension_name%.control.tt
@@ -0,0 +1,5 @@
+# <%= extension_name %> extension
+comment = '<%= abstract %>'
+default_version = '<%= version %>'
+module_pathname = '$libdir/<%= extension_name %>'
+relocatable = true
View
8 lib/pgxn_utils/templates/fdw/.gitignore.tt
@@ -0,0 +1,8 @@
+results/
+*.so
+tmp/
+*.o
+regression.diffs
+regression.out
+/sql/<%= extension_name =>--*
+!/sql/<%= extension_name =>--*--*.sql
View
1 lib/pgxn_utils/templates/fdw/.template
@@ -0,0 +1 @@
+fdw
View
37 lib/pgxn_utils/templates/fdw/META.json.tt
@@ -0,0 +1,37 @@
+{
+ "name": "<%= extension_name %>",
+ "abstract": "<%= abstract %>",
+ "description": "<%= description %>",
+ "version": "<%= version %>",
+ "maintainer": "<%= maintainer %>",
+ "license": "<%= license %>",
+ "provides": {
+ "<%= extension_name %>": {
+ "abstract": "<%= abstract %>",
+ "file": "sql/<%= extension_name %>.sql",
+ "docfile": "doc/<%= extension_name %>.md",
+ "version": "<%= version %>"
+ }
+ },
+ "release_status": "<%= release_status %>",
+ "resources": {
+ "bugtracker": {
+ "web": "http://change.me"
+ },
+ "repository": {
+ "url": "git://change.me/<%= extension_name %>.git",
+ "web": "http://change.me",
+ "type": "git"
+ }
+ },
+<% if generated_by %>
+ "generated_by": "<%= generated_by %>",
+<% end %>
+<% if tags %>
+ "tags": [ <%= tags.collect { |t| %Q|"#{t}"| }.join(",") %> ],
+<% end %>
+ "meta-spec": {
+ "version": "1.0.0",
+ "url": "http://pgxn.org/meta/spec.txt"
+ }
+}
View
24 lib/pgxn_utils/templates/fdw/Makefile.tt
@@ -0,0 +1,24 @@
+EXTENSION = <%= extension_name %>
+EXTVERSION = $(shell grep default_version $(EXTENSION).control | sed -e "s/default_version[[:space:]]*=[[:space:]]*'\([^']*\)'/\1/")
+
+DATA = $(filter-out $(wildcard sql/*--*.sql),$(wildcard sql/*.sql))
+DOCS = $(wildcard doc/*.md)
+TESTS = $(wildcard test/sql/*.sql)
+REGRESS = $(patsubst test/sql/%.sql,%,$(TESTS))
+REGRESS_OPTS = --inputdir=test --load-language=plpgsql
+MODULES = $(patsubst %.c,%,$(wildcard src/*.c))
+PG_CONFIG = pg_config
+PG91 = $(shell $(PG_CONFIG) --version | grep -qE " 8\.| 9\.0" && echo no || echo yes)
+
+ifeq ($(PG91),yes)
+all: sql/$(EXTENSION)--$(EXTVERSION).sql
+
+sql/$(EXTENSION)--$(EXTVERSION).sql: sql/$(EXTENSION).sql
+ cp $< $@
+
+DATA = $(wildcard sql/*--*.sql) sql/$(EXTENSION)--$(EXTVERSION).sql
+EXTRA_CLEAN = sql/$(EXTENSION)--$(EXTVERSION).sql
+endif
+
+PGXS := $(shell $(PG_CONFIG) --pgxs)
+include $(PGXS)
View
80 lib/pgxn_utils/templates/fdw/README.md.tt
@@ -0,0 +1,80 @@
+<%= extension_name %>
+<%= extension_name.gsub(/./,"=") %>
+
+<%= description %>
+
+To build it, just do this:
+
+ make
+ make installcheck
+ make install
+
+If you encounter an error such as:
+
+ "Makefile", line 8: Need an operator
+
+You need to use GNU make, which may well be installed on your system as
+`gmake`:
+
+ gmake
+ gmake install
+ gmake installcheck
+
+If you encounter an error such as:
+
+ make: pg_config: Command not found
+
+Be sure that you have `pg_config` installed and in your path. If you used a
+package management system such as RPM to install PostgreSQL, be sure that the
+`-devel` package is also installed. If necessary tell the build process where
+to find it:
+
+ env PG_CONFIG=/path/to/pg_config make && make installcheck && make install
+
+And finally, if all that fails (and if you're on PostgreSQL 8.1 or lower, it
+likely will), copy the entire distribution directory to the `contrib/`
+subdirectory of the PostgreSQL source tree and try it there without
+`pg_config`:
+
+ env NO_PGXS=1 make && make installcheck && make install
+
+If you encounter an error such as:
+
+ ERROR: must be owner of database regression
+
+You need to run the test suite using a super user, such as the default
+"postgres" super user:
+
+ make installcheck PGUSER=postgres
+
+Once <%= extension_name %> is installed, you can add it to a database. If you're running
+PostgreSQL 9.1.0 or greater, it's a simple as connecting to a database as a
+super user and running:
+
+ CREATE EXTENSION <%= extension_name %>;
+
+If you've upgraded your cluster to PostgreSQL 9.1 and already had <%= extension_name %>
+installed, you can upgrade it to a properly packaged extension with:
+
+ CREATE EXTENSION <%= extension_name %> FROM unpackaged;
+
+For versions of PostgreSQL less than 9.1.0, you'll need to run the
+installation script:
+
+ psql -d mydb -f /path/to/pgsql/share/contrib/<%= extension_name %>.sql
+
+If you want to install <%= extension_name %> and all of its supporting objects into a specific
+schema, use the `PGOPTIONS` environment variable to specify the schema, like
+so:
+
+ PGOPTIONS=--search_path=extensions psql -d mydb -f <%= extension_name %>.sql
+
+Dependencies
+------------
+The `<%= extension_name %>` data type has no dependencies other than PostgreSQL.
+
+Copyright and License
+---------------------
+
+Copyright (c) <%= Time.now.strftime("%Y") %> <%= maintainer %>.
+
View
33 lib/pgxn_utils/templates/fdw/doc/%extension_name%.md.tt
@@ -0,0 +1,33 @@
+<%= extension_name %>
+<%= extension_name.gsub(/./,"=") %>
+
+Synopsis
+--------
+
+ Show a brief synopsis of the extension.
+
+Description
+-----------
+
+<%= description %>
+
+Usage
+-----
+
+ Show usage.
+
+Support
+-------
+
+ There is issues tracker? Github? Put this information here.
+
+Author
+------
+
+[<%= maintainer %>]
+
+Copyright and License
+---------------------
+
+Copyright (c) <%= Time.now.strftime("%Y") %> <%= maintainer %>.
+
View
31 lib/pgxn_utils/templates/fdw/sql/%extension_name%.sql.tt
@@ -0,0 +1,31 @@
+/*
+ * Author: <%= maintainer %>
+ * Created at: <%= Time.now %>
+ *
+ */
+
+--
+-- This is a example code genereted automaticaly
+-- by pgxn-utils.
+
+CREATE OR REPLACE FUNCTION <%= extension_name %>_fdw_validator (text[], oid)
+RETURNS bool
+AS 'MODULE_PATHNAME'
+LANGUAGE C STRICT;
+
+CREATE OR REPLACE FUNCTION <%= extension_name %>_fdw_handler ()
+RETURNS fdw_handler
+AS 'MODULE_PATHNAME'
+LANGUAGE C STRICT;
+
+CREATE FOREIGN DATA WRAPPER <%= extension_name %>_fdw
+VALIDATOR <%= extension_name %>_fdw_validator HANDLER <%= extension_name %>_fdw_handler;
+
+CREATE SERVER <%= extension_name %>_local_service
+FOREIGN DATA WRAPPER <%= extension_name %>_fdw
+OPTIONS ( server_address 'localhost', server_port '389');
+
+-- See more:
+-- http://www.postgresql.org/docs/current/static/sql-createserver.html
+-- http://www.postgresql.org/docs/current/static/sql-createusermapping.html
+-- http://www.postgresql.org/docs/current/static/sql-createforeigndatawrapper.html
View
14 lib/pgxn_utils/templates/fdw/sql/uninstall_%extension_name%.sql.tt
@@ -0,0 +1,14 @@
+/*
+ * Author: <%= maintainer %>
+ * Created at: <%= Time.now %>
+ *
+ */
+
+--
+-- This is a example code genereted automaticaly
+-- by pgxn-utils.
+
+DROP SERVER <%= extension_name %>_local_service;
+DROP FOREIGN DATA WRAPPER <%= extension_name %>_fdw;
+DROP FUNCTION <%= extension_name %>_fdw_handler();
+DROP FUNCTION <%= extension_name %>_fdw_validator(text[], oid);
View
323 lib/pgxn_utils/templates/fdw/src/%extension_name%_fdw.c.tt
@@ -0,0 +1,323 @@
+/*
+ * Author: <%= maintainer %>
+ * Created at: <%= Time.now %>
+ *
+ * This is an *example code* genereted automaticaly
+ * by pgxn-utils, you must write your own code.
+ *
+ * Other examples could be found at:
+ * http://wiki.postgresql.org/wiki/Foreign_data_wrappers
+ *
+ */
+#include "postgres.h"
+
+/*
+ * You can include more files here if needed.
+ * To use some types, you must include the
+ * correct file here based on:
+ * http://www.postgresql.org/docs/current/static/xfunc-c.html#XFUNC-C-TYPE-TABLE
+ */
+#include "access/reloptions.h"
+#include "catalog/pg_foreign_table.h"
+#include "catalog/pg_foreign_server.h"
+#include "catalog/pg_user_mapping.h"
+#include "commands/defrem.h"
+#include "commands/explain.h"
+#include "foreign/fdwapi.h"
+#include "foreign/foreign.h"
+#include "funcapi.h"
+#include "miscadmin.h"
+#include "nodes/makefuncs.h"
+#include "optimizer/cost.h"
+#include "utils/rel.h"
+#include "utils/builtins.h"
+
+PG_MODULE_MAGIC;
+
+/*
+ * An example how to handle valid options that
+ * could be used by this FDW. You should write
+ * your own.
+ *
+ */
+typedef struct <%= extension_name.to_s.gsub(/\/(.?)/) { "::#{$1.upcase}" }.gsub(/(?:^|_)(.)/) { $1.upcase } %>FdwOption
+{
+ const char *option_name;
+ Oid option_context;
+};
+
+/*
+ * This is an example how you could enumerate valid options
+ * for your FDW. You should write your own.
+ */
+static struct <%= extension_name.to_s.gsub(/\/(.?)/) { "::#{$1.upcase}" }.gsub(/(?:^|_)(.)/) { $1.upcase } %>FdwOption valid_options[] =
+{
+ {"server_address", ForeignServerRelationId },
+ {"server_port", ForeignServerRelationId },
+
+ {"user", UserMappingRelationId },
+ {"password", UserMappingRelationId },
+
+ {"table", ForeignTableRelationId},
+
+ {NULL, InvalidOid}
+};
+
+/*
+ * Handler and Validator functions
+ */
+extern Datum <%= extension_name %>_fdw_handler(PG_FUNCTION_ARGS);
+extern Datum <%= extension_name %>_fdw_validator(PG_FUNCTION_ARGS);
+
+PG_FUNCTION_INFO_V1(<%= extension_name %>_fdw_handler);
+PG_FUNCTION_INFO_V1(<%= extension_name %>_fdw_validator);
+
+/*
+ * FDW functions declarations
+ */
+static FdwPlan *<%= extension_name %>_plan(Oid foreign_table_id, PlannerInfo *root, RelOptInfo *base_relation);
+static void <%= extension_name %>_explain(ForeignScanState *node, ExplainState *es);
+static void <%= extension_name %>_begin(ForeignScanState *node, int eflags);
+static TupleTableSlot *<%= extension_name %>_iterate(ForeignScanState *node);
+static void <%= extension_name %>_rescan(ForeignScanState *node);
+static void <%= extension_name %>_end(ForeignScanState *node);
+
+/*
+ * Helper functions
+ */
+static bool is_valid_option(const char *option, Oid context);
+static void <%= extension_name %>_get_options(Oid foreign_table_id, char **server_address, int *server_port, char **user, char **password, char **table)
+
+/*
+ * FDW functions implementation
+ */
+
+Datum
+<%= extension_name %>_fdw_handler(PG_FUNCTION_ARGS)
+{
+ FdwRoutine *fdw_routine = makeNode(FdwRoutine);
+
+ fdw_routine->PlanForeignScan = <%= extension_name %>_plan;
+ fdw_routine->ExplainForeignScan = <%= extension_name %>_explain;
+ fdw_routine->BeginForeignScan = <%= extension_name %>_begin;
+ fdw_routine->IterateForeignScan = <%= extension_name %>_iterate;
+ fdw_routine->ReScanForeignScan = <%= extension_name %>_rescan;
+ fdw_routine->EndForeignScan = <%= extension_name %>_end;
+
+ PG_RETURN_POINTER(fdw_routine);
+}
+
+Datum
+<%= extension_name %>_fdw_validator(PG_FUNCTION_ARGS)
+{
+ /*
+ * This is an example how you could validate the
+ * your FDW options. You should write your own
+ * validator.
+ */
+
+ List *options_list = untransformRelOptions(PG_GETARG_DATUM(0));
+ Oid catalog = PG_GETARG_OID(1);
+ ListCell *cell;
+
+ foreach(cell, options_list)
+ {
+ DefElem *def = (DefElem *) lfirst(cell);
+
+ if (!is_valid_option(def->defname, catalog))
+ {
+ struct <%= extension_name.to_s.gsub(/\/(.?)/) { "::#{$1.upcase}" }.gsub(/(?:^|_)(.)/) { $1.upcase } %>FdwOption *opt;
+ StringInfoData buf;
+
+ /*
+ * Unknown option specified, complain about it. Provide a hint
+ * with list of valid options for the object.
+ */
+ initStringInfo(&buf);
+ for (opt = valid_options; opt->option_name; opt++)
+ {
+ if (catalog == opt->option_context)
+ appendStringInfo(&buf, "%s%s", (buf.len > 0) ? ", " : "",
+ opt->option_name);
+ }
+
+ ereport(ERROR,
+ (errcode(ERRCODE_FDW_INVALID_OPTION_NAME),
+ errmsg("invalid option \"%s\"", def->defname),
+ errhint("Valid options in this context are: %s",
+ buf.data)));
+ }
+ }
+
+ PG_RETURN_BOOL(true);
+}
+
+static FdwPlan *
+<%= extension_name %>_plan( Oid foreign_table_id,
+ PlannerInfo *root,
+ RelOptInfo *base_relation)
+{
+ /*
+ * Plan a scan on a foreign table. This is called when a query is planned.
+ * foreign_table_id is the pg_class OID of the foreign table. root is the
+ * planner's global information about the query, and base_relation is the
+ * planner's information about this table. This is an example and you
+ * should write your own.
+ *
+ * see: http://www.postgresql.org/docs/current/static/fdw-callbacks.html
+ */
+
+ FdwPlan *fdw_plan;
+
+ fdw_plan = makeNode(FdwPlan);
+
+ fdw_plan->startup_cost = /* calculate and return a startup cost */;
+ base_relation->rows = /* calculate and return an extimation of row many rows this call will return */;
+ fdw_plan->total_cost = /* calculate and return an total cost extimation */;
+
+ return fdw_plan;
+}
+
+static void
+<%= extension_name %>_explain(ForeignScanState *node, ExplainState *es)
+{
+ /*
+ * Print additional EXPLAIN output for a foreign table scan. This can just
+ * return if there is no need to print anything. Otherwise, it should call
+ * ExplainPropertyText and related functions to add fields to the EXPLAIN
+ * output. This is an example and you should write your own.
+ *
+ * see: http://www.postgresql.org/docs/current/static/fdw-callbacks.html
+ */
+
+ /* calculate real values for costs */
+ ExplainPropertyText("Foreign <%= extension_name.to_s.gsub(/\/(.?)/) { "::#{$1.upcase}" }.gsub(/(?:^|_)(.)/) { $1.upcase } %>", "<%= extension_name %>", es);
+
+ if (es->costs)
+ {
+ ExplainPropertyLong("Foreign <%= extension_name.to_s.gsub(/\/(.?)/) { "::#{$1.upcase}" }.gsub(/(?:^|_)(.)/) { $1.upcase } %> cost", /* calculated costs */, es);
+ }
+}
+
+static void
+<%= extension_name %>_begin(ForeignScanState *node, int eflags)
+{
+ /*
+ * Begin executing a foreign scan. This is called during executor startup.
+ * It should perform any initialization needed before the scan can start,
+ * but not start executing the actual scan (that should be done upon the
+ * first call to IterateForeignScan)
+ *
+ * see: http://www.postgresql.org/docs/current/static/fdw-callbacks.html
+ */
+}
+
+static TupleTableSlot *
+<%= extension_name %>_iterate(ForeignScanState *node)
+{
+ /*
+ * Fetch one row from the foreign source, returning it in a tuple table slot
+ * (the node's ScanTupleSlot should be used for this purpose). Return NULL
+ * if no more rows are available.
+ *
+ * see: http://www.postgresql.org/docs/current/static/fdw-callbacks.html
+ */
+
+}
+
+static void
+<%= extension_name %>_rescan(ForeignScanState *node)
+{
+ /*
+ * Restart the scan from the beginning.
+ *
+ * see: http://www.postgresql.org/docs/current/static/fdw-callbacks.html
+ */
+}
+
+static void
+<%= extension_name %>_end(ForeignScanState *node)
+{
+ /*
+ * End the scan and release resources. It is normally not important to
+ * release palloc'd memory, but for example open files and connections
+ * to remote servers should be cleaned up.
+ *
+ * see: http://www.postgresql.org/docs/current/static/fdw-callbacks.html
+ */
+}
+
+/*
+ * Helper functions
+ */
+
+/*
+ * Example function to check if the provided option is one of the
+ * valid options where context is the Oid of the catalog holding
+ * the object the option is for.
+ */
+static bool
+is_valid_option(const char *option, Oid context)
+{
+ struct <%= extension_name.to_s.gsub(/\/(.?)/) { "::#{$1.upcase}" }.gsub(/(?:^|_)(.)/) { $1.upcase } %>FdwOption *opt;
+
+ for (opt = valid_options; opt->option_name; opt++)
+ {
+ if (context == opt->option_context && strcmp(opt->option_name, option) == 0)
+ return true;
+ }
+ return false;
+}
+
+/*
+ * Fetch the options for a <%= extension_name %>_fdw foreign table.
+ * This is an example and you should write your own.
+ */
+static void
+<%= extension_name %>_get_options(Oid foreign_table_id, char **server_address, int *server_port, char **user, char **password, char **table)
+{
+ ForeignTable *f_table;
+ ForeignServer *f_server;
+ UserMapping *f_mapping;
+ List *options;
+ ListCell *lc;
+
+ /*
+ * Extract options from FDW objects.
+ */
+ f_table = GetForeignTable(foreign_table_id);
+ f_server = GetForeignServer(f_table->serverid);
+ f_mapping = GetUserMapping(GetUserId(), f_table->serverid);
+
+ options = NIL;
+ options = list_concat(options, f_table->options);
+ options = list_concat(options, f_server->options);
+ options = list_concat(options, f_mapping->options);
+
+ foreach(lc, options)
+ {
+ DefElem *def = (DefElem *) lfirst(lc);
+
+ if (strcmp(def->defname, "server_address") == 0)
+ *server_address = defGetString(def);
+
+ if (strcmp(def->defname, "server_port") == 0)
+ *server_port = atoi(defGetString(def));
+
+ if (strcmp(def->defname, "user") == 0)
+ *user = defGetString(def);
+
+ if (strcmp(def->defname, "password") == 0)
+ *password = defGetString(def);
+
+ if (strcmp(def->defname, "table") == 0)
+ *table = defGetString(def);
+ }
+
+ /* Default values, if required */
+ if (!*server_address)
+ *server_address = "127.0.0.1";
+
+ if (!*server_port)
+ *port = 12345;
+}
View
4 lib/pgxn_utils/templates/fdw/test/expected/base.out.tt
@@ -0,0 +1,4 @@
+\set ECHO 0
+-- You should write your tests
+
+ROLLBACK;
View
8 lib/pgxn_utils/templates/fdw/test/sql/base.sql.tt
@@ -0,0 +1,8 @@
+\set ECHO 0
+BEGIN;
+\i sql/<%= extension_name %>.sql
+\set ECHO all
+
+-- You should write your tests
+
+ROLLBACK;
View
4 lib/pgxn_utils/templates/sql/%extension_name%.control.tt
@@ -0,0 +1,4 @@
+# <%= extension_name %> extension
+comment = '<%= abstract %>'
+default_version = '<%= version %>'
+relocatable = true
View
8 lib/pgxn_utils/templates/sql/.gitignore.tt
@@ -0,0 +1,8 @@
+results/
+*.so
+tmp/
+*.o
+regression.diffs
+regression.out
+/sql/<%= extension_name =>--*
+!/sql/<%= extension_name =>--*--*.sql
View
1 lib/pgxn_utils/templates/sql/.template
@@ -0,0 +1 @@
+sql
View
27 lib/pgxn_utils/templates/sql/META.json.tt
@@ -0,0 +1,27 @@
+{
+ "name": "<%= extension_name %>",
+ "abstract": "<%= abstract %>",
+ "description": "<%= description %>",
+ "version": "<%= version %>",
+ "maintainer": "<%= maintainer %>",
+ "license": "<%= license %>",
+ "provides": {
+ "<%= extension_name %>": {
+ "abstract": "<%= abstract %>",
+ "file": "sql/<%= extension_name %>.sql",
+ "docfile": "doc/<%= extension_name %>.md",
+ "version": "<%= version %>"
+ }
+ },
+ "release_status": "<%= release_status %>",
+<% if generated_by %>
+ "generated_by": "<%= generated_by %>",
+<% end %>
+<% if tags %>
+ "tags": [ <%= tags.collect { |t| %Q|"#{t}"| }.join(",") %> ],
+<% end %>
+ "meta-spec": {
+ "version": "1.0.0",
+ "url": "http://pgxn.org/meta/spec.txt"
+ }
+}
View
28 lib/pgxn_utils/templates/sql/Makefile.tt
@@ -0,0 +1,28 @@
+EXTENSION = <%= extension_name %>
+EXTVERSION = $(shell grep default_version $(EXTENSION).control | sed -e "s/default_version[[:space:]]*=[[:space:]]*'\([^']*\)'/\1/")
+
+DATA = $(filter-out $(wildcard sql/*--*.sql),$(wildcard sql/*.sql))
+DOCS = $(wildcard doc/*.md)
+TESTS = $(wildcard test/sql/*.sql)
+REGRESS = $(patsubst test/sql/%.sql,%,$(TESTS))
+REGRESS_OPTS = --inputdir=test --load-language=plpgsql
+#
+# Uncoment the MODULES line if you are adding C files
+# to your extention.
+#
+#MODULES = $(patsubst %.c,%,$(wildcard src/*.c))
+PG_CONFIG = pg_config
+PG91 = $(shell $(PG_CONFIG) --version | grep -qE " 8\.| 9\.0" && echo no || echo yes)
+
+ifeq ($(PG91),yes)
+all: sql/$(EXTENSION)--$(EXTVERSION).sql
+
+sql/$(EXTENSION)--$(EXTVERSION).sql: sql/$(EXTENSION).sql
+ cp $< $@
+
+DATA = $(wildcard sql/*--*.sql) sql/$(EXTENSION)--$(EXTVERSION).sql
+EXTRA_CLEAN = sql/$(EXTENSION)--$(EXTVERSION).sql
+endif
+
+PGXS := $(shell $(PG_CONFIG) --pgxs)
+include $(PGXS)
View
80 lib/pgxn_utils/templates/sql/README.md.tt
@@ -0,0 +1,80 @@
+<%= extension_name %>
+<%= extension_name.gsub(/./,"=") %>
+
+<%= description %>
+
+To build it, just do this:
+
+ make
+ make installcheck
+ make install
+
+If you encounter an error such as:
+
+ "Makefile", line 8: Need an operator
+
+You need to use GNU make, which may well be installed on your system as
+`gmake`:
+
+ gmake
+ gmake install
+ gmake installcheck
+
+If you encounter an error such as:
+
+ make: pg_config: Command not found
+
+Be sure that you have `pg_config` installed and in your path. If you used a
+package management system such as RPM to install PostgreSQL, be sure that the
+`-devel` package is also installed. If necessary tell the build process where
+to find it:
+
+ env PG_CONFIG=/path/to/pg_config make && make installcheck && make install
+
+And finally, if all that fails (and if you're on PostgreSQL 8.1 or lower, it
+likely will), copy the entire distribution directory to the `contrib/`
+subdirectory of the PostgreSQL source tree and try it there without
+`pg_config`:
+
+ env NO_PGXS=1 make && make installcheck && make install
+
+If you encounter an error such as:
+
+ ERROR: must be owner of database regression
+
+You need to run the test suite using a super user, such as the default
+"postgres" super user:
+
+ make installcheck PGUSER=postgres
+
+Once <%= extension_name %> is installed, you can add it to a database. If you're running
+PostgreSQL 9.1.0 or greater, it's a simple as connecting to a database as a
+super user and running:
+
+ CREATE EXTENSION <%= extension_name %>;
+
+If you've upgraded your cluster to PostgreSQL 9.1 and already had <%= extension_name %>
+installed, you can upgrade it to a properly packaged extension with:
+
+ CREATE EXTENSION <%= extension_name %> FROM unpackaged;
+
+For versions of PostgreSQL less than 9.1.0, you'll need to run the
+installation script:
+
+ psql -d mydb -f /path/to/pgsql/share/contrib/<%= extension_name %>.sql
+
+If you want to install <%= extension_name %> and all of its supporting objects into a specific
+schema, use the `PGOPTIONS` environment variable to specify the schema, like
+so:
+
+ PGOPTIONS=--search_path=extensions psql -d mydb -f <%= extension_name %>.sql
+
+Dependencies
+------------
+The `<%= extension_name %>` data type has no dependencies other than PostgreSQL.
+
+Copyright and License
+---------------------
+
+Copyright (c) <%= Time.now.strftime("%Y") %> <%= maintainer %>.
+
View
33 lib/pgxn_utils/templates/sql/doc/%extension_name%.md.tt
@@ -0,0 +1,33 @@
+<%= extension_name %>
+<%= extension_name.gsub(/./,"=") %>
+
+Synopsis
+--------
+
+ Show a brief synopsis of the extension.
+
+Description
+-----------
+
+<%= description %>
+
+Usage
+-----
+
+ Show usage.
+
+Support
+-------
+
+ There is issues tracker? Github? Put this information here.
+
+Author
+------
+
+[<%= maintainer %>]
+
+Copyright and License
+---------------------
+
+Copyright (c) <%= Time.now.strftime("%Y") %> <%= maintainer %>.
+
View
31 lib/pgxn_utils/templates/sql/sql/%extension_name%.sql.tt
@@ -0,0 +1,31 @@
+/*
+ * Author: <%= maintainer %>
+ * Created at: <%= Time.now %>
+ *
+ */
+
+--
+-- This is a example code genereted automaticaly
+-- by pgxn-utils.
+
+SET client_min_messages = warning;
+
+-- If your extension will create a type you can
+-- do somenthing like this
+CREATE TYPE <%= extension_name %> AS ( a text, b text );
+
+-- Maybe you want to create some function, so you can use
+-- this as an example
+CREATE OR REPLACE FUNCTION <%= extension_name %> (text, text)
+RETURNS <%= extension_name %> LANGUAGE SQL AS 'SELECT ROW($1, $2)::<%= extension_name %>';
+
+-- Sometimes it is common to use special operators to
+-- work with your new created type, you can create
+-- one like the command bellow if it is applicable
+-- to your case
+
+CREATE OPERATOR #? (
+ LEFTARG = text,
+ RIGHTARG = text,
+ PROCEDURE = <%= extension_name %>
+);
View
21 lib/pgxn_utils/templates/sql/sql/uninstall_%extension_name%.sql.tt
@@ -0,0 +1,21 @@
+/*
+ * Author: <%= maintainer %>
+ * Created at: <%= Time.now %>
+ *
+ */
+
+--
+-- This is a example code genereted automaticaly
+-- by pgxn-utils.
+
+SET client_min_messages = warning;
+
+BEGIN;
+
+-- You can use this statements as
+-- template for your extension.
+
+DROP OPERATOR #? (text, text);
+DROP FUNCTION <%= extension_name %>(text, text);
+DROP TYPE <%= extension_name %> CASCADE;
+COMMIT;
View
49 lib/pgxn_utils/templates/sql/test/expected/base.out.tt
@@ -0,0 +1,49 @@
+\set ECHO 0
+-- You should write your tests
+SELECT <%= extension_name %>('foo', 'bar');
+ <%= extension_name %>
+<%= '-' * (extension_name.length + 2) %>
+ (foo,bar)
+(1 row)
+
+SELECT 'foo' #? 'bar' AS arrowop;
+ arrowop
+-----------
+ (foo,bar)
+(1 row)
+
+CREATE TABLE ab (
+ a_field <%= extension_name %>
+);
+INSERT INTO ab VALUES('foo' #? 'bar');
+SELECT (a_field).a, (a_field).b FROM ab;
+ a | b
+-----+-----
+ foo | bar
+(1 row)
+
+SELECT (<%= extension_name %>('foo', 'bar')).a;
+ a
+-----
+ foo
+(1 row)
+
+SELECT (<%= extension_name %>('foo', 'bar')).b;
+ b
+-----
+ bar
+(1 row)
+
+SELECT ('foo' #? 'bar').a;
+ a
+-----
+ foo
+(1 row)
+
+SELECT ('foo' #? 'bar').b;
+ b
+-----
+ bar
+(1 row)
+
+ROLLBACK;
View
25 lib/pgxn_utils/templates/sql/test/sql/base.sql.tt
@@ -0,0 +1,25 @@
+\set ECHO 0
+BEGIN;
+\i sql/<%= extension_name %>.sql
+\set ECHO all
+
+-- You should write your tests
+
+SELECT <%= extension_name %>('foo', 'bar');
+
+SELECT 'foo' #? 'bar' AS arrowop;
+
+CREATE TABLE ab (
+ a_field <%= extension_name %>
+);
+
+INSERT INTO ab VALUES('foo' #? 'bar');
+SELECT (a_field).a, (a_field).b FROM ab;
+
+SELECT (<%= extension_name %>('foo', 'bar')).a;
+SELECT (<%= extension_name %>('foo', 'bar')).b;
+
+SELECT ('foo' #? 'bar').a;
+SELECT ('foo' #? 'bar').b;
+
+ROLLBACK;
View
2 lib/pgxn_utils/version.rb
@@ -1,3 +1,3 @@
module PgxnUtils
- VERSION = "0.1.3"
+ VERSION = "0.1.4dev"
end
View
51 spec/cli_spec.rb
@@ -59,16 +59,16 @@
makefile.should match(/EXTENSION = #{expected_extension}/)
control = File.read("/tmp/#{expected_extension}/#{expected_extension}.control")
- control.should match(/module_pathname = '\$libdir\/#{expected_extension}'/)
control.should match(/default_version = '#{expected_version}'/)
end
- it "should generates a skeleton" do
+ it "should generates a default skeleton" do
extension = next_extension
skeleton extension
- Dir["#{extension}/**/{*,.gitignore}"].sort.should == [
+ Dir["#{extension}/**/{*,.gitignore,.template}"].sort.should == [
"#{extension}/.gitignore",
+ "#{extension}/.template",
"#{extension}/META.json",
"#{extension}/Makefile",
"#{extension}/README.md",
@@ -84,6 +84,51 @@
"#{extension}/test/sql/base.sql",
"#{extension}/#{extension}.control"
].sort
+
+ template = File.read("#{extension}/.template").chomp
+ template.should == "sql"
+ end
+
+ it "should generates a skeleton for C extensions" do
+ extension = next_extension
+ skeleton extension, %w|--template c|
+
+ Dir["#{extension}/**/{*,.gitignore,.template}"].sort.should == [
+ "#{extension}/.gitignore",
+ "#{extension}/.template",
+ "#{extension}/META.json",
+ "#{extension}/Makefile",
+ "#{extension}/README.md",
+ "#{extension}/doc",
+ "#{extension}/doc/#{extension}.md",
+ "#{extension}/sql",
+ "#{extension}/sql/#{extension}.sql",
+ "#{extension}/sql/uninstall_#{extension}.sql",
+ "#{extension}/src",
+ "#{extension}/src/#{extension}.c",
+ "#{extension}/test",
+ "#{extension}/test/expected",
+ "#{extension}/test/expected/base.out",
+ "#{extension}/test/sql",
+ "#{extension}/test/sql/base.sql",
+ "#{extension}/#{extension}.control"
+ ].sort
+
+ makefile = File.read("#{extension}/Makefile")
+ makefile.should match(/EXTENSION = #{extension}/)
+
+ control = File.read("#{extension}/#{extension}.control")
+ control.should match(/module_pathname = '\$libdir\/#{extension}'/)
+
+ template = File.read("#{extension}/.template").chomp
+ template.should == "c"
+
+ c_file = File.read("#{extension}/src/#{extension}.c")
+ c_file.should match(/#include "postgres.h"/)
+ c_file.should match(/#include "fmgr.h"/)
+ c_file.should match(/PG_MODULE_MAGIC;/)
+ c_file.should match(/PG_FUNCTION_INFO_V1\(#{extension}\);/)
+ c_file.should match(/Datum #{extension}\(PG_FUNCTION_ARGS\);/)
end
it "should generates a git repo with --git" do

0 comments on commit 917967d

Please sign in to comment.
Something went wrong with that request. Please try again.