Skip to content

Commit 0a6a755

Browse files
committed
Install rule: add CONF_INSTALL_VERSION_ALIAS (version-named symlinks); harmonize CONF_INSTALL_SYMLINK cleanup.
- New CONF_INSTALL_VERSION_ALIAS configuration: each listed file or directory is aliased by a symlink which name contains the installed version number ('style.css' pointed by 'style-1.2.0.css') or the main branch's name. - CONF_INSTALL_SYMLINK: links cleanup is now pattern-based (version numbers and main branch name, non-committed links only), the 'main'-named link is created when the main branch is deployed, and links are never created over committed files. - Documentation and example configuration updated.
1 parent 5d94958 commit 0a6a755

3 files changed

Lines changed: 153 additions & 19 deletions

File tree

README.md

Lines changed: 40 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -169,10 +169,11 @@ $ dpk install --platform=test --tag=3.2.1
169169
Dispak will perform these operations:
170170
- On production server, check if the requested tag is not an unstable version (see [above](#112-version-numbering)).
171171
- Fetch and read the configuration file from the tag.
172-
- Remove previously created symlink (see [below](#35-static-files-symlinks-and-amazon-s3)).
172+
- Remove version-named symlinks and version alias links created by previous deployments (see [below](#35-static-files-symlinks-and-amazon-s3)).
173173
- Execute pre-install scripts (see [below](#33-prepost-scripts-execution)).
174174
- Execute pre-configuration scripts (see [below](#33-prepost-scripts-execution)).
175175
- **Deploy new version's source code.**
176+
- Create version-named symlinks and version alias links (see [below](#35-static-files-symlinks-and-amazon-s3)).
176177
- Install crontab file (see [below](#32-crontab-installation)).
177178
- Perform database migration (see [below](#31-database-migrations)).
178179
- Install Apache configuration files (see [below](#37-apache-configuration)).
@@ -509,28 +510,61 @@ Generator scripts are listed in the `CONF_INSTALL_GENERATE` variable of the [con
509510

510511
Dispak helps you to manage the static files of your web projects.
511512

512-
There is two (non-mutually exclusive) ways to manage these files: Using symlink, and copying files to Amazon S3.
513+
There is three (non-mutually exclusive) ways to manage these files: Using symlinks, using version alias links, and copying files to Amazon S3.
513514

514515
#### Symbolic links
515-
You can define a list of symbolic links in the [configuration file](#311-configuration-file). These links will be created during the tag installation process. In fact, you define the target of each link (usually a directory but it can be a file), and the directory where these links are going to be created. The created links are named with the installed version's number.
516+
You can define a list of symbolic links in the [configuration file](#311-configuration-file). These links will be created during the installation process. In fact, you define the target of each link (usually a directory but it can be a file), and the directory where these links are going to be created. The created links are named with the installed version's number, or with the name of the main branch when the main branch is deployed. The target is interpreted relative to the link's directory.
516517

517518
Example: Let's say your configuration file contains this line:
518519
```shell
519-
CONF_INSTALL_SYMLINK["www/css"]="www/css"
520+
CONF_INSTALL_SYMLINK["www/css"]="."
520521
```
521522

522523
Now, when the version `1.2.0` is installed, the following link will be created:
523524
```shell
524525
$ ls -l www/css/1.2.0
525526
www/css/1.2.0 -> .
526527
```
528+
And when the `main` branch is deployed (on a test server for example), the `www/css/main` link is created the same way.
529+
530+
Before each deployment, the symbolic links created by previous deployments are removed: every *symbolic link* of the configured directories whose name is a version number (`X.Y.Z`) or the main branch's name is deleted — unless it is committed in the git repository. Committed links are never removed, and no new link is created if its name is already used by a committed link or file.
527531

528532
Then you can adapt your templates:
529533
```html
530534
<link href="/css/{$conf.version}/style.css" rel="stylesheet">
531535
```
532536
(in this example, the `$conf.version` variable have been defined in the framework's configuration file, thanks to the [file generation](#34-files-generation) feature)
533537

538+
#### Version alias links
539+
While the symbolic links described above put the version number in the *path* of the URL (a whole directory at once), Dispak can also put the version number in the *name* of selected files or directories, by creating version-named symbolic links next to them. It is the usual way to do [cache busting](https://www.keycdn.com/support/what-is-cache-busting) with named assets (`bundle-1.2.0.js`).
540+
541+
List the files and/or directories in the `CONF_INSTALL_VERSION_ALIAS` variable of the [configuration file](#311-configuration-file):
542+
```shell
543+
CONF_INSTALL_VERSION_ALIAS="
544+
www/css/style.css
545+
www/js
546+
"
547+
```
548+
549+
When the version `1.2.0` is installed, the following links are created:
550+
```shell
551+
$ ls -l www/css/style-1.2.0.css www/js-1.2.0
552+
www/css/style-1.2.0.css -> style.css
553+
www/js-1.2.0 -> js
554+
```
555+
And when the `main` branch is deployed, the `www/css/style-main.css` and `www/js-main` links are created the same way.
556+
557+
The name of the link is computed from the name of the aliased element:
558+
- For a file with an extension, the version is added before the last extension (`style.css``style-1.2.0.css`, `jquery.min.js``jquery.min-1.2.0.js`).
559+
- For a file without extension, a dot file or a directory (even if its name contains a dot), the version is added at the end of the name (`toto``toto-1.2.0`, `assets.css/``assets.css-1.2.0`).
560+
561+
Then you can adapt your templates:
562+
```html
563+
<link href="/css/style-{$conf.version}.css" rel="stylesheet">
564+
```
565+
566+
The cleanup rules are the same as for the symbolic links above: before each deployment, the version alias links of previous deployments are removed if they are not committed; committed links are never removed, and no new link is created if its name is already used by a committed link or file. If a listed element is removed from the configuration, its old alias links must be removed manually.
567+
534568
#### Amazon S3
535569
It is also possible to define a bucket on Amazon S3 where your static files will be copied each time you create a *stable* version (or even for *unstable* version if you defined the `CONF_PKG_S3_UNSTABLE` configuration variable). A subdirectory will be created, named as the tag version number, and all configured files will be copied there.
536570

@@ -640,7 +674,8 @@ Here are the definable variables:
640674
- `CONF_PKG_S3_COMPRESS`: Set this variable to 1 if you want to compress text files (raw text, HTML, JSON, SVG…) sent to Amazon S3. Files are compressed with GZIP. Note that files are compressed and sent one by one, whereas folder synchronization is used when there is no compression. As a result, upload is quite slower with compression.
641675
- `CONF_PKG_S3_UNSTABLE`: Set this variable to 1 if you want to copy static files to Amazon S3 for stable *and* unstable versions (not only for stable versions).
642676
- **install rule**
643-
- `CONF_INSTALL_SYMLINK`: Use this variable if you need to create symlinks when you install a new version. It is an associative array; the key is the path to the link's directory; the value is the path pointed by the link. The link will be created in its destination directory, and its name is the installed tag's version number.
677+
- `CONF_INSTALL_SYMLINK`: Use this variable if you need to create symlinks when you install a new version. It is an associative array; the key is the path to the link's directory; the value is the path pointed by the link (interpreted relative to the link's directory). The link will be created in its destination directory, and its name is the installed tag's version number (or the main branch's name when the main branch is deployed). Links created by previous deployments are removed, unless they are committed.
678+
- `CONF_INSTALL_VERSION_ALIAS`: List of files and/or directories that must be aliased by a version-named symlink, created next to them (`www/css/style.css` is pointed by the `www/css/style-1.2.0.css` link when the `1.2.0` tag is installed). Links created by previous deployments are removed, unless they are committed.
644679
- `CONF_INSTALL_SCRIPTS_PRE`: Here is a list of scripts to execute before install.
645680
- `CONF_INSTALL_SCRIPTS_POST`: Here is a list of scripts to execute after install. The scripts are not executed if an error has occured during the install process.
646681
- `CONF_CONFIG_SCRIPTS_PRE`: Here is a list of scripts to execute before install (after pre-install scripts) or at the beginning of configuration (`dpk config` command).

dispak-example.conf

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,13 @@ CONF_PKG_S3["static.skriv.com"]="static.skriv.com/www"
5555
# Symlinks to create (key: where to create the link; value: what is pointed by the link)
5656
CONF_INSTALL_SYMLINK["/path/to/www"]="/path/to/www"
5757

58+
# Files and directories aliased with a version-named symlink
59+
# (e.g. '/path/to/www/css/style.css' pointed by a '/path/to/www/css/style-1.2.0.css' link)
60+
CONF_INSTALL_VERSION_ALIAS="
61+
/path/to/www/css/style.css
62+
/path/to/www/js
63+
"
64+
5865
# pre-install scripts
5966
CONF_INSTALL_SCRIPTS_PRE="/path/to/scripts/pre-install"
6067

rules/03-install.sh

Lines changed: 106 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -78,16 +78,14 @@ rule_exec_install() {
7878
# reset the configuration file
7979
git restore --staged --worktree "$GIT_REPO_PATH/etc/dispak.conf"
8080
fi
81-
# remove symlinks from the currently installed tag
81+
# get the currently deployed branch or tag (used as parameter of pre/post scripts)
8282
CURRENT_TAG="$(git symbolic-ref -q --short HEAD || git describe --tags --exact-match)"
83-
if [ "$CURRENT_TAG" != "$CONF_GIT_MAIN" ] && [ ${#CONF_INSTALL_SYMLINK[@]} -ne 0 ]; then
84-
for _SYMLINK in ${!CONF_INSTALL_SYMLINK[@]}; do
85-
if [ -L "$_SYMLINK/$CURRENT_TAG" ]; then
86-
echo "$(ansi bold)Removing symlink $(ansi reset)$(ansi dim)$_SYMLINK/$CURRENT_TAG$(ansi reset)"
87-
rm -f "$_SYMLINK/$CURRENT_TAG"
88-
fi
89-
done
90-
fi
83+
# remove version-named symlinks created by previous deployments
84+
for _SYMLINK in ${!CONF_INSTALL_SYMLINK[@]}; do
85+
_install_clean_version_links "$_SYMLINK" "" ""
86+
done
87+
# remove version alias links created by previous deployments
88+
_install_version_alias_cleanup
9189
# execute pre-install scripts
9290
_install_pre_scripts
9391
# execute pre-config scripts
@@ -103,12 +101,18 @@ rule_exec_install() {
103101
if ! git checkout "tags/${DPK_OPT["tag"]}" --quiet ; then
104102
abort "$(ansi red)Failed to update repository to tag '${DPK_OPT["tag"]}'.$(ansi reset)"
105103
fi
106-
# create symlinks
107-
for _SYMLINK in ${!CONF_INSTALL_SYMLINK[@]}; do
108-
echo "$(ansi bold)Create symlink $(ansi reset)$(ansi dim)${CONF_INSTALL_SYMLINK["$_SYMLINK"]}/${DPK_OPT["tag"]}$(ansi reset)"
109-
ln -s "${CONF_INSTALL_SYMLINK["$_SYMLINK"]}" "$_SYMLINK/${DPK_OPT["tag"]}"
110-
done
111104
fi
105+
# create symlinks (named with the tag number, or the main branch's name)
106+
for _SYMLINK in ${!CONF_INSTALL_SYMLINK[@]}; do
107+
if [ -e "$_SYMLINK/${DPK_OPT["tag"]}" ] || [ -L "$_SYMLINK/${DPK_OPT["tag"]}" ]; then
108+
# a committed link or file already uses this name
109+
continue
110+
fi
111+
echo "$(ansi bold)Create symlink $(ansi reset)$(ansi dim)$_SYMLINK/${DPK_OPT["tag"]}$(ansi reset)"
112+
ln -sn "${CONF_INSTALL_SYMLINK["$_SYMLINK"]}" "$_SYMLINK/${DPK_OPT["tag"]}"
113+
done
114+
# create version alias links
115+
_install_version_alias
112116
# install crontab
113117
_install_crontab
114118
# database migration
@@ -173,6 +177,94 @@ _install_post_scripts() {
173177
echo "$(ansi gree)Done$(ansi reset)"
174178
}
175179

180+
# _install_clean_version_links()
181+
# Remove the symbolic links of a directory which names contain a version number
182+
# (or the main branch's name) and that are not committed.
183+
# @param string Path to the directory to process.
184+
# @param string Prefix of the links' names (may be empty).
185+
# @param string Suffix of the links' names (may be empty).
186+
_install_clean_version_links() {
187+
for _VLINK in "$1/$2"*"$3"; do
188+
# this test must stay the first instruction of the loop: it absorbs the
189+
# literal pattern given by bash when the glob matches nothing
190+
if [ ! -L "$_VLINK" ]; then
191+
continue
192+
fi
193+
# extract the version part of the link's name
194+
_VPART="${_VLINK##*/}"
195+
_VPART="${_VPART#"$2"}"
196+
_VPART="${_VPART%"$3"}"
197+
if ! [[ "$_VPART" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]] && [ "$_VPART" != "$CONF_GIT_MAIN" ]; then
198+
continue
199+
fi
200+
# committed links are never removed
201+
if git ls-files --error-unmatch -- "$_VLINK" > /dev/null 2>&1; then
202+
continue
203+
fi
204+
echo "$(ansi bold)Removing symlink $(ansi reset)$(ansi dim)$_VLINK$(ansi reset)"
205+
rm -f "$_VLINK"
206+
done
207+
}
208+
209+
# _install_version_alias_cleanup()
210+
# Remove the version alias links created by previous deployments.
211+
_install_version_alias_cleanup() {
212+
if [ "$CONF_INSTALL_VERSION_ALIAS" = "" ]; then
213+
return
214+
fi
215+
for _ALIAS in $CONF_INSTALL_VERSION_ALIAS; do
216+
_ALIAS_DIR="$(dirname "$_ALIAS")"
217+
_ALIAS_BASE="$(basename "$_ALIAS")"
218+
# version added at the end of the name (directories, files without extension)
219+
_install_clean_version_links "$_ALIAS_DIR" "${_ALIAS_BASE}-" ""
220+
# version added before the file's extension
221+
if [[ "${_ALIAS_BASE:1}" == *.* ]]; then
222+
_install_clean_version_links "$_ALIAS_DIR" "${_ALIAS_BASE%.*}-" ".${_ALIAS_BASE##*.}"
223+
fi
224+
done
225+
}
226+
227+
# _install_version_alias()
228+
# Create version alias links: for each listed file or directory, a symbolic link
229+
# which name contains the installed version number (or the main branch's name).
230+
_install_version_alias() {
231+
if [ "$CONF_INSTALL_VERSION_ALIAS" = "" ]; then
232+
return
233+
fi
234+
# the version must be a tag number or the main branch's name
235+
if ! [[ "${DPK_OPT["tag"]}" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]] && [ "${DPK_OPT["tag"]}" != "$CONF_GIT_MAIN" ]; then
236+
warn "Tag '$(ansi dim)${DPK_OPT["tag"]}$(ansi reset)' doesn't match the X.Y.Z format, no version alias created."
237+
return
238+
fi
239+
echo "$(ansi bold)Create version alias links$(ansi reset)"
240+
for _ALIAS in $CONF_INSTALL_VERSION_ALIAS; do
241+
# check the aliased element exists
242+
if [ ! -e "$_ALIAS" ] && [ ! -L "$_ALIAS" ]; then
243+
warn "Unable to find '$(ansi dim)$_ALIAS$(ansi reset)', no alias created."
244+
continue
245+
fi
246+
_ALIAS_DIR="$(dirname "$_ALIAS")"
247+
_ALIAS_BASE="$(basename "$_ALIAS")"
248+
# compute the link's name
249+
if [ -d "$_ALIAS" ] || [[ "${_ALIAS_BASE:1}" != *.* ]]; then
250+
# directory, file without extension or dot file: version added at the end
251+
_ALIAS_LINK="$_ALIAS_DIR/${_ALIAS_BASE}-${DPK_OPT["tag"]}"
252+
else
253+
# file: version added before the extension
254+
_ALIAS_LINK="$_ALIAS_DIR/${_ALIAS_BASE%.*}-${DPK_OPT["tag"]}.${_ALIAS_BASE##*.}"
255+
fi
256+
# create the link, unless its name is already used (committed link or file)
257+
if [ -e "$_ALIAS_LINK" ] || [ -L "$_ALIAS_LINK" ]; then
258+
continue
259+
fi
260+
echo "$(ansi dim)> $_ALIAS_LINK$(ansi reset)"
261+
ln -sn "$_ALIAS_BASE" "$_ALIAS_LINK"
262+
if [ $? -ne 0 ]; then
263+
abort "Unable to create the symlink '$(ansi dim)$_ALIAS_LINK$(ansi reset)'."
264+
fi
265+
done
266+
}
267+
176268
# _install_crontab()
177269
# Install new crontab file.
178270
_install_crontab() {

0 commit comments

Comments
 (0)