Skip to content

Commit c20f583

Browse files
authored
feat(protoc): add protoc feature (#4)
* feat(protoc): add protoc feature * docs(readme): update features list * chore(protoc): fix version number to 1.0.0
1 parent b7012af commit c20f583

7 files changed

Lines changed: 255 additions & 2 deletions

File tree

README.md

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

55
## Features
66

7-
- **Lefthook** (`lefthook`) – fast polyglot Git hooks manager to automate code checks, formatting, and tests before commits and pushes.
8-
- **Air** (`go-air`) - live reloader for Go apps
7+
- **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))
910

1011
## Usage
1112

src/protoc/NOTES.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
## OS Support
2+
3+
This Feature should work on recent versions of Debian/Ubuntu-based distributions with the `apt` package manager installed.
4+
5+
`bash` is required to execute the `install.sh` script.
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
{
2+
"name": "Protoc",
3+
"id": "protoc",
4+
"version": "1.0.0",
5+
"documentationURL": "http://github.com/omoxyz/devcontainer-features/tree/main/src/protoc",
6+
"description": "Install Protoc protocol buffer compiler.",
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/protoc/install.sh

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
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+
PROTOC_VERSION=${VERSION:-"latest"}
11+
INSTALL_DIRECTLY_FROM_GITHUB_RELEASE=${INSTALLDIRECTLYFROMGITHUBRELEASE:-"true"}
12+
GITHUB_REPO=https://github.com/google/protobuf
13+
14+
# Exit immediately if a command exits with a non-zero status.
15+
set -e
16+
17+
apt_get_update
18+
19+
# Clean up
20+
rm -rf /var/lib/apt/lists/*
21+
22+
export DEBIAN_FRONTEND=noninteractive
23+
24+
get_github_filename() {
25+
local version=$1
26+
local arch=$2
27+
echo "protoc-${version}-linux-${arch}.zip"
28+
}
29+
30+
install_from_github() {
31+
local version_list=$(git ls-remote --tags ${GITHUB_REPO})
32+
33+
# Get 2 latest appropriate versions
34+
versions=($(find_latest_versions $PROTOC_VERSION version_list "tags/v"))
35+
if [ $? -eq 1 ]; then
36+
echo "Can't find appropriate version"
37+
exit 1
38+
fi
39+
40+
latest_version=${versions[0]}
41+
prev_version=${versions[1]}
42+
43+
echo "Downloading protoc v${latest_version}...."
44+
45+
check_packages wget
46+
47+
# Get architecture
48+
local arch=$(dpkg --print-architecture)
49+
50+
# Map to generic architecture
51+
case "$arch" in
52+
amd64)
53+
arch="x86_64"
54+
;;
55+
i386)
56+
arch="x86_32"
57+
;;
58+
arm64)
59+
arch="aarch64"
60+
;;
61+
armhf)
62+
arch="arm"
63+
;;
64+
ppc64el)
65+
arch="ppc64le"
66+
;;
67+
s390x)
68+
arch="s390x"
69+
;;
70+
*)
71+
echo "Unknown architecture $arch."
72+
exit 1
73+
;;
74+
esac
75+
76+
local filename=$(get_github_filename $latest_version $arch)
77+
78+
set +e
79+
80+
# Create temporary directory
81+
mkdir -p /tmp/protoc
82+
pushd /tmp/protoc
83+
84+
# Download zip file
85+
wget ${GITHUB_REPO}/releases/download/v${latest_version}/${filename}
86+
local exit_code=$?
87+
88+
set -e
89+
90+
if [ "$exit_code" != "0" ]; then
91+
# Handle situation where git tags are ahead of what was is available to actually download
92+
echo "(!) protoc version ${latest_version} failed to download. Attempting to fall back to ${prev_version} to retry..."
93+
filename=$(get_github_filename $prev_version $arch)
94+
wget ${GITHUB_REPO}/releases/download/v${prev_version}/${filename}
95+
fi
96+
97+
unzip /tmp/protoc/${filename} -d /tmp/protoc
98+
99+
# Install bin/
100+
if [[ -d /tmp/protoc/bin ]]; then
101+
echo "Installing binaries to /usr/local/bin/..."
102+
cp -r /tmp/protoc/bin/* /usr/local/bin/
103+
fi
104+
105+
# Move include/
106+
if [[ -d /tmp/protoc/include ]]; then
107+
echo "Installing headers to /usr/local/include/..."
108+
cp -r /tmp/protoc/include/* /usr/local/include/
109+
fi
110+
111+
# Remove temporary directory
112+
popd
113+
rm -rf /tmp/protoc
114+
}
115+
116+
# Install curl, unzip if missing
117+
check_packages curl ca-certificates unzip git
118+
119+
install_from_github
120+
121+
# Clean up
122+
rm -rf /var/lib/apt/lists/*

src/protoc/utils.sh

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
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+
}
82+
83+
get_apt_versions() {
84+
package="$1"
85+
apt list -a "$package" 2>/dev/null \
86+
| awk -F' ' 'NR>1 {print $2}' \
87+
| sort -rV
88+
}

test/protoc/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/protoc/test.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 "protoc version" protoc --version
8+
9+
reportResults

0 commit comments

Comments
 (0)