Skip to content

Commit dc59f0c

Browse files
authored
Merge pull request #205 from lalten/prek
Add `prek`
2 parents d861af9 + 061fa63 commit dc59f0c

File tree

7 files changed

+310
-0
lines changed

7 files changed

+310
-0
lines changed

src/prek/README.md

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
# prek (via Github Releases)
2+
3+
prek is a faster, dependency-free alternative to pre-commit, re-engineered in Rust.
4+
5+
## Example Usage
6+
7+
```json
8+
"features": {
9+
"ghcr.io/devcontainers-extra/features/prek:1": {}
10+
}
11+
```
12+
13+
## Options
14+
15+
| Options Id | Description | Type | Default Value |
16+
|-----|-----|-----|-----|
17+
| version | Select the version to install. | string | latest |
18+
19+
## About prek
20+
21+
[prek](https://github.com/j178/prek) is a reimagined version of pre-commit, built in Rust. It is designed to be a faster, dependency-free and drop-in alternative, while also providing some additional long-requested features.
22+
23+
### Key Features
24+
25+
- A single binary with no dependencies, does not require Python or any other runtime
26+
- Multiple times faster than `pre-commit` and takes up half the disk space
27+
- Fully compatible with the original pre-commit configurations and hooks
28+
- Built-in support for monorepos (workspace mode)
29+
- Integration with uv for managing Python virtual environments and dependencies
30+
- Built-in Rust-native implementation of some common hooks
31+
32+
## Installation
33+
34+
This feature installs prek from GitHub releases based on your system architecture (x86_64 or aarch64) and C library type (glibc or musl).
35+
36+
---
37+
38+
_Note: This file was auto-generated from the [devcontainer-feature.json](devcontainer-feature.json)._

src/prek/devcontainer-feature.json

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
{
2+
"id": "prek",
3+
"version": "1.0.0",
4+
"name": "prek (via Github Releases)",
5+
"documentationURL": "http://github.com/devcontainers-extra/features/tree/main/src/prek",
6+
"description": "prek is a faster, dependency-free alternative to pre-commit, re-engineered in Rust.",
7+
"options": {
8+
"version": {
9+
"default": "latest",
10+
"description": "Select the version to install.",
11+
"proposals": [
12+
"latest"
13+
],
14+
"type": "string"
15+
}
16+
},
17+
"installsAfter": [
18+
"ghcr.io/devcontainers-extra/features/gh-release"
19+
]
20+
}

src/prek/install.sh

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
#!/usr/bin/env bash
2+
3+
set -e
4+
5+
source ./library_scripts.sh
6+
7+
# nanolayer is a cli utility which keeps container layers as small as possible
8+
# source code: https://github.com/devcontainers-extra/nanolayer
9+
# `ensure_nanolayer` is a bash function that will find any existing nanolayer installations,
10+
# and if missing - will download a temporary copy that automatically get deleted at the end
11+
# of the script
12+
ensure_nanolayer nanolayer_location "v0.5.6"
13+
14+
# Detect C library type (musl for Alpine, gnu for Debian/Ubuntu)
15+
if [ -f "/lib/ld-musl-x86_64.so.1" ] || [ -f "/lib/ld-musl-aarch64.so.1" ]; then
16+
clib_type=musl
17+
else
18+
clib_type=gnu
19+
fi
20+
21+
# Detect architecture
22+
architecture="$(uname -m)"
23+
case $architecture in
24+
x86_64)
25+
arch="x86_64"
26+
;;
27+
aarch64)
28+
arch="aarch64"
29+
;;
30+
*)
31+
echo "(!) Architecture ${architecture} is not supported"
32+
exit 1
33+
;;
34+
esac
35+
36+
# Build asset regex to match prek release binaries
37+
# Example: prek-x86_64-unknown-linux-gnu.tar.gz
38+
asset_regex="^prek-${arch}-unknown-linux-${clib_type}\\.tar\\.gz$"
39+
40+
$nanolayer_location \
41+
install \
42+
devcontainer-feature \
43+
"ghcr.io/devcontainers-extra/features/gh-release:1.0.26" \
44+
--option repo='j178/prek' \
45+
--option binaryNames='prek' \
46+
--option version="$VERSION" \
47+
--option assetRegex="$asset_regex"
48+
49+
echo 'Done!'

src/prek/library_scripts.sh

Lines changed: 169 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,169 @@
1+
clean_download() {
2+
# The purpose of this function is to download a file with minimal impact on container layer size
3+
# this means if no valid downloader is found (curl or wget) then we install a downloader (currently wget) in a
4+
# temporary manner, and making sure to
5+
# 1. uninstall the downloader at the return of the function
6+
# 2. revert back any changes to the package installer database/cache (for example apt-get lists)
7+
# The above steps will minimize the leftovers being created while installing the downloader
8+
# Supported distros:
9+
# debian/ubuntu/alpine
10+
11+
url=$1
12+
output_location=$2
13+
tempdir=$(mktemp -d)
14+
downloader_installed=""
15+
16+
_apt_get_install() {
17+
tempdir=$1
18+
19+
# copy current state of apt list - in order to revert back later (minimize contianer layer size)
20+
cp -p -R /var/lib/apt/lists $tempdir
21+
apt-get update -y
22+
apt-get -y install --no-install-recommends wget ca-certificates
23+
}
24+
25+
_apt_get_cleanup() {
26+
tempdir=$1
27+
28+
echo "removing wget"
29+
apt-get -y purge wget --auto-remove
30+
31+
echo "revert back apt lists"
32+
rm -rf /var/lib/apt/lists/*
33+
rm -r /var/lib/apt/lists && mv $tempdir/lists /var/lib/apt/lists
34+
}
35+
36+
_apk_install() {
37+
tempdir=$1
38+
# copy current state of apk cache - in order to revert back later (minimize contianer layer size)
39+
cp -p -R /var/cache/apk $tempdir
40+
41+
apk add --no-cache wget
42+
}
43+
44+
_apk_cleanup() {
45+
tempdir=$1
46+
47+
echo "removing wget"
48+
apk del wget
49+
}
50+
# try to use either wget or curl if one of them already installer
51+
if type curl >/dev/null 2>&1; then
52+
downloader=curl
53+
elif type wget >/dev/null 2>&1; then
54+
downloader=wget
55+
else
56+
downloader=""
57+
fi
58+
59+
# in case none of them is installed, install wget temporarly
60+
if [ -z $downloader ] ; then
61+
if [ -x "/usr/bin/apt-get" ] ; then
62+
_apt_get_install $tempdir
63+
elif [ -x "/sbin/apk" ] ; then
64+
_apk_install $tempdir
65+
else
66+
echo "distro not supported"
67+
exit 1
68+
fi
69+
downloader="wget"
70+
downloader_installed="true"
71+
fi
72+
73+
if [ $downloader = "wget" ] ; then
74+
wget -q $url -O $output_location
75+
else
76+
curl -sfL $url -o $output_location
77+
fi
78+
79+
# NOTE: the cleanup procedure was not implemented using `trap X RETURN` only because
80+
# alpine lack bash, and RETURN is not a valid signal under sh shell
81+
if ! [ -z $downloader_installed ] ; then
82+
if [ -x "/usr/bin/apt-get" ] ; then
83+
_apt_get_cleanup $tempdir
84+
elif [ -x "/sbin/apk" ] ; then
85+
_apk_cleanup $tempdir
86+
else
87+
echo "distro not supported"
88+
exit 1
89+
fi
90+
fi
91+
92+
}
93+
94+
95+
ensure_nanolayer() {
96+
# Ensure existance of the nanolayer cli program
97+
local variable_name=$1
98+
99+
local required_version=$2
100+
101+
local __nanolayer_location=""
102+
103+
# If possible - try to use an already installed nanolayer
104+
if [ -z "${NANOLAYER_FORCE_CLI_INSTALLATION}" ]; then
105+
if [ -z "${NANOLAYER_CLI_LOCATION}" ]; then
106+
if type nanolayer >/dev/null 2>&1; then
107+
echo "Found a pre-existing nanolayer in PATH"
108+
__nanolayer_location=nanolayer
109+
fi
110+
elif [ -f "${NANOLAYER_CLI_LOCATION}" ] && [ -x "${NANOLAYER_CLI_LOCATION}" ] ; then
111+
__nanolayer_location=${NANOLAYER_CLI_LOCATION}
112+
echo "Found a pre-existing nanolayer which were given in env variable: $__nanolayer_location"
113+
fi
114+
115+
# make sure its of the required version
116+
if ! [ -z "${__nanolayer_location}" ]; then
117+
local current_version
118+
current_version=$($__nanolayer_location --version)
119+
120+
121+
if ! [ $current_version == $required_version ]; then
122+
echo "skipping usage of pre-existing nanolayer. (required version $required_version does not match existing version $current_version)"
123+
__nanolayer_location=""
124+
fi
125+
fi
126+
127+
fi
128+
129+
# If not previuse installation found, download it temporarly and delete at the end of the script
130+
if [ -z "${__nanolayer_location}" ]; then
131+
132+
if [ "$(uname -sm)" = 'Linux x86_64' ] || [ "$(uname -sm)" = "Linux aarch64" ]; then
133+
tmp_dir=$(mktemp -d -t nanolayer-XXXXXXXXXX)
134+
135+
clean_up () {
136+
ARG=$?
137+
rm -rf $tmp_dir
138+
exit $ARG
139+
}
140+
trap clean_up EXIT
141+
142+
143+
if [ -x "/sbin/apk" ] ; then
144+
clib_type=musl
145+
else
146+
clib_type=gnu
147+
fi
148+
149+
tar_filename=nanolayer-"$(uname -m)"-unknown-linux-$clib_type.tgz
150+
151+
# clean download will minimize leftover in case a downloaderlike wget or curl need to be installed
152+
clean_download https://github.com/devcontainers-extra/nanolayer/releases/download/$required_version/$tar_filename $tmp_dir/$tar_filename
153+
154+
tar xfzv $tmp_dir/$tar_filename -C "$tmp_dir"
155+
chmod a+x $tmp_dir/nanolayer
156+
__nanolayer_location=$tmp_dir/nanolayer
157+
158+
159+
else
160+
echo "No binaries compiled for non-x86-linux architectures yet: $(uname -m)"
161+
exit 1
162+
fi
163+
fi
164+
165+
# Expose outside the resolved location
166+
export ${variable_name}=$__nanolayer_location
167+
168+
}
169+

test/prek/scenarios.json

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
{
2+
"test_defaults_debian": {
3+
"image": "mcr.microsoft.com/devcontainers/base:debian",
4+
"features": {
5+
"prek": {}
6+
}
7+
},
8+
"test_specific_version": {
9+
"image": "mcr.microsoft.com/devcontainers/base:debian",
10+
"features": {
11+
"prek": {
12+
"version": "0.3.6"
13+
}
14+
}
15+
}
16+
}

test/prek/test_defaults_debian.sh

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
#!/usr/bin/env bash
2+
3+
set -e
4+
5+
source dev-container-features-test-lib
6+
7+
check "prek --version" prek --version
8+
9+
reportResults

test/prek/test_specific_version.sh

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
#!/usr/bin/env bash
2+
3+
set -e
4+
5+
source dev-container-features-test-lib
6+
7+
check "prek version is equal to 0.3.6" sh -c "prek --version | grep '0.3.6'"
8+
9+
reportResults

0 commit comments

Comments
 (0)