Implement --self-upgrade capacity.

As from now, to install a new version of pgloader when you have an older
one, say because there's that bug that got fixed meanwhile, all you need
to do is run

  $ git clone https://github.com/dimitri/pgloader.git /tmp/pgloader
  $ pgloader --self-upgrade /tmp/pgloader <options as usual>

Any Common Lisp developper using the product is already doing that many
times a day, it might prove useful for users to be able to hot-patch
themselves too, after all.
This commit is contained in:
Dimitri Fontaine 2014-05-03 00:25:44 +02:00
parent 1d480c2590
commit fecae2c2d9
4 changed files with 65 additions and 4 deletions

View File

@ -33,7 +33,8 @@ candidate). The next stable versions are going to be `3.1` then `3.2` etc.
## INSTALL
pgloader is now a Common Lisp program, tested using the
[SBCL](http://sbcl.org/) (>= 1.1.14) implementation with
[SBCL](http://sbcl.org/) (>= 1.1.14) and
[Clozure CL](http://ccl.clozure.com/) implementations with
[Quicklisp](http://www.quicklisp.org/beta/).
$ apt-get install sbcl libsqlite3-dev make curl
@ -41,6 +42,27 @@ pgloader is now a Common Lisp program, tested using the
$ make pgloader
$ ./build/bin/pgloader --help
You can also fetch pre-made binary packages at
[pgloader.io](http://pgloader.io/download.html).
## Testing a new feature
Being a Common Lisp program, pgloader is able to *upgrade itself* at run
time, and provides the command-line option `--self-upgrade` that just does
that.
If you want to test the current repository version (or any checkout really),
it's possible to clone the sources then load them with an older pgloader
release:
$ git clone https://github.com/dimitri/pgloader.git /tmp/pgloader
$ /usr/bin/pgloader --self-upgrade /tmp/pgloader myfile.load
Here, the code from the *git clone* will be used at run-time. Of course,
code that has changed before the self-upgrade mechanism is executed will
have no change to get run again. That only includes command line options
processing, though.
## The pgloader.lisp script
Now you can use the `#!` script or build a self-contained binary executable

View File

@ -1,7 +1,7 @@
.\" generated with Ronn/v0.7.3
.\" http://github.com/rtomayko/ronn/tree/0.7.3
.
.TH "PGLOADER" "1" "April 2014" "ff" ""
.TH "PGLOADER" "1" "May 2014" "ff" ""
.
.SH "NAME"
\fBpgloader\fR \- PostgreSQL data loader
@ -75,6 +75,12 @@ Parse given files in the command line as \fBpgloader\.conf\fR files with the \fB
\-l \fIfile\fR, \-\-load \fIfile\fR
Specify a lisp \fIfile\fR to compile and load into the pgloader image before reading the commands, allowing to define extra transformation function\. Those functions should be defined in the \fBpgloader\.transforms\fR package\. This option can appear more than once in the command line\.
.
.TP
\-\-self\-upgrade \fIdirectory\fR:
.
.IP
Specify a \fIdirectory\fR where to find pgloader sources so that one of the very first things it does is dynamically loading\-in (and compiling to machine code) another version of itself, usually a newer one like a very recent git checkout\.
.
.P
To get the maximum amount of debug information, you can use both the \fB\-\-verbose\fR and the \fB\-\-debug\fR switches at the same time, which is equivalent to saying \fB\-\-client\-min\-messages data\fR\. Then the log messages will show the data being processed, in the cases where the code has explicit support for it\.
.

View File

@ -60,6 +60,13 @@ pgloader operates from commands which are read from files:
Those functions should be defined in the `pgloader.transforms` package.
This option can appear more than once in the command line.
* --self-upgrade <directory>:
Specify a <directory> where to find pgloader sources so that one of the
very first things it does is dynamically loading-in (and compiling to
machine code) another version of itself, usually a newer one like a very
recent git checkout.
To get the maximum amount of debug information, you can use both the
`--verbose` and the `--debug` switches at the same time, which is equivalent
to saying `--client-min-messages data`. Then the log messages will show the

View File

@ -38,7 +38,10 @@
:documentation "Filename where to send the logs.")
(("load" #\l) :type string :list t :optional t
:documentation "Read user code from file")))
:documentation "Read user code from file")
("self-upgrade" :type string :optional t
:documentation "Path to pgloader newer sources")))
(defun print-backtrace (condition debug stream)
"Depending on DEBUG, print out the full backtrace or just a shorter
@ -79,6 +82,25 @@
(command-line-arguments:show-option-help *opt-spec*)
(when quit (uiop:quit)))
(defun self-upgrade (namestring)
"Load pgloader sources at PATH-TO-PGLOADER-SOURCES."
(let ((pgloader-pathname (uiop:directory-exists-p
(uiop:parse-unix-namestring namestring))))
(unless pgloader-pathname
(format t "No such directory: ~s~%" namestring)
(uiop:quit))
;; now the real thing
(handler-case
(handler-bind ((condition #'muffle-warning))
(let ((asdf:*central-registry* (list* pgloader-pathname
asdf:*central-registry*)))
(format t "Self-upgrading from sources at ~s~%"
(uiop:native-namestring pgloader-pathname))
(asdf:load-system :pgloader)))
(condition (c)
(format t "Fatal: ~a~%" c)))))
(defun main (argv)
"Entry point when building an executable image with buildapp"
(let ((args (rest argv)))
@ -93,7 +115,7 @@
(destructuring-bind (&key help version quiet verbose debug logfile
list-encodings upgrade-config load
client-min-messages log-min-messages
root-dir)
root-dir self-upgrade)
options
;; First care about the root directory where pgloader is supposed to
@ -137,6 +159,10 @@
(format t "~%~%"))
(uiop:quit))
;; Self Upgrade?
(when self-upgrade
(self-upgrade self-upgrade))
(when load
(loop for filename in load
do (load (compile-file filename :verbose nil :print nil))))