<?xml version="1.0" encoding="UTF-8" standalone="yes"?><feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en-us"><id>https://blog.pgxn.org/tags/pgxn/</id><title>Pgxn</title><updated>2024-02-02T15:32:53Z</updated><link rel="self" type="application/atom+xml" href="https://blog.pgxn.org/tags/pgxn/feed.xml"/><link rel="alternate" type="text/html" href="https://blog.pgxn.org/tags/pgxn/"/><author><name>The PGXN Maintainers</name></author><generator uri="https://gohugo.io/" version="0.167.0">Hugo</generator><entry><id>https://blog.pgxn.org/post/741225763692494848</id><title type="html">Presentation: Introduction to the PGXN</title><link rel="alternate" type="text/html" href="https://blog.pgxn.org/2024/presentation-introduction-to-the-pgxn/"/><updated>2026-10-07T16:13:48Z</updated><published>2024-02-02T15:32:53Z</published><author><name>David E. Wheeler</name></author><category scheme="https://blog.pgxn.org/tags" term="software-architecture" label="Software Architecture"/><category scheme="https://blog.pgxn.org/tags" term="presentation" label="Presentation"/><category scheme="https://blog.pgxn.org/tags" term="pgxn" label="PGXN"/><summary type="html"><![CDATA[<p><a href="https://tembo.io/blog/pgxn-architecture"><img src="/2024/presentation-introduction-to-the-pgxn/architecture.png" alt="Presentation: Introduction to the PGXN Architecture | Tembo"></a></p>
<p>The Tembo blog has posted a presentation on the PGXN architecture. There
hasn&rsquo;t been much coverage of it since a few posts here on the PGXN blog back
in 2012, so worth a revisit &mdash; and a fair bit changed in the interim, as
well!</p>]]></summary><content type="html" xml:base="https://blog.pgxn.org/" xml:space="preserve"><![CDATA[<p><a href="https://tembo.io/blog/pgxn-architecture"><img src="/2024/presentation-introduction-to-the-pgxn/architecture.png" alt="Presentation: Introduction to the PGXN Architecture | Tembo"></a></p>
<p>The Tembo blog has posted a presentation on the PGXN architecture. There
hasn&rsquo;t been much coverage of it since a few posts here on the PGXN blog back
in 2012, so worth a revisit &mdash; and a fair bit changed in the interim, as
well!</p>
]]></content></entry><entry><id>https://blog.pgxn.org/post/741049567045468160</id><title type="html">PGXN Tools Docker Image Updated</title><link rel="alternate" type="text/html" href="https://blog.pgxn.org/2024/pgxn-tools-v4/"/><updated>2026-10-07T16:13:48Z</updated><published>2024-01-31T16:52:19Z</published><author><name>David E. Wheeler</name></author><category scheme="https://blog.pgxn.org/tags" term="pgxn" label="PGXN"/><category scheme="https://blog.pgxn.org/tags" term="docker" label="Docker"/><category scheme="https://blog.pgxn.org/tags" term="github-actions" label="GitHub Actions"/><category scheme="https://blog.pgxn.org/tags" term="github-workflows" label="GitHub Workflows"/><category scheme="https://blog.pgxn.org/tags" term="release" label="Release"/><category scheme="https://blog.pgxn.org/tags" term="bundle" label="Bundle"/><summary type="html"><![CDATA[<p>Just a quick note to highlight some bug fixes and improvements in the
<a href="https://github.com/pgxn/docker-pgxn-tools/">pgxn/pgxn-tools Docker image</a> in the last few weeks.</p>
<p>v1.4.0 adds the <code>GIT_BUNDLE_OPTS</code> and <code>ZIP_BUNDLE_OPTS</code> environment variables.
The former is passed to <code>git archive</code> and the latter to zip, and let
additional options be passed to those commands. For example, the <a href="https://pgxn.org/dist/vectorize/">vectorize
extension</a>&rsquo;s <a href="https://github.com/tembo-io/pg_vectorize/blob/v0.9.0/.github/workflows/pgxn-release.yml">release workflow</a> sets <code>GIT_BUNDLE_OPTS: --add-file META.json</code>
because git archive archives only checked-in files, and <code>META.json</code> is not
checked in but <a href="https://github.com/tembo-io/pg_vectorize/blob/v0.9.0/Makefile#L17-L18">generated from</a> <code>META.json.in</code>.</p>]]></summary><content type="html" xml:base="https://blog.pgxn.org/" xml:space="preserve"><![CDATA[<p>Just a quick note to highlight some bug fixes and improvements in the
<a href="https://github.com/pgxn/docker-pgxn-tools/">pgxn/pgxn-tools Docker image</a> in the last few weeks.</p>
<p>v1.4.0 adds the <code>GIT_BUNDLE_OPTS</code> and <code>ZIP_BUNDLE_OPTS</code> environment variables.
The former is passed to <code>git archive</code> and the latter to zip, and let
additional options be passed to those commands. For example, the <a href="https://pgxn.org/dist/vectorize/">vectorize
extension</a>&rsquo;s <a href="https://github.com/tembo-io/pg_vectorize/blob/v0.9.0/.github/workflows/pgxn-release.yml">release workflow</a> sets <code>GIT_BUNDLE_OPTS: --add-file META.json</code>
because git archive archives only checked-in files, and <code>META.json</code> is not
checked in but <a href="https://github.com/tembo-io/pg_vectorize/blob/v0.9.0/Makefile#L17-L18">generated from</a> <code>META.json.in</code>.</p>
<p>v1.4.1 <a href="https://github.com/pgxn/docker-pgxn-tools/commit/1114aed">fixes an issue</a> where <code>git archive</code> was never actually used to build a
release zip archive. This changed at some point without noticing due to the
introduction of the <code>safe.directory</code> configuration in recent versions of Git.
Inside the container the directory was never trusted, and the <code>pgxn-bundle</code>
command caught the error, decided it wasn&rsquo;t working with a Git repository, and
used the <code>zip</code> command, instead.</p>
<p>As a result, a number of recent releases have included files they shouldn&rsquo;t,
such as the contents of the <code>.git</code> directory. <a href="https://github.com/pgxn/docker-pgxn-tools/commit/1114aed">The fix</a>
<a href="https://stackoverflow.com/a/73100228/79202">disables</a> <code>safe.directory</code> so that the repository directory is always trusted
inside the container, as needed in GitHub actions.</p>
<p>If you use <code>pgxn-bundle</code> in a GitHub workflow, be aware that recent releases
(since November 2021 at least) include stuff that it should not, including the
<code>.git</code> directory (here&rsquo;s <a href="https://gist.github.com/theory/93c93571200aad02e93170c6d2c93cbe">a list</a>) and patterns excluded in <code>.gitattributes</code>.
Your next release should be cleaner.</p>
<p>v1.4.1 also allows the setting of the <code>PROFILE</code> environment variable, so that
the default <code>PROFILE=--Werror</code> can be overridden.</p>
<p>v1.4.2 adds (and v1.4.3 improves, see below) <code>git-archive-all</code> to the image,
and the <code>GIT_ARCHIVE_CMD</code> environment variable to tell <code>pgxn-bundle</code> which archive
command to use, either <code>archive</code> or <code>archive-all</code>. The latter is useful for
repositories that use Git submodules and need to include their contents in the
release, as demonstrated in <a href="https://github.com/plv8/plv8/pull/570/files#diff-4e4745c3f39dff4c307faf79bfa1242cc5ba2eb5947bebdcddc8d97eeb40685fR15">this plv8 pull request</a>.</p>
<p>v1.4.2 also adds <a href="https://cmake.org/"><code>cmake</code></a> and the <code>libarchive-tools</code> package to the image.
The latter bundles in <a href="https://libarchive.org/">libarchive</a> tools like <code>bsdtar</code> and <code>bsdcpio</code>, which
might be useful for editing Zip files in place.</p>
<p>v1.4.3 passes the <code>--force-submodules</code> option to <code>git-archive-all</code>, because
otherwise submodules weren&rsquo;t included in the bundle.</p>
<p>All of this should just start showing up in your GitHub workflows as long as
they use <code>container: pgxn/pgxn-tools</code> or <code>container: pgxn/pgxn-tools@v1</code>.</p>
<p>Questions? Post em in the <a href="https://postgresteam.slack.com/archives/C056ZA93H1A">#extensions</a> channel on the <a href="https://pgtreats.info/slack-invite">Postgres Slack</a> or to
the attention of the <a href="https://mastodon.social/@pgxn">PGXN Mastodon bot</a>.</p>
]]></content></entry><entry><id>https://blog.pgxn.org/post/709635160523620352</id><title type="html">Hello Mastodon 🐘</title><link rel="alternate" type="text/html" href="https://blog.pgxn.org/2023/hello-mastodon/"/><updated>2026-10-07T16:13:48Z</updated><published>2023-02-18T22:53:46Z</published><author><name>David E. Wheeler</name></author><category scheme="https://blog.pgxn.org/tags" term="pgxn" label="PGXN"/><category scheme="https://blog.pgxn.org/tags" term="mastodon" label="Mastodon"/><category scheme="https://blog.pgxn.org/tags" term="twitter" label="Twitter"/><category scheme="https://blog.pgxn.org/tags" term="postgresql" label="PostgreSQL"/><category scheme="https://blog.pgxn.org/tags" term="listen/notify" label="LISTEN/NOTIFY"/><summary type="html"><![CDATA[<p>Hey all you Postgres people out there! Just wanted to make a quick post
regarding the PGXN <a href="https://twitter.com/pgxn">twitter bot</a>. In light of the recent announcements by
Twitter to charge for API use, I updated <a href="https://manager.pgxn.org">PGXN Manager</a> to also post to
Mastodon! If you&rsquo;re have joined the exodus to the Fediverse, give it a follow:</p>
<p><a href="https://mastodon.social/@pgxn">@pgxn@mastodon.social</a></p>
<p>In fact, I made some time to rewrite the notification bits of the manager
service. Previously there was just some code jammed into the upload controller
that would make an API call to Twitter. I ripped that out, and added a trigger
to the distributions table that posts a a <a href="https://www.postgresql.org/docs/current/sql-notify.html">LISTEN/NOTIFY</a> message.</p>]]></summary><content type="html" xml:base="https://blog.pgxn.org/" xml:space="preserve"><![CDATA[<p>Hey all you Postgres people out there! Just wanted to make a quick post
regarding the PGXN <a href="https://twitter.com/pgxn">twitter bot</a>. In light of the recent announcements by
Twitter to charge for API use, I updated <a href="https://manager.pgxn.org">PGXN Manager</a> to also post to
Mastodon! If you&rsquo;re have joined the exodus to the Fediverse, give it a follow:</p>
<p><a href="https://mastodon.social/@pgxn">@pgxn@mastodon.social</a></p>
<p>In fact, I made some time to rewrite the notification bits of the manager
service. Previously there was just some code jammed into the upload controller
that would make an API call to Twitter. I ripped that out, and added a trigger
to the distributions table that posts a a <a href="https://www.postgresql.org/docs/current/sql-notify.html">LISTEN/NOTIFY</a> message.</p>
<p>Then I wrote a little service that checks for new notifications every 5
seconds and dispatches to one mor more configured consumers. Today there are
just two: Twitter and Mastodon; in the future the might be more, especially
since I also added triggers to the users and mirrors tables, so we could have
the bot announce new mirrors and users. Should be pretty easy to do, might put
in the time in the next few weeks.</p>
<p>Oh, and for fun, I also added some emoji to the Mastodon posts, as well as the
abstract from new releases. Makes the messages more informative than on
Twitter. Of course, we could probably do the same, there, especially since the
post length was extended to 280 characters sometime after the original bot. I
have in mind to make a little library that allows the customization of
messages via configuration.</p>
]]></content></entry><entry><id>https://blog.pgxn.org/post/651216661677064192</id><title type="html">A Few Belated PGXN Updates</title><link rel="alternate" type="text/html" href="https://blog.pgxn.org/2021/a-few-belated-pgxn-updates/"/><updated>2026-10-07T16:13:48Z</updated><published>2021-05-15T03:16:44Z</published><author><name>David E. Wheeler</name></author><category scheme="https://blog.pgxn.org/tags" term="pgxn" label="PGXN"/><category scheme="https://blog.pgxn.org/tags" term="upgrade" label="Upgrade"/><category scheme="https://blog.pgxn.org/tags" term="tls" label="TLS"/><category scheme="https://blog.pgxn.org/tags" term="retina" label="Retina"/><summary type="html"><![CDATA[<p>The last couple weeks I&rsquo;ve returned to PGXN and made a few updates. Nothing
huge, but all long overdue.</p>
<p>First up, <a href="https://manager.pgxn.org">PGXN Manager</a> is all TSL now. No public HTTP-only site. What
started as a convenient division of labor (http for the public site and https
for the authenticated site) turned out to be quite irksome &mdash; especially
since some browsers wouldn&rsquo;t load the non-TLS site at all anymore. So I did
away with it, and now it&rsquo;s all TLS, authenticated and not. (The API and search
sites have been TLS for a while now.)</p>]]></summary><content type="html" xml:base="https://blog.pgxn.org/" xml:space="preserve"><![CDATA[<p>The last couple weeks I&rsquo;ve returned to PGXN and made a few updates. Nothing
huge, but all long overdue.</p>
<p>First up, <a href="https://manager.pgxn.org">PGXN Manager</a> is all TSL now. No public HTTP-only site. What
started as a convenient division of labor (http for the public site and https
for the authenticated site) turned out to be quite irksome &mdash; especially
since some browsers wouldn&rsquo;t load the non-TLS site at all anymore. So I did
away with it, and now it&rsquo;s all TLS, authenticated and not. (The API and search
sites have been TLS for a while now.)</p>
<p>I also fixed a few long-standing bugs in PGXN Manager, most of which weren&rsquo;t
visible to end-users, but have annoyed me over the years. A few silly server
errors, some instances of uploads failing for anything other than zip files,
that sort of thing.</p>
<p>Oh, and if you&rsquo;re a extension author, PGXN Manger now allows updates to old
distribution versions to be uploaded. Previously it only allowed a new version
to be greater than all previous versions. Now it will allow a new X.Y.Z
version if X.Y previously existed and the new .Z is greater, and a new X.Y
version if X previously existed and the new .Y is greater than any previous
X.Y. To get this to work properly, I also dropped the check for versions of
extensions in the uploaded files. It would just be too complicated to add a
bunch of rules more likely to annoy than not. So it now only enforces patterns
for distribution release versions. I trust extension authors not to then lower
extension versions on new releases &mdash; that would just be silly, and not
helpful to your users.</p>
<p>As part of this work, I also revamped the management of the PGXN server. Back
in 2010 I wrote Capistrano files to manage the server, but have long ceased to
use them, as they ceased to work. I&rsquo;ve now removed all that detritus from the
PGXN Manager, API, and Site repositories, and replaced them all with a single
new repository, <a href="https://github.com/pgxn/pgxn-ops">pgxn-ops</a>, which contains Ansible playbooks to manage all the
services. They don&rsquo;t deal with a lot of the server-side stuff, which depesz
handles separately, but they now make it much easier to build and deploy a new
release, restart it remotely, manage passwords, etc.</p>
<p>And finally, I&rsquo;ve updated the <a href="https://pgxn.org/">PGXN search site</a>. In addition to fixing a few
long-standing minor annoyances (borders around images linked in documentation,
broken links, etc.), I also updated most of the graphics to be
retina-friendly. So it should look a lot sharper on your hi-res screens now.
Check it out!</p>
<p>Next up I think I&rsquo;d like to make the search site more mobile-friendly, and
then perhaps I&rsquo;ll finally go back and attack the terrible search provided by
the API. I&rsquo;ll try to do it in less than five years this time.</p>
]]></content></entry><entry><id>https://blog.pgxn.org/post/21171605888</id><title type="html">pgxn-utils 0.1.4 is out!</title><link rel="alternate" type="text/html" href="https://blog.pgxn.org/2012/pgxn-utils-014-is-out/"/><updated>2026-10-07T16:13:48Z</updated><published>2012-04-15T21:44:12Z</published><author><name>David E. Wheeler</name></author><category scheme="https://blog.pgxn.org/tags" term="pgxn" label="PGXN"/><category scheme="https://blog.pgxn.org/tags" term="utils" label="Utils"/><category scheme="https://blog.pgxn.org/tags" term="automation" label="Automation"/><category scheme="https://blog.pgxn.org/tags" term="release" label="Release"/><summary type="html"><![CDATA[<p><em>by Dickson S. Guedes</em></p>
<p>Hi everybody!</p>
<p>I&rsquo;m proud to tell you that a new version of <a href="https://github.com/guedes/pgxn-utils">PGXN Utils</a> was released with
this new features:</p>
<ul>
<li>Git support</li>
<li>Templates and custom templates</li>
<li><a href="https://pgxnclient.projects.postgresql.org/">PGXN Client</a> integration</li>
</ul>
<h2 id="git-support">Git support</h2>
<p>You can start a new extension with or without version control. By default
<code>pgxn-utils</code> supports <a href="https://git-scm.org">git</a> but it will not create a repository unless you use
<code>--git</code> option in the skeleton task.</p>
<p>You can try:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-console" data-lang="console"><span class="line"><span class="cl"><span class="gp">$</span> pgxn-utils skeleton my_cool_versioned_extension --git
</span></span></code></pre></div><p>When you create a new extension with git support in addition to creating the
skeleton, <code>pgxn-utils</code> will initialize a git repository and create the initial
commit.</p>]]></summary><content type="html" xml:base="https://blog.pgxn.org/" xml:space="preserve"><![CDATA[<p><em>by Dickson S. Guedes</em></p>
<p>Hi everybody!</p>
<p>I&rsquo;m proud to tell you that a new version of <a href="https://github.com/guedes/pgxn-utils">PGXN Utils</a> was released with
this new features:</p>
<ul>
<li>Git support</li>
<li>Templates and custom templates</li>
<li><a href="https://pgxnclient.projects.postgresql.org/">PGXN Client</a> integration</li>
</ul>
<h2 id="git-support">Git support</h2>
<p>You can start a new extension with or without version control. By default
<code>pgxn-utils</code> supports <a href="https://git-scm.org">git</a> but it will not create a repository unless you use
<code>--git</code> option in the skeleton task.</p>
<p>You can try:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-console" data-lang="console"><span class="line"><span class="cl"><span class="gp">$</span> pgxn-utils skeleton my_cool_versioned_extension --git
</span></span></code></pre></div><p>When you create a new extension with git support in addition to creating the
skeleton, <code>pgxn-utils</code> will initialize a git repository and create the initial
commit.</p>
<p>Once you have your extension in a git repository your <code>bundle</code> will use only
the committed files to create the archive, but if your repository is dirty
then <code>pgxn-utils</code> will suggest that you to commit or stash your changes before
bundling.</p>
<p>You must be careful with new files not added to repository, because they will
<strong>not</strong> be archived.</p>
<h2 id="default-templates">Default templates</h2>
<p>There are three default templates: <code>sql</code>, <code>c</code> and <code>fdw</code>. If you call
<code>skeleton</code> without specifying a template, <code>sql</code> is the default. But if your
extension will supply some C modules or you will create a FDW, you can create
the extension calling <code>skeleton</code> with a <code>--template</code> option.</p>
<p>Try:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-console" data-lang="console"><span class="line"><span class="cl"><span class="gp">$</span> pgxn-utils skeleton my_cool_c_extension --template<span class="o">=</span>c
</span></span><span class="line"><span class="cl"><span class="gp">$</span> pgxn-utils skeleton my_cool_fdw_extension --template<span class="o">=</span>fdw
</span></span></code></pre></div><p>The templates contain example code and some links to PostgreSQL documentation
that will try to help you to start coding. SQL and C templates contains some
test examples, and the example code will compile and pass <code>make installcheck</code>.
However, this code is intended to be an example, and you must write your own
tests and code.</p>
<h2 id="custom-templates">Custom templates</h2>
<p>If you don&rsquo;t like the templates provided by <code>pgxn-utils</code> you can create you
own. Just create a directory with at least a <code>META.json</code> or <code>META.json.tt</code>
file and then use your directory as argument to the <code>--template</code> option.</p>
<p>To know how create your own template, see the examples in the <a href="https://github.com/guedes/pgxn-utils/tree/master/lib/pgxn_utils/templates">templates
directory</a>.</p>
<h2 id="pgxn-client-integration">PGXN Client integration</h2>
<p>If you have <a href="https://pgxnclient.projects.postgresql.org/">PGXN client</a> installed you can change the command line from
<code>pgxn-utils some_task</code> to <code>pgxn some_task</code> and this will save you some typing.</p>
<p>See:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-console" data-lang="console"><span class="line"><span class="cl"><span class="gp">$</span> <span class="nb">cd</span> /tmp
</span></span><span class="line"><span class="cl"><span class="gp">$</span> pgxn skeleton --help
</span></span><span class="line"><span class="cl"><span class="go">PGXN Utils version: 0.1.4
</span></span></span><span class="line"><span class="cl"><span class="go">Usage:
</span></span></span><span class="line"><span class="cl"><span class="go">  pgxn skeleton extension_name
</span></span></span><span class="line"><span class="cl"><span class="err">
</span></span></span><span class="line"><span class="cl"><span class="go">Options:
</span></span></span><span class="line"><span class="cl"><span class="go">      [--git]                            # Initialize a git repository after create the extension
</span></span></span><span class="line"><span class="cl"><span class="go">  -a, [--abstract=ABSTRACT]              # Defines a short description to abstract
</span></span></span><span class="line"><span class="cl"><span class="go">  -p, [--target=TARGET]                  # Define the target directory
</span></span></span><span class="line"><span class="cl"><span class="go">                                          # Default: .
</span></span></span><span class="line"><span class="cl"><span class="go">      [--template=TEMPLATE]              # The template that will be used to create the extension. Expected values are: sql, c, fdw
</span></span></span><span class="line"><span class="cl"><span class="go">                                          # Default: sql
</span></span></span><span class="line"><span class="cl"><span class="go">  -r, [--release-status=RELEASE_STATUS]  # Initial extension&#39;s release status
</span></span></span><span class="line"><span class="cl"><span class="go">  -d, [--description=DESCRIPTION]        # A long text that contains more information about extension
</span></span></span><span class="line"><span class="cl"><span class="go">  -b, [--generated-by=GENERATED_BY]      # Name of extension&#39;s generator
</span></span></span><span class="line"><span class="cl"><span class="go">  -l, [--license=LICENSE]                # The extension license
</span></span></span><span class="line"><span class="cl"><span class="go">  -t, [--tags=one two three]             # Defines extension&#39;s tags
</span></span></span><span class="line"><span class="cl"><span class="go">  -v, [--version=VERSION]                # Initial version
</span></span></span><span class="line"><span class="cl"><span class="go">  -m, [--maintainer=MAINTAINER]          # Maintainer&#39;s name &lt;maintainer@email&gt;
</span></span></span><span class="line"><span class="cl"><span class="err">
</span></span></span><span class="line"><span class="cl"><span class="go">Creates an extension skeleton in current directory
</span></span></span><span class="line"><span class="cl"><span class="err">
</span></span></span><span class="line"><span class="cl"><span class="gp">$</span> pgxn skeleton <span class="nb">test</span>
</span></span><span class="line"><span class="cl"><span class="go">      create  test
</span></span></span><span class="line"><span class="cl"><span class="go">      create  test/test.control
</span></span></span><span class="line"><span class="cl"><span class="go">      create  test/.gitignore
</span></span></span><span class="line"><span class="cl"><span class="go">      create  test/.template
</span></span></span><span class="line"><span class="cl"><span class="go">      create  test/META.json
</span></span></span><span class="line"><span class="cl"><span class="go">      create  test/Makefile
</span></span></span><span class="line"><span class="cl"><span class="go">      create  test/README.md
</span></span></span><span class="line"><span class="cl"><span class="go">      create  test/doc/test.md
</span></span></span><span class="line"><span class="cl"><span class="go">      create  test/sql/test.sql
</span></span></span><span class="line"><span class="cl"><span class="go">      create  test/sql/uninstall_test.sql
</span></span></span><span class="line"><span class="cl"><span class="go">      create  test/test/expected/base.out
</span></span></span><span class="line"><span class="cl"><span class="go">      create  test/test/sql/base.sql
</span></span></span><span class="line"><span class="cl"><span class="err">
</span></span></span><span class="line"><span class="cl"><span class="gp">$</span> <span class="nb">cd</span> test/
</span></span><span class="line"><span class="cl"><span class="gp">$</span> pgxn bundle
</span></span><span class="line"><span class="cl"><span class="go">          run  make distclean from &#34;.&#34;
</span></span></span><span class="line"><span class="cl"><span class="go">      create  /tmp/test-0.0.1.zip
</span></span></span></code></pre></div><p>I hope you enjoy this version. &ldquo;:)</p>
]]></content></entry><entry><id>https://blog.pgxn.org/post/8742312488</id><title type="html">My presentation at the 2012 PDXPUG PGDay</title><link rel="alternate" type="text/html" href="https://blog.pgxn.org/2011/video-building-and-distributing-extensions-without-c/"/><updated>2026-10-07T16:13:48Z</updated><published>2011-08-10T18:58:09Z</published><author><name>David E. Wheeler</name></author><category scheme="https://blog.pgxn.org/tags" term="pgxn" label="PGXN"/><category scheme="https://blog.pgxn.org/tags" term="pgday" label="PgDay"/><category scheme="https://blog.pgxn.org/tags" term="oscon" label="OSCON"/><category scheme="https://blog.pgxn.org/tags" term="c" label="C"/><category scheme="https://blog.pgxn.org/tags" term="extensions" label="Extensions"/><category scheme="https://blog.pgxn.org/tags" term="video" label="Video"/><summary type="html">&lt;figure>
&lt;figcaption>
My presentation at the 2012 PDXPUG PGDay. It covers the basics of how to
create useful extensions to PostgreSQL and distribute them on PGXN---without
needing to learn C.
&lt;/figcaption>
&lt;/figure></summary><content type="html" xml:base="https://blog.pgxn.org/" xml:space="preserve">&lt;figure>
&lt;figcaption>
My presentation at the 2012 PDXPUG PGDay. It covers the basics of how to
create useful extensions to PostgreSQL and distribute them on PGXN---without
needing to learn C.
&lt;/figcaption>
&lt;/figure>
</content></entry><entry><id>https://blog.pgxn.org/post/5118152273</id><title type="html">New release for the PGXN client</title><link rel="alternate" type="text/html" href="https://blog.pgxn.org/2011/new-release-for-the-pgxn-client/"/><updated>2026-10-07T16:13:48Z</updated><published>2011-05-02T00:59:37Z</published><author><name>Daniele Varrazzo</name></author><category scheme="https://blog.pgxn.org/tags" term="pgxn" label="PGXN"/><category scheme="https://blog.pgxn.org/tags" term="client" label="Client"/><category scheme="https://blog.pgxn.org/tags" term="release" label="Release"/><category scheme="https://blog.pgxn.org/tags" term="uninstall" label="Uninstall"/><category scheme="https://blog.pgxn.org/tags" term="drop" label="Drop"/><category scheme="https://blog.pgxn.org/tags" term="sudo" label="sudo"/><summary type="html"><![CDATA[<p>During the last days I&rsquo;ve done some lightweight hacking on the PGXN client,
and I&rsquo;ve just released the last package on PyPI, with the still very shy
version number of 0.1a4.</p>
<p>First change: the package name. The package is now called <code>pgxnclient</code>,
without the point. As <a href="https://blog.pgxn.org/post/5026314153/writing-a-client-for-pgxn#dsq-comments">Marti has commented</a>, the point in the name could
create problems to some distributions which may have needed to munge it into a
shape fitting their naming constraints. So, in order to install the last
release you will need the command:</p>]]></summary><content type="html" xml:base="https://blog.pgxn.org/" xml:space="preserve"><![CDATA[<p>During the last days I&rsquo;ve done some lightweight hacking on the PGXN client,
and I&rsquo;ve just released the last package on PyPI, with the still very shy
version number of 0.1a4.</p>
<p>First change: the package name. The package is now called <code>pgxnclient</code>,
without the point. As <a href="https://blog.pgxn.org/post/5026314153/writing-a-client-for-pgxn#dsq-comments">Marti has commented</a>, the point in the name could
create problems to some distributions which may have needed to munge it into a
shape fitting their naming constraints. So, in order to install the last
release you will need the command:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-console" data-lang="console"><span class="line"><span class="cl"><span class="gp">$</span> easy_install pgxnclient
</span></span></code></pre></div><p>The name of the entry point script is still <code>pgxn</code> and it shouldn&rsquo;t change.</p>
<p>One of the new features in this release is the addition of commands <code>drop</code>, to
remove the the extensions of a distribution from a database (opposite of the
<code>load</code> command) and <code>uninstall</code>, to remove installed files from the system
(opposite of <code>install</code>).</p>
<p>Another change is the ability to work on a local zip or directory instead of
using the API to get metadata and package from PGXN. The main goal of this
feature is to help the packagers to test their packages with the client before
submission, verifying that the data uploaded can be used in an automatized
way.</p>
<p>A third change is in the <code>install</code> command: it previously required to be run
as root if, as likely, the PostgreSQL directories are system ones. I was
feeling this need slightly scary as download and build phases would have been
run as root too, so now <code>sudo</code> is invoked by the script only when installing,
with command line options allowing its customization.</p>
<p>What I feel mostly missing now is documentation: I know that adding it will
force a big review of the code, adding missing comments, add tests to enforce
what documented&hellip; so it&rsquo;s something I will start tomorrow. Once documentation
and code have converged there will also be a more sound basis to discuss about
the client features. And dare version 0.2, maybe :)</p>
<p>Thanks everybody for the feedback. If you want to have a chat about the client
or PGXN in general, the best place is <a href="https://groups.google.com/group/pgxn-users">the PGXN group</a>. See you there!</p>
]]></content></entry><entry><id>https://blog.pgxn.org/post/1353947079</id><title type="html">Creating Distributions</title><link rel="alternate" type="text/html" href="https://blog.pgxn.org/2010/creating-distributions/"/><updated>2026-10-07T16:13:48Z</updated><published>2010-10-19T22:28:00Z</published><author><name>David E. Wheeler</name></author><category scheme="https://blog.pgxn.org/tags" term="distribution" label="Distribution"/><category scheme="https://blog.pgxn.org/tags" term="makefile" label="Makefile"/><category scheme="https://blog.pgxn.org/tags" term="pgxn" label="Pgxn"/><category scheme="https://blog.pgxn.org/tags" term="pgxs" label="Pgxs"/><category scheme="https://blog.pgxn.org/tags" term="pg_config" label="pg_config"/><category scheme="https://blog.pgxn.org/tags" term="pg_regress" label="pg_regress"/><category scheme="https://blog.pgxn.org/tags" term="directory-structure" label="Directory Structure"/><summary type="html"><![CDATA[<p>Following the <a href="https://blog.pgxn.org/post/1352326020/first-upload">upload of <code>pair</code></a> to PGXN, I wanted to take a few minutes to
write about how to structure a PGXN distribution.</p>
<h2 id="omg-distribution-wtf">OMG Distribution WTF?</h2>
<p>First of all, what is a &ldquo;distribution&rdquo; in the PGXN sense? Basically, it&rsquo;s a
collection of one or more PostgreSQL extensions. That&rsquo;s it.</p>
<p>So why allow more than one extension? Maybe no PGXN distribution will ever
have more than one extension. After all, the goal should be many focused,
minimalist tools that folks can combine in their apps. But sometimes it
doesn&rsquo;t work out that way.</p>]]></summary><content type="html" xml:base="https://blog.pgxn.org/" xml:space="preserve"><![CDATA[<p>Following the <a href="https://blog.pgxn.org/post/1352326020/first-upload">upload of <code>pair</code></a> to PGXN, I wanted to take a few minutes to
write about how to structure a PGXN distribution.</p>
<h2 id="omg-distribution-wtf">OMG Distribution WTF?</h2>
<p>First of all, what is a &ldquo;distribution&rdquo; in the PGXN sense? Basically, it&rsquo;s a
collection of one or more PostgreSQL extensions. That&rsquo;s it.</p>
<p>So why allow more than one extension? Maybe no PGXN distribution will ever
have more than one extension. After all, the goal should be many focused,
minimalist tools that folks can combine in their apps. But sometimes it
doesn&rsquo;t work out that way.</p>
<p>As an example, I&rsquo;ve been planning to break <a href="https://pgtap.org/">pgTAP</a> up into two parts for a
while: one for scalar and relational testing, the other for schema testing.
Often one needs only the scalar and relational testing, while the schema
testing is more often needed only for testing replication and whatnot. Whether
or not I choose to distribute both parts in one package I have yet to
determine, but it could well make sense to keep them in one distribution.</p>
<p>Besides, I&rsquo;ve tried to write <a href="https://github.com/theory/pgxn-manager">PGXN::Manager</a> in such a way that it&rsquo;s not
specific to PostgreSQL. So that if someone wanted to create a Drupal XN with
it or something, they could. Or PyXN. Or, hell, even if <a href="https://cpan/org/">CPAN</a> wanted to
switch someday, they could. (Note that I&rsquo;ve registered myxn.org for fun. I may
or may not do anything with that, but see <a href="https://theory.github.com/mytap/">MyTAP</a>. Yes, I am insane.)</p>
<h2 id="thats-so-meta">That&rsquo;s So Meta</h2>
<p>Anyway, back to the structure of distributions. At its simplest, the only
thing PGXN requires is a single file, <code>META.json</code>, which describes the
package. This is (currently) the only file that PGXN Manager uses to index a
distribution, so it&rsquo;s important to get it right. The <a href="https://pgxn.org/meta/spec.html">PGXN Meta Spec</a> has a
rather complete example of a hypothetical pgTAP distribution <code>META.json</code>.</p>
<p>If you have only one .sql file for your extension and it&rsquo;s the same name as
the distribution (and I expect this would be common), then you can make it
pretty simple. For example, the <code>pair</code> distribution has only one SQL file. So
the <code>META.json</code> could be:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;name&#34;</span><span class="p">:</span> <span class="s2">&#34;pair&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;abstract&#34;</span><span class="p">:</span> <span class="s2">&#34;A key/value pair data type&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;version&#34;</span><span class="p">:</span> <span class="s2">&#34;0.1.0&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;maintainer&#34;</span><span class="p">:</span> <span class="s2">&#34;David E. Wheeler &lt;david@justatheory.com&gt;&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;license&#34;</span><span class="p">:</span> <span class="s2">&#34;postgresql&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;meta-spec&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;version&#34;</span><span class="p">:</span> <span class="s2">&#34;1.0.0&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;url&#34;</span><span class="p">:</span> <span class="s2">&#34;https://pgxn.org/meta/spec.txt&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="p">},</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>That&rsquo;s it. The only thing that may not be obvious from this example is that
all version numbers in a <code>META.json</code> <em>must</em> be <a href="https://semver.org/">semantic versions</a>. If they&rsquo;re
not, PGXN will make them so. So &ldquo;1.2&rdquo; will become &ldquo;1.2.0&rdquo;, and so would
&ldquo;1.02&rdquo;. So do try to use semantic versions and not worry about it.</p>
<p>In the short run, you won&rsquo;t need anything more in your <code>META.json</code> file. But
once I get to creating the search site and the command-line client for PGXN,
you&rsquo;re probably going to want to do more. Other useful keys to include are:</p>
<ul>
<li><a href="https://pgxn.org/meta/spec.html#tags"><code>tags</code></a>: An array of tags to associate with a distribution. Will help
with searching.</li>
<li><a href="https://pgxn.org/meta/spec.html#prereqs"><code>prereqs</code></a>: A list of prerequisite extensions or PostgreSQL contrib
moules (or PostgreSQL itself).</li>
<li><a href="https://pgxn.org/meta/spec.html#provides"><code>provides</code></a>: A list of included extensions. Useful if you have more than
one or the one has a different name that the distribution (silly, but it
happens). It also will index such extension names such that you are the
owner, if you&rsquo;re the first to update one with that name.</li>
<li><a href="https://pgxn.org/meta/spec.html#release_status"><code>release_status</code></a>: To label a distribution as &ldquo;stable,&rdquo; &ldquo;unstable,&rdquo; or
&ldquo;testing.&rdquo; Useful for uploading distributions for people to test but that
clients won&rsquo;t install by default.</li>
<li><a href="https://pgxn.org/meta/spec.html#resources"><code>resources</code></a>: A list of related links, such as to an SCM repository or
bug tracker. The search site will output these links.</li>
</ul>
<p>Have a look at <a href="https://github.com/theory/kv-pair/blob/master/META.json">the <code>META.json</code> in the <code>pair</code> distribution</a> for a more
extended example.</p>
<h2 id="new-order">New Order</h2>
<p>For PGXN, the general idea is that you&rsquo;ll use <a href="https://www.postgresql.org/docs/9/static/xfunc-c.html#XFUNC-C-PGXS">PGXS</a> to create your PostgreSQL
extensions. I&rsquo;m hoping to encourage a slight modification of the directory
layout for PGXN distributions, but as I hope I&rsquo;ve made clear so far, PGXN
itself doesn&rsquo;t really care how you structure things, or if you use PGXS. That
said, the proposed <a href="https://wiki.postgresql.org/wiki/PGXN#PGXN_Client">download and installation client</a> will assume the use of
PGXS (unless and until the PostgreSQL core adds some other kind of
extension-building support), so it&rsquo;s probably the best choice.</p>
<p>Most PGXS-powered distributions have the code files in the main directory,
with documentation in a <code>README.extension_name</code> file. What I&rsquo;d like to see
instead, and will encourage via the forthcoming <a href="https://wiki.postgresql.org/wiki/PGXN#Search_Site">search site</a>, is that things
be organized into subdirectories:</p>
<ul>
<li><code>src</code> for any C source code files</li>
<li><code>sql</code> for SQL source files. These usually are responsible for installing an
extension into a database</li>
<li><code>doc</code> for documentation files (the search site will likely look there for
Markdown, Textile, HTML, and other document formats)</li>
<li><code>test</code> for tests</li>
</ul>
<p>I&rsquo;ve tried to make the <code>pair</code> distribution a good <a href="https://github.com/theory/kv-pair/blob/">example of this</a>. To make
it all work, The <a href="https://github.com/theory/kv-pair/blob/master/Makefile">Makefile</a> is written like so:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-makefile" data-lang="makefile"><span class="line"><span class="cl"><span class="nv">DATA</span> <span class="o">=</span> sql/pair.sql sql/uninstall_pair.sql
</span></span><span class="line"><span class="cl"><span class="nv">TESTS</span> <span class="o">=</span> <span class="k">$(</span>wildcard test/sql/*.sql<span class="k">)</span>
</span></span><span class="line"><span class="cl"><span class="nv">REGRESS</span> <span class="o">=</span> <span class="k">$(</span>patsubst test/sql/%.sql,%,<span class="k">$(</span>TESTS<span class="k">))</span>
</span></span><span class="line"><span class="cl"><span class="nv">REGRESS_OPTS</span> <span class="o">=</span> --inputdir<span class="o">=</span><span class="nb">test</span>
</span></span><span class="line"><span class="cl"><span class="nv">DOCS</span> <span class="o">=</span> doc/pair.txt
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="err">ifdef</span> <span class="err">NO_PGXS</span>
</span></span><span class="line"><span class="cl"><span class="nv">top_builddir</span> <span class="o">=</span> ../..
</span></span><span class="line"><span class="cl"><span class="err">include</span> <span class="k">$(</span><span class="nv">top_builddir</span><span class="k">)</span><span class="err">/src/Makefile.global</span>
</span></span><span class="line"><span class="cl"><span class="err">include</span> <span class="k">$(</span><span class="nv">top_srcdir</span><span class="k">)</span><span class="err">/contrib/contrib-global.mk</span>
</span></span><span class="line"><span class="cl"><span class="err">else</span>
</span></span><span class="line"><span class="cl"><span class="nv">PG_CONFIG</span> <span class="o">=</span> pg_config
</span></span><span class="line"><span class="cl"><span class="nv">PGXS</span> <span class="o">:=</span> <span class="k">$(</span>shell <span class="k">$(</span>PG_CONFIG<span class="k">)</span> --pgxs<span class="k">)</span>
</span></span><span class="line"><span class="cl"><span class="err">include</span> <span class="k">$(</span><span class="nv">PGXS</span><span class="k">)</span>
</span></span><span class="line"><span class="cl"><span class="err">endif</span>
</span></span></code></pre></div><p>The <code>DATA</code> variable identifies the files containing the extension, while
<code>TESTS</code> loads a list of all the tests, which are in the <code>test/sql</code> directory.
Note that I&rsquo;m using <code>pg_regress</code> for tests. It expects that tests be named and
that there be corresponding &ldquo;expected&rdquo; files to compare against. With the
<code>REGRESS_OPTS = --inputdir=test</code> line, I&rsquo;m telling <code>pg_regess</code> to find the
test files in <a href="https://github.com/theory/kv-pair/tree/master/test/sql/"><code>test/sql</code></a> and the expected output files in <a href="https://github.com/theory/kv-pair/tree/master/test/expected/"><code>test/expected</code></a>.
And finally, the <code>DOCS</code> variable points to a single file with the
documentation, <a href="https://github.com/theory/kv-pair/blob/master/doc/pair.txt"><code>doc/pair.txt</code></a>. If this extension had required any C code
(like <a href="https://pgtap.org/">pgTAP</a> or <a href="https://postgis.org/">PostGIS</a> do), I would have pointed the <code>MODULES</code> variable at
files in a <code>src</code> directory.</p>
<p>After that we just have build instructions. If called with <code>make NO_PGXS=1</code>,
it assumes that the unzipped distribution directory has been put in the
&ldquo;contrib&rdquo; directory of the PostgreSQL source tree used to build PostgreSQL.
That&rsquo;s probably only important if one is installing on PostgreSQL 8.1 or
lower. Otherwise, it assumes a plain <code>make</code> and uses the <a href="https://www.postgresql.org/docs/current/static/app-pgconfig.html"><code>pg_config</code></a> in your
path to find PGXS to do the build.</p>
<p>For more on PostgreSQL extension building support, please consult <a href="https://www.postgresql.org/docs/9/static/xfunc-c.html#XFUNC-C-PGXS">the
documentation</a>.</p>
<h2 id="zip-me-up">Zip Me Up</h2>
<p>Once you&rsquo;ve got your extension developed and well-tested, and your
distribution just right and the <code>META.json</code> file all proof-read and solid,
it&rsquo;s time to upload the distribution to PGXN. What you want to do is to zip it
up to create a distribution archive. Here&rsquo;s what I did for <code>pair</code>, exporting
it from Git:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sh" data-lang="sh"><span class="line"><span class="cl">git checkout-index -af --prefix ~/Desktop/pair-0.1.0/
</span></span><span class="line"><span class="cl"><span class="nb">cd</span> ~/Desktop/
</span></span><span class="line"><span class="cl">rm pair-0.1.0/.gitignore
</span></span><span class="line"><span class="cl">zip -r pair-0.1.0.zip pair-0.1.0
</span></span></code></pre></div><p>Then the <code>pair-0.1.0.zip</code> file was ready to upload. Simple, eh?</p>
<p>Now, one can upload any kind of archive file to PGXN, including a tarball, or
bzip2&hellip;um&hellip;ball? Basically, any kind of archive format recognized by
<a href="https://search.cpan.org/perldoc?Archive::Extract">Archive::Extract</a>. You can upload a <code>.pgz</code> if you like, in which case PGXN
will assume that it&rsquo;s a zip file. A zip file is best because then
PGXN::Manager won&rsquo;t have to rewrite it. It&rsquo;s also preferable that everything
be unpacked from an archive into a directory with the name
<code>$distribution-$version</code>. If not, PGXN will rewrite it to do so. But it saves
the server some effort if all it has to do is move a .zip file that&rsquo;s properly
formatted, so it would be appreciated if you would upload stuff that&rsquo;s already
nicely formatted for distribution in a zip archive.</p>
<h2 id="release-it">Release It!</h2>
<p>And that&rsquo;s it! Not too bad, eh? Just please do be very careful cutting and
pasting examples; I initially uploaded the <code>pair</code> distribution thinking that
it contained pgTAP. It was kind of a PITA to fix. Hopefully we&rsquo;ll be able to
build things up to the point where a lot of this stuff can be automated
(especially the creation of the <code>META.json</code>), but for now it&rsquo;s done by hand.
So be careful out there, and good luck!</p>
<p>Oh, and if you have an extension that you&rsquo;d like to release on PGXN now, I am
running a limited beta for interested extension developers. Please hit the
<a href="https://groups.google.com/group/pgxn-users/">mail list</a> for the details to be posted shortly.</p>
]]></content></entry><entry><id>https://blog.pgxn.org/post/1352594371</id><title type="html">Fundraising and Development Update</title><link rel="alternate" type="text/html" href="https://blog.pgxn.org/2010/fundraising-development-update/"/><updated>2026-10-07T16:13:48Z</updated><published>2010-10-19T18:43:57Z</published><author><name>David E. Wheeler</name></author><category scheme="https://blog.pgxn.org/tags" term="fundraising" label="Fundraising"/><category scheme="https://blog.pgxn.org/tags" term="development" label="Development"/><category scheme="https://blog.pgxn.org/tags" term="pgxn" label="PGXN"/><category scheme="https://blog.pgxn.org/tags" term="contribute" label="Contribute"/><category scheme="https://blog.pgxn.org/tags" term="perl" label="Perl"/><category scheme="https://blog.pgxn.org/tags" term="database" label="Database"/><category scheme="https://blog.pgxn.org/tags" term="pgwest" label="PgWest"/><category scheme="https://blog.pgxn.org/tags" term="conference" label="Conference"/><summary type="html"><![CDATA[<p>Yesterday was a busy day. In addition to making the <a href="https://blog.pgxn.org/post/1352326020/first-upload">first PGXN release</a>, I
updated the fundraising spreadsheet and then the thermometer displayed on the
<a href="https://pgxn.org/contributors.html">main site</a>. The good news is that things are coming along nicely. Thanks to
recent contributions from <a href="https://www.commandprompt.com/">Command Prompt</a>, <a href="https://www.marchex.com/">Marchex</a>, Hitoshi Harada, and
<a href="https://www.25th-floor.com/">25th-floor</a>, we are now just $2500 short of our goal of $25,000. Thank you
all!</p>
<p>Can you help us get to our goal in time for <a href="https://www.postgresqlconference.org/2010/west/">PgWest 2010</a>, which is November
2-4 in San Francisco? I&rsquo;ll be giving a talk there, &ldquo;<a href="https://www.postgresqlconference.org/content/building-and-distributing-postgresql-extensions-without-learning-c">Building and Distributing
PostgreSQL Extensions Without Learning C</a>&rdquo;, in which PGXN will of course be
featured. Would be great to announce that the fundraising was successful.</p>]]></summary><content type="html" xml:base="https://blog.pgxn.org/" xml:space="preserve"><![CDATA[<p>Yesterday was a busy day. In addition to making the <a href="https://blog.pgxn.org/post/1352326020/first-upload">first PGXN release</a>, I
updated the fundraising spreadsheet and then the thermometer displayed on the
<a href="https://pgxn.org/contributors.html">main site</a>. The good news is that things are coming along nicely. Thanks to
recent contributions from <a href="https://www.commandprompt.com/">Command Prompt</a>, <a href="https://www.marchex.com/">Marchex</a>, Hitoshi Harada, and
<a href="https://www.25th-floor.com/">25th-floor</a>, we are now just $2500 short of our goal of $25,000. Thank you
all!</p>
<p>Can you help us get to our goal in time for <a href="https://www.postgresqlconference.org/2010/west/">PgWest 2010</a>, which is November
2-4 in San Francisco? I&rsquo;ll be giving a talk there, &ldquo;<a href="https://www.postgresqlconference.org/content/building-and-distributing-postgresql-extensions-without-learning-c">Building and Distributing
PostgreSQL Extensions Without Learning C</a>&rdquo;, in which PGXN will of course be
featured. Would be great to announce that the fundraising was successful.</p>
<p>As for the time I&rsquo;ve put in so far, I&rsquo;m happy to have PGXN Manager up and
working, but of course it has taken more hours than I expected. 76.5 so far.
I&rsquo;d estimated 40. Meanwhile, the database design is up to 43 hours from the
estimated 24. And that doesn&rsquo;t count the hours I spent chasing shiny yaks and
shaving them, like <a href="https://search.cpan.org/perldoc?SemVer">SemVer</a> and <a href="https://search.cpan.org/perldoc?Router::Resource">Router::Resource</a>. Those of you who estimate
development projects, take heed! I clearly need to double all my estimates
before I submit them.</p>
<p>Still, with the fundraising nearly done, I&rsquo;m committed to finishing this
project. I view it as a project budget, and so that&rsquo;s what it will be, whether
or not it takes me twice or four times as many hours as I&rsquo;d estimated.</p>
<p>That said, you could help. Right? PGXN Manager is in good shape, but it&rsquo;s not
done. If you&rsquo;d like to roll up your sleeves and contribute some code, please
<a href="https://github.com/theory/pgxn-manager/">fork it</a>, build it, and hack what you can. A few things on the to-do list:</p>
<ul>
<li>Add user admin interface. Should include checkbox to make and remove
administrative permission</li>
<li>Add mirror admin interface</li>
<li>Add extension ownership permissions interface</li>
</ul>
<p>The database API is there for these bits already; the code would mainly be in
Perl. Hit me on #pgxn on <a href="https://webchat.freenode.net/">Freenode</a> if you want to help.</p>
<p>If documentation is your thing, contributions there would be appreciated, as
well. In particular, the <a href="https://manager.pgxn.org/about">About PGXN</a> page is a bit thin. Other interfaces
will need help, too. More on that as we add users.</p>
<p>Thanks everyone for your support!</p>
]]></content></entry><entry><id>https://blog.pgxn.org/post/1352326020</id><title type="html">First Upload to PGXN</title><link rel="alternate" type="text/html" href="https://blog.pgxn.org/2010/first-upload/"/><updated>2026-10-07T16:13:48Z</updated><published>2010-10-19T17:46:44Z</published><author><name>David E. Wheeler</name></author><category scheme="https://blog.pgxn.org/tags" term="pgxn" label="PGXN"/><category scheme="https://blog.pgxn.org/tags" term="upload" label="Upload"/><category scheme="https://blog.pgxn.org/tags" term="distribution" label="Distribution"/><category scheme="https://blog.pgxn.org/tags" term="metadata" label="Metadata"/><category scheme="https://blog.pgxn.org/tags" term="json" label="JSON"/><category scheme="https://blog.pgxn.org/tags" term="pair" label="Pair"/><summary type="html"><![CDATA[<p>Last night I deployed <a href="https://github.com/theory/pgxn-manager/">PGXN::Manager</a> v0.2.1 and uploaded the first
distribution, <a href="https://master.pgxn.org/dist/pair/">pair</a>. If you follow that link you&rsquo;ll see three files:</p>
<ul>
<li><a href="https://master.pgxn.org/dist/pair/pair-0.1.0.json"><code>pair-0.1.0.json</code></a> is metadata file generated by PGXN manager to describe
the distribution. Most of its data is taken from the <a href="https://github.com/theory/kv-pair/blob/master/META.json"><code>META.json</code></a> included
in the uploaded zip file, but a few keys, like &ldquo;sha1&rdquo;, are generated, and
others, like &ldquo;release_status&rdquo; are added if they&rsquo;re not in the included
<code>META.json</code>.</li>
<li><a href="https://master.pgxn.org/dist/pair/pair-0.1.0.readme">pair-0.0.1.readme</a> is a copy of the <code>README</code> file distributed with pair.</li>
<li><a href="https://master.pgxn.org/dist/pair/pair-0.1.0.pgz">pair-0.1.0.pgz</a> is the distribution zip file. That&rsquo;s the file you want to
download, unzip, and build and install.</li>
</ul>
<p>Following the spec I previously <a href="https://blog.pgxn.org/post/988613682/restful-directory">wrote up</a>, there are a number of other files
that get created when a new distribution is uploaded to PGXN. For the pair
extension, we got:</p>]]></summary><content type="html" xml:base="https://blog.pgxn.org/" xml:space="preserve"><![CDATA[<p>Last night I deployed <a href="https://github.com/theory/pgxn-manager/">PGXN::Manager</a> v0.2.1 and uploaded the first
distribution, <a href="https://master.pgxn.org/dist/pair/">pair</a>. If you follow that link you&rsquo;ll see three files:</p>
<ul>
<li><a href="https://master.pgxn.org/dist/pair/pair-0.1.0.json"><code>pair-0.1.0.json</code></a> is metadata file generated by PGXN manager to describe
the distribution. Most of its data is taken from the <a href="https://github.com/theory/kv-pair/blob/master/META.json"><code>META.json</code></a> included
in the uploaded zip file, but a few keys, like &ldquo;sha1&rdquo;, are generated, and
others, like &ldquo;release_status&rdquo; are added if they&rsquo;re not in the included
<code>META.json</code>.</li>
<li><a href="https://master.pgxn.org/dist/pair/pair-0.1.0.readme">pair-0.0.1.readme</a> is a copy of the <code>README</code> file distributed with pair.</li>
<li><a href="https://master.pgxn.org/dist/pair/pair-0.1.0.pgz">pair-0.1.0.pgz</a> is the distribution zip file. That&rsquo;s the file you want to
download, unzip, and build and install.</li>
</ul>
<p>Following the spec I previously <a href="https://blog.pgxn.org/post/988613682/restful-directory">wrote up</a>, there are a number of other files
that get created when a new distribution is uploaded to PGXN. For the pair
extension, we got:</p>
<ul>
<li>
<p><a href="https://master.pgxn.org/by/dist/pair.json"><code>by/dist/pair.json</code></a>, which will be updated with information for every
release of the &ldquo;pair&rdquo; distribution.</p>
</li>
<li>
<p><a href="https://master.pgxn.org/by/extension/pair.json"><code>by/extension/pair.json</code></a>, which will be updated for every upload
containing the &ldquo;pair&rdquo; extension.</p>
</li>
<li>
<p><a href="https://master.pgxn.org/by/owner/theory.json"><code>by/owner/theory.json</code></a>, which will be updated every time I upload a
distribution.</p>
</li>
<li>
<p>Files for every tag listed in the <a href="https://master.pgxn.org/dist/pair/pair-0.1.0.json">metadata</a> are also
created. In this case, that includes:</p>
<ul>
<li><a href="https://master.pgxn.org/by/tag/key%20value%20pair.json"><code>by/tag/key value pair.json</code></a></li>
<li><a href="https://master.pgxn.org/by/tag/key%20value.json"><code>by/tag/key value.json</code></a></li>
<li><a href="https://master.pgxn.org/by/tag/ordered%20pair.json"><code>by/tag/ordered pair.json</code></a></li>
<li><a href="https://master.pgxn.org/by/tag/pair.json"><code>by/tag/pair.json</code></a></li>
<li><a href="https://master.pgxn.org/by/tag/variadic%20function.json"><code>by/tag/variadic function.json</code></a></li>
</ul>
<p>Each of these files will be updated every time a distribution is uploaded
containing the relevant tag.</p>
</li>
</ul>
<p>You&rsquo;ll soon be able to upload your own extension distributions to PGXN. If
you&rsquo;re interested, please subscribe to the <a href="https://groups.google.com/group/pgxn-users">mail list</a>, where I&rsquo;ll soon be
inviting folks to get an account and start uploading.</p>
<p>But first, a blog post on how to create a PGXN-friendly distribution archive.
Coming up shortly.</p>
]]></content></entry></feed>