Unverified Commit 694906e3 authored by Jonathan Backhaus's avatar Jonathan Backhaus Committed by GitHub

Add support for Alpine to `git` feature (#1008)

* feat: add basic scaffolding for alpine, based on debian implementation

* feat: add baseline packages from <https://github.com/alpinelinux/aports/blob/master/main/git/APKBUILD>

* fix: add `curl` package (needed for version lookup)

* feat: use `jq`-based version matching implementation for alpine

the alpine version of `grep` doesn't support PCRE

* fix: forgot to strip the leading "v" from the version number

* fix: need `make` package to build from source

* feat: parameterize make options to easily inject Alpine-specific option

* fix: wip: latest baseline (still breaking due to musl)

* feat: add basic scaffolding for alpine, based on debian implementation

note: this won't install from source (due to build issues with musl) but will install using the `apk` package manager

* chore: chmod +x

* chore: bump semver (proposed)

* docs: add Alpine/apk to notes

* test: add test for `alpine:3` to install system package

note: feature does not currently implement building from source on Alpine

* fix: working build from source!

still need to tweak the package dependencies and make config

* perf: remove OBE `gettext-dev` package from dependencies

no longer required with "NO_GETTEXT=YesPlease" make config

* perf: remove OBE `libintl` package from dependencies

no longer required with "NO_GETTEXT=YesPlease" make config (?)

* feat: add remaining make options from apk package source reference

* docs: add refs. for alpine build from source

* test(git): add test case for building git from src on alpine:3

* fix: lint: SC2068: Double quote array expansions to avoid re-splitting elements

* fix: use Devcontainer Alpine image as base (because it has `bash` installed); refactor test script names to remove major version suffix (since it isn't specified in the associated image tag)

* perf: consolidate to a single, jq-based implementation

using `jq` avoids the need for PCRE `grep` expression (not supported in Alpine)

* fix: set `sysconfdir` option for alpine build as well

see [#395](https://github.com/devcontainers/features/pull/395)

* test: fix: alpine doesn't include perl support; leverage test cases from `install_git_from_src.sh` script

* style: remove unused options

* fix: set `prefix` option for alpine build to be consistent with other builds

see [#395](https://github.com/devcontainers/features/pull/395)

* refactor: move common arguments out of distro-specific logic

* perf: minimum set of make options for building git from source in Alpine

* chore: remove OBE code (unused make options for Git)

* style: whitespace

* test: fix: remove `gettext` check (since this package isn't installed in Alpine)

* feat: update implementation based on local Git feature in `base-alpine` image

* feat: remove `libsecret-dev` package

not present in local Git feature in `base-alpine` image `install.sh` script

* feat: switch `glib-dev` to `g++` and `gcc` packages, based on local Git feature in `base-alpine` image

* chore: remove `alpine-sdk` package, based on local Git feature in `base-alpine` image

no longer needed, based on initial testing

* revert: switch back to `grep`-based PCRE implementation,  based on local Git feature in `base-alpine` image

`jq` package no longer needed

* test: revert: remove test cases (covered by generic `install_git_from_src.sh`)

* test: fix: remove perl check for system package in Alpine (because the system package is not built with PCRE support)

---------
Co-authored-by: 's avatarSamruddhi Khandale <skhandale@microsoft.com>
parent 414d3450
...@@ -2,6 +2,6 @@ ...@@ -2,6 +2,6 @@
## OS Support ## OS Support
This Feature should work on recent versions of Debian/Ubuntu, RedHat Enterprise Linux, Fedora, Alma, and RockyLinux distributions with the `apt`, `yum`, `dnf`, or `microdnf` package manager installed. This Feature should work on recent versions of Alpine, Debian/Ubuntu, RedHat Enterprise Linux, Fedora, Alma, and RockyLinux distributions with the `apk`, `apt`, `yum`, `dnf`, or `microdnf` package manager installed.
`bash` is required to execute the `install.sh` script. `bash` is required to execute the `install.sh` script.
{ {
"id": "git", "id": "git",
"version": "1.2.1", "version": "1.3.0",
"name": "Git (from source)", "name": "Git (from source)",
"documentationURL": "https://github.com/devcontainers/features/tree/main/src/git", "documentationURL": "https://github.com/devcontainers/features/tree/main/src/git",
"description": "Install an up-to-date version of Git, built from source as needed. Useful for when you want the latest and greatest features. Auto-detects latest stable version and installs needed dependencies.", "description": "Install an up-to-date version of Git, built from source as needed. Useful for when you want the latest and greatest features. Auto-detects latest stable version and installs needed dependencies.",
......
...@@ -26,6 +26,8 @@ fi ...@@ -26,6 +26,8 @@ fi
# Get an adjusted ID independent of distro variants # Get an adjusted ID independent of distro variants
if [ "${ID}" = "debian" ] || [ "${ID_LIKE}" = "debian" ]; then if [ "${ID}" = "debian" ] || [ "${ID_LIKE}" = "debian" ]; then
ADJUSTED_ID="debian" ADJUSTED_ID="debian"
elif [ "${ID}" = "alpine" ]; then
ADJUSTED_ID="alpine"
elif [[ "${ID}" = "rhel" || "${ID}" = "fedora" || "${ID}" = "mariner" || "${ID_LIKE}" = *"rhel"* || "${ID_LIKE}" = *"fedora"* || "${ID_LIKE}" = *"mariner"* ]]; then elif [[ "${ID}" = "rhel" || "${ID}" = "fedora" || "${ID}" = "mariner" || "${ID_LIKE}" = *"rhel"* || "${ID_LIKE}" = *"fedora"* || "${ID_LIKE}" = *"mariner"* ]]; then
ADJUSTED_ID="rhel" ADJUSTED_ID="rhel"
VERSION_CODENAME="${ID}{$VERSION_ID}" VERSION_CODENAME="${ID}{$VERSION_ID}"
...@@ -36,6 +38,8 @@ fi ...@@ -36,6 +38,8 @@ fi
if type apt-get > /dev/null 2>&1; then if type apt-get > /dev/null 2>&1; then
INSTALL_CMD=apt-get INSTALL_CMD=apt-get
elif type apk > /dev/null 2>&1; then
INSTALL_CMD=apk
elif type microdnf > /dev/null 2>&1; then elif type microdnf > /dev/null 2>&1; then
INSTALL_CMD=microdnf INSTALL_CMD=microdnf
elif type dnf > /dev/null 2>&1; then elif type dnf > /dev/null 2>&1; then
...@@ -53,6 +57,9 @@ clean_up() { ...@@ -53,6 +57,9 @@ clean_up() {
debian) debian)
rm -rf /var/lib/apt/lists/* rm -rf /var/lib/apt/lists/*
;; ;;
alpine)
rm -rf /var/cache/apk/*
;;
rhel) rhel)
rm -rf /var/cache/dnf/* rm -rf /var/cache/dnf/*
rm -rf /var/cache/yum/* rm -rf /var/cache/yum/*
...@@ -102,6 +109,11 @@ pkg_mgr_update() { ...@@ -102,6 +109,11 @@ pkg_mgr_update() {
echo "Running apt-get update..." echo "Running apt-get update..."
${INSTALL_CMD} update -y ${INSTALL_CMD} update -y
fi fi
elif [ ${INSTALL_CMD} = "apk" ]; then
if [ "$(find /var/cache/apk/* | wc -l)" = "0" ]; then
echo "Running apk update..."
${INSTALL_CMD} update
fi
elif [ ${INSTALL_CMD} = "dnf" ] || [ ${INSTALL_CMD} = "yum" ]; then elif [ ${INSTALL_CMD} = "dnf" ] || [ ${INSTALL_CMD} = "yum" ]; then
if [ "$(find /var/cache/${INSTALL_CMD}/* | wc -l)" = "0" ]; then if [ "$(find /var/cache/${INSTALL_CMD}/* | wc -l)" = "0" ]; then
echo "Running ${INSTALL_CMD} check-update ..." echo "Running ${INSTALL_CMD} check-update ..."
...@@ -118,6 +130,10 @@ check_packages() { ...@@ -118,6 +130,10 @@ check_packages() {
pkg_mgr_update pkg_mgr_update
${INSTALL_CMD} -y install --no-install-recommends "$@" ${INSTALL_CMD} -y install --no-install-recommends "$@"
fi fi
elif [ ${INSTALL_CMD} = "apk" ]; then
${INSTALL_CMD} add \
--no-cache \
"$@"
elif [ ${INSTALL_CMD} = "dnf" ] || [ ${INSTALL_CMD} = "yum" ]; then elif [ ${INSTALL_CMD} = "dnf" ] || [ ${INSTALL_CMD} = "yum" ]; then
_num_pkgs=$(echo "$@" | tr ' ' \\012 | wc -l) _num_pkgs=$(echo "$@" | tr ' ' \\012 | wc -l)
_num_installed=$(${INSTALL_CMD} -C list installed "$@" | sed '1,/^Installed/d' | wc -l) _num_installed=$(${INSTALL_CMD} -C list installed "$@" | sed '1,/^Installed/d' | wc -l)
...@@ -154,6 +170,8 @@ if [ ${GIT_VERSION} = "os-provided" ] || [ ${GIT_VERSION} = "system" ]; then ...@@ -154,6 +170,8 @@ if [ ${GIT_VERSION} = "os-provided" ] || [ ${GIT_VERSION} = "system" ]; then
if [ "$INSTALL_CMD" = "apt-get" ]; then if [ "$INSTALL_CMD" = "apt-get" ]; then
echo "Installing git from OS apt repository" echo "Installing git from OS apt repository"
elif [ "$INSTALL_CMD" = "apk" ]; then
echo "Installing git from OS apk repository"
else else
echo "Installing git from OS yum/dnf repository" echo "Installing git from OS yum/dnf repository"
fi fi
...@@ -194,6 +212,14 @@ if [ "${ADJUSTED_ID}" = "debian" ]; then ...@@ -194,6 +212,14 @@ if [ "${ADJUSTED_ID}" = "debian" ]; then
check_packages libpcre2-posix3 check_packages libpcre2-posix3
fi fi
elif [ "${ADJUSTED_ID}" = "alpine" ]; then
# update build dependencies
${INSTALL_CMD} add --no-cache --update curl grep make zlib-dev
# ref. <https://github.com/alpinelinux/aports/blob/32ac93ffb642031b88ba8639fbb3abb324169dea/main/git/APKBUILD#L62>
check_packages asciidoc curl-dev expat-dev g++ gcc openssl-dev pcre2-dev perl-dev perl-error python3-dev tcl tk xmlto
elif [ "${ADJUSTED_ID}" = "rhel" ]; then elif [ "${ADJUSTED_ID}" = "rhel" ]; then
if [ $VERSION_CODENAME = "centos7" ]; then if [ $VERSION_CODENAME = "centos7" ]; then
...@@ -212,6 +238,10 @@ elif [ "${ADJUSTED_ID}" = "rhel" ]; then ...@@ -212,6 +238,10 @@ elif [ "${ADJUSTED_ID}" = "rhel" ]; then
if [ $ID = "mariner" ]; then if [ $ID = "mariner" ]; then
check_packages glibc-devel kernel-headers binutils check_packages glibc-devel kernel-headers binutils
fi fi
else
echo "Linux distro ${ID} not supported."
exit 1
fi fi
# Partial version matching # Partial version matching
...@@ -235,7 +265,15 @@ echo "Downloading source for ${GIT_VERSION}..." ...@@ -235,7 +265,15 @@ echo "Downloading source for ${GIT_VERSION}..."
curl -sL https://github.com/git/git/archive/v${GIT_VERSION}.tar.gz | tar -xzC /tmp 2>&1 curl -sL https://github.com/git/git/archive/v${GIT_VERSION}.tar.gz | tar -xzC /tmp 2>&1
echo "Building..." echo "Building..."
cd /tmp/git-${GIT_VERSION} cd /tmp/git-${GIT_VERSION}
make -s USE_LIBPCRE=YesPlease prefix=/usr/local sysconfdir=/etc all && make -s USE_LIBPCRE=YesPlease prefix=/usr/local sysconfdir=/etc install 2>&1 git_options=("prefix=/usr/local")
git_options+=("sysconfdir=/etc")
git_options+=("USE_LIBPCRE=YesPlease")
if [ "${ADJUSTED_ID}" = "alpine" ]; then
# ref. <https://github.com/alpinelinux/aports/blob/32ac93ffb642031b88ba8639fbb3abb324169dea/main/git/APKBUILD#L126>
git_options+=("NO_REGEX=YesPlease")
git_options+=("NO_GETTEXT=YesPlease")
fi
make -s "${git_options[@]}" all && make -s "${git_options[@]}" install 2>&1
rm -rf /tmp/git-${GIT_VERSION} rm -rf /tmp/git-${GIT_VERSION}
clean_up clean_up
echo "Done!" echo "Done!"
#!/bin/bash
set -e
# Optional: Import test library
source dev-container-features-test-lib
# Definition specific tests
check "version" git --version
cd /tmp && git clone https://github.com/devcontainers/feature-starter.git
cd feature-starter
check "perl" bash -c "git -c grep.patternType=perl grep -q 'a.+b'"
# Report result
reportResults
#!/bin/bash
set -e
# Optional: Import test library
source dev-container-features-test-lib
# Definition specific tests
check "version" git --version
cd /tmp && git clone https://github.com/devcontainers/feature-starter.git
cd feature-starter
# Report result
reportResults
...@@ -8,6 +8,15 @@ ...@@ -8,6 +8,15 @@
} }
} }
}, },
"install_git_from_src_alpine": {
"image": "mcr.microsoft.com/devcontainers/base:alpine",
"features": {
"git": {
"version": "latest",
"ppa": "false"
}
}
},
"install_git_from_src_jammy": { "install_git_from_src_jammy": {
"image": "ubuntu:jammy", "image": "ubuntu:jammy",
"features": { "features": {
...@@ -107,6 +116,15 @@ ...@@ -107,6 +116,15 @@
} }
} }
}, },
"install_git_from_system_alpine": {
"image": "mcr.microsoft.com/devcontainers/base:alpine",
"features": {
"git": {
"version": "system",
"ppa": "false"
}
}
},
"install_git_from_system_centos-7": { "install_git_from_system_centos-7": {
"image": "centos:centos7", "image": "centos:centos7",
"features": { "features": {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment