Skip to content

Commit d3c2fe8

Browse files
authored
feat(protolint): add protolint feature (#6)
* feat(protolint): add protolint feature * docs(readme): update features
1 parent d33561a commit d3c2fe8

7 files changed

Lines changed: 209 additions & 2 deletions

File tree

README.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,9 @@ Custom features for dev containers used in development of Omoxyz software projec
55
## Features
66

77
- **Lefthook** ([lefthook](./src/lefthook/README.md)) – fast polyglot Git hooks manager to automate code checks, formatting, and tests before commits and pushes.
8-
- **Air** ([go-air](./src/go-air/README.md)) - live reloader for Go apps
9-
- **Protoc** ([protoc](./src/protoc/README.md))
8+
- **Air** ([go-air](./src/go-air/README.md)) - live reloader for Go apps.
9+
- **Protoc** ([protoc](./src/protoc/README.md)) - protocol buffer compiler.
10+
- **Protolint** ([protolint](./src/protolint/README.md)) - linter and fixer to enforce Protocol Buffer style and conventions.
1011

1112
## Usage
1213

src/protolint/NOTES.md

Whitespace-only changes.
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
{
2+
"name": "Protolint",
3+
"id": "protolint",
4+
"version": "1.0.0",
5+
"documentationURL": "http://github.com/omoxyz/devcontainer-features/tree/main/src/protolint",
6+
"description": "Install Protolint linter and fixer to enforce Protocol Buffer style and conventions.",
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/features/git"
19+
]
20+
}

src/protolint/install.sh

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
#!/usr/bin/env bash
2+
3+
if [ "$(id -u)" -ne 0 ]; then
4+
echo -e 'Scripts must be run as root. Use sudo, su, or add "USER root" to your Dockerfile before running this script.'
5+
exit 1
6+
fi
7+
8+
source ./utils.sh
9+
10+
PROTOLINT_VERSION=${VERSION:-"latest"}
11+
GITHUB_REPO=https://github.com/yoheimuta/protolint
12+
13+
# Exit immediately if a command exits with a non-zero status.
14+
set -e
15+
16+
apt_get_update
17+
18+
# Clean up
19+
rm -rf /var/lib/apt/lists/*
20+
21+
export DEBIAN_FRONTEND=noninteractive
22+
23+
get_github_filename() {
24+
local version=$1
25+
local arch=$2
26+
echo "protolint_${version}_linux_${arch}.tar.gz"
27+
}
28+
29+
install_from_github() {
30+
local version_list=$(git ls-remote --tags ${GITHUB_REPO})
31+
32+
# Get 2 latest appropriate versions
33+
versions=($(find_latest_versions $PROTOLINT_VERSION version_list "tags/v"))
34+
if [ $? -eq 1 ]; then
35+
echo "Can't find appropriate version"
36+
exit 1
37+
fi
38+
39+
latest_version=${versions[0]}
40+
prev_version=${versions[1]}
41+
42+
echo "Downloading protolint v${latest_version}...."
43+
44+
check_packages wget
45+
46+
# Get architecture
47+
local arch=$(dpkg --print-architecture)
48+
49+
local filename=$(get_github_filename $latest_version $arch)
50+
51+
set +e
52+
53+
# Create temporary directory
54+
mkdir -p /tmp/protolint
55+
pushd /tmp/protolint
56+
57+
# Download zip file
58+
wget ${GITHUB_REPO}/releases/download/v${latest_version}/${filename}
59+
local exit_code=$?
60+
61+
set -e
62+
63+
if [ "$exit_code" != "0" ]; then
64+
# Handle situation where git tags are ahead of what was is available to actually download
65+
echo "(!) protolint version ${latest_version} failed to download. Attempting to fall back to ${prev_version} to retry..."
66+
filename=$(get_github_filename $prev_version $arch)
67+
wget ${GITHUB_REPO}/releases/download/v${prev_version}/${filename}
68+
fi
69+
70+
tar -xvzf /tmp/protolint/${filename} -C /tmp/protolint
71+
72+
# Install binaries
73+
cp -r /tmp/protolint/protolint /usr/local/bin/protolint
74+
cp -r /tmp/protolint/protoc-gen-protolint /usr/local/bin/protoc-gen-protolint
75+
76+
# Remove temporary directory
77+
popd
78+
rm -rf /tmp/protolint
79+
}
80+
81+
# Install curl, unzip if missing
82+
check_packages curl ca-certificates unzip git
83+
84+
install_from_github
85+
86+
# Clean up
87+
rm -rf /var/lib/apt/lists/*

src/protolint/utils.sh

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
#!/usr/bin/env bash
2+
3+
# Refresh the local package index if no package list entries are stored on the system.
4+
apt_get_update() {
5+
if [ "$(find /var/lib/apt/lists/* | wc -l)" = "0" ]; then
6+
echo "Running apt-get update..."
7+
apt-get update -y
8+
fi
9+
}
10+
11+
# Checks if packages are installed and installs them if not
12+
check_packages() {
13+
for pkg in "$@"; do
14+
# Check if it's a command in PATH
15+
if command -v "$pkg" &> /dev/null; then
16+
echo "[OK] $pkg found in PATH"
17+
continue
18+
fi
19+
20+
# Check if it's a Debian/Ubuntu package installed
21+
if dpkg -s "$pkg" &> /dev/null; then
22+
echo "[OK] $pkg package installed"
23+
continue
24+
fi
25+
26+
# If not found, install package
27+
echo "$pkg not found. Installing..."
28+
apt_get_update
29+
apt-get install -y --no-install-recommends $pkg
30+
31+
done
32+
}
33+
34+
# Find 2 latest versions that appropriate to requested version
35+
find_latest_versions() {
36+
local requested_version=$1
37+
local version_list=${!2}
38+
39+
# Version prefix such as "tags/v"
40+
local prefix_regex=${3:-''}
41+
42+
# Version number part separator such as "." in "1.0.0"
43+
local separator=${4:-"."}
44+
local escaped_separator=${separator//./\\.}
45+
46+
local suffix_regex=${5:-''}
47+
48+
# Format and sort version list
49+
local version_regex="${prefix_regex}\\K[0-9]+(${escaped_separator}[0-9]+){0,2}${suffix_regex}$"
50+
version_list="$(printf "%s\n" "${version_list[@]}" | grep -oP $version_regex| tr -d ' ' | tr $separator '.' | sort -rV)"
51+
52+
if [ "${requested_version}" = "latest" ]; then
53+
echo "$(echo "${version_list}" | head -n 2)"
54+
else
55+
# Try to get latest matching version
56+
57+
set +e
58+
local regex="^"
59+
60+
# Get major version or exit
61+
local major="$(echo "${requested_version}" | grep -oE '^[0-9]+')"
62+
if [ $major != '' ]; then
63+
regex="${regex}${major}"
64+
else
65+
echo "Invalid version \"${requested_version}\". Use \"latest\" or MAJOR[.MINOR][.PATCH]"
66+
return 1
67+
fi
68+
69+
# Get minor number or accept any
70+
local minor="$(echo "${requested_version}" | grep -oP '^[0-9]+\.\K[0-9]+')"
71+
regex="${regex}$([ "$minor" != '' ] && echo "${escaped_separator}${minor}" || echo "(${escaped_separator}[0-9]+)?")"
72+
73+
74+
# Get patch number or accept any
75+
local patch="$(echo "${requested_version}" | grep -oP '^[0-9]+\.[0-9]+\.\K[0-9]+')"
76+
regex="${regex}$([ "$patch" != '' ] && echo "${escaped_separator}${patch}" || echo "(${escaped_separator}[0-9]+)?")"
77+
set -e
78+
79+
echo "$(echo "${version_list}" | grep -E -m 2 "^${regex}$")"
80+
fi
81+
}

test/protolint/scenarios.json

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{
2+
"test": {
3+
"image": "mcr.microsoft.com/devcontainers/base:debian",
4+
"features": {
5+
"protoc": {}
6+
}
7+
}
8+
}

test/protolint/test.sh

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

0 commit comments

Comments
 (0)