Initial Commit

This commit is contained in:
Christian Tosta
2026-08-11 14:46:19 -03:00
commit 33ed3db2ba
13 changed files with 605 additions and 0 deletions
+62
View File
@@ -0,0 +1,62 @@
# SPDX-FileCopyrightText: 2026 Christian Tosta
# SPDX-License-Identifier: GPL-2.0-or-later
# @file .github/workflows/build.yml
# @brief Simplified master workflow using CMake workflows
name: Pyenv Build & Release
on:
push:
tags:
- "v*"
jobs:
release-ci:
runs-on: ubuntu-24.04
outputs:
VERSION: ${{ steps.step_getlatest_tag.outputs.VERSION }}
steps:
- name: Checkout local
uses: actions/checkout@v4
with:
repository: ${{ github.repository }}
sparse-checkout: |
.github/workflows
- name: Install build dependencies
run: sudo apt-get install git -y -qq
- name: Get latest pyenv release tag
id: step_getlatest_tag
run: |
latest_tag=$(git -c 'versionsort.suffix=-' ls-remote --exit-code --refs --sort='version:refname' --tags https://github.com/pyenv/pyenv '*.*' \
| tail --lines=1 | cut --delimiter='/' --fields=3)
test ! -z "$latest_tag" && echo "LATEST_TAG=$latest_tag" >> "$GITHUB_ENV" || exit 1
echo "VERSION=$(echo $latest_tag | sed 's/v//')" >> "$GITHUB_OUTPUT"
- name: Save version
run: echo ${{ steps.step_getlatest_tag.outputs.VERSION }} > VERSION
- name: Upload version
uses: actions/upload-artifact@v4
with:
name: VERSION
path: VERSION
retention-days: 1
debian:
needs: release-ci
uses: ./.github/workflows/targets/debian.yml
with:
containers: "['debian:trixie','debian:bookworm']"
fedora:
needs: release-ci
uses: ./.github/workflows/targets/fedora.yml
with:
containers: "['fedora:44','fedora:45','fedora:latest']"
publish:
needs: [debian, fedora]
uses: ./.github/workflows/release.yml
+34
View File
@@ -0,0 +1,34 @@
# SPDX-FileCopyrightText: 2026 Christian Tosta
# SPDX-License-Identifier: GPL-2.0-or-later
name: Publish release
on: workflow_call
jobs:
publish:
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v4
- name: Get version
uses: actions/download-artifact@v4
with:
name: VERSION
- name: Set version
run: echo "VERSION=$(cat VERSION | xargs)" >> "$GITHUB_ENV"
- name: Download artifacts
uses: actions/download-artifact@v4
with:
pattern: pyenv-*
merge-multiple: true
- name: Release
uses: softprops/action-gh-release@v2
if: startsWith(github.ref, 'refs/tags/')
with:
files: |
*.deb
*.rpm
+38
View File
@@ -0,0 +1,38 @@
# SPDX-FileCopyrightText: 2026 Christian Tosta
# SPDX-License-Identifier: GPL-2.0-or-later
# @file .github/workflows/targets/debian.yml
# @brief Simplified Debian build target using workflow preset
name: Debian Build Target
on:
workflow_call:
inputs:
containers:
required: true
type: string
jobs:
build-deb:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
container: ${{ fromJson(inputs.containers) }}
container:
image: ${{ matrix.container }}
steps:
- name: Checkout Repository
uses: actions/checkout@v4
- name: Install Dependencies
run: apt-get update && apt-get install -y cmake build-essential git dpkg-dev fakeroot
- name: Run CMake Workflow
run: cmake --workflow --preset deb-workflow
- name: Upload Artifacts
uses: actions/upload-artifact@v4
with:
name: pyenv-deb-${{ matrix.container }}
path: build/deb/*.deb
+34
View File
@@ -0,0 +1,34 @@
# SPDX-FileCopyrightText: 2026 Christian Tosta
# SPDX-License-Identifier: GPL-2.0-or-later
# @file .github/workflows/targets/fedora.yml
# @brief Fedora build target with internal container matrix
name: Fedora Build Target
on:
workflow_call:
jobs:
build-rpm:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
container: [fedora:42, fedora:43, fedora:latest]
container:
image: ${{ matrix.container }}
steps:
- name: Checkout Repository
uses: actions/checkout@v4
- name: Install Dependencies
run: dnf install -y cmake gcc-c++ make git rpm-build
- name: Run CMake Workflow
run: cmake --workflow --preset rpm-workflow
- name: Upload Artifacts
uses: actions/upload-artifact@v4
with:
name: pyenv-rpm-${{ matrix.container }}
path: build/rpm/*.rpm
+37
View File
@@ -0,0 +1,37 @@
.agignore
/bats
/bats-*/
bin/
build/
/cache
CHANGELOG.md
COMMANDS.md
completions/
CONDUCT.md
CONTRIBUTING.md
/default-packages
.dockerignore
.editorconfig
.idea
install_local_python.gif
libexec/
/libexec/*.dylib
LICENSE.pyenv.md
MAINTENANCE.md
Makefile
man/
plugins/
pyenv/
pyenv.d/
README.pyenv.md
/shims
/sources
src/
/src/Makefile
/src/*.o
terminal_output.png
test/
*.un~
/version
/versions
.vimrc
+47
View File
@@ -0,0 +1,47 @@
# SPDX-FileCopyrightText: 2026 Christian Tosta
# SPDX-License-Identifier: GPL-2.0-or-later
#
# @file CMakeLists.txt
# @brief Main CMake configuration for multi-distribution pyenv packaging.
cmake_minimum_required(VERSION 3.24)
project(pyenv-packaging NONE)
file(READ "${CMAKE_CURRENT_SOURCE_DIR}/metadata.json" METADATA_JSON)
string(JSON PYENV_VERSION GET ${METADATA_JSON} "version")
string(JSON PYENV_URL GET ${METADATA_JSON} "source_url")
string(REPLACE "\${self.version}" "${PYENV_VERSION}" PYENV_URL "${PYENV_URL}")
include(ExternalProject)
ExternalProject_Add(pyenv_upstream
URL ${PYENV_URL}
DOWNLOAD_EXTRACT_TIMESTAMP TRUE
CONFIGURE_COMMAND ""
BUILD_COMMAND ""
INSTALL_COMMAND ""
PATCH_COMMAND sh -c "find <SOURCE_DIR> \\( -name .git\\* \\) -exec rm -rf {} +"
)
set(PYENV_SRC_UPSTREAM "${CMAKE_CURRENT_BINARY_DIR}/pyenv_upstream-prefix/src/pyenv_upstream")
set(PYENV_SRC "${CMAKE_CURRENT_SOURCE_DIR}/pyenv")
add_custom_target(merge_upstream ALL
COMMAND ${CMAKE_COMMAND} -E copy_directory "${PYENV_SRC_UPSTREAM}" "${PYENV_SRC}"
DEPENDS pyenv_upstream
)
include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/CPackRules.cmake)
install(DIRECTORY ${PYENV_SRC}/bin ${PYENV_SRC}/libexec ${PYENV_SRC}/plugins ${PYENV_SRC}/pyenv.d
DESTINATION ${PACKAGE_PREFIX}/share/pyenv)
install(DIRECTORY ${PYENV_SRC}/man DESTINATION ${PACKAGE_PREFIX}/share)
install(CODE "file(MAKE_DIRECTORY \"\$ENV{DESTDIR}${PACKAGE_PREFIX}/share/pyenv/versions\")")
install(CODE "file(MAKE_DIRECTORY \"\$ENV{DESTDIR}${PACKAGE_PREFIX}/share/pyenv/shims\")")
install(CODE "file(MAKE_DIRECTORY \"\$ENV{DESTDIR}${PACKAGE_PREFIX}/share/pyenv/hooks\")")
install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/pyenv.sh"
DESTINATION /etc/profile.d
PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ)
+88
View File
@@ -0,0 +1,88 @@
{
"version": 6,
"cmakeMinimumRequired": {
"major": 3,
"minor": 24
},
"configurePresets": [
{
"name": "deb-config",
"displayName": "Debian / Ubuntu Build",
"binaryDir": "${sourceDir}/build/deb",
"cacheVariables": {
"BUILD_DEB": "ON",
"BUILD_RPM": "OFF",
"CMAKE_INSTALL_PREFIX": "/usr"
}
},
{
"name": "rpm-config",
"displayName": "Fedora / RPM Build",
"binaryDir": "${sourceDir}/build/rpm",
"cacheVariables": {
"BUILD_DEB": "OFF",
"BUILD_RPM": "ON",
"CMAKE_INSTALL_PREFIX": "/usr"
}
},
{
"name": "act-config",
"displayName": "Local Containerized Build (act)",
"binaryDir": "${sourceDir}/build/act",
"cacheVariables": {
"USE_ACT_CONTAINER": "ON",
"BUILD_DEB": "ON"
}
}
],
"buildPresets": [
{
"name": "deb-build",
"configurePreset": "deb-config"
},
{
"name": "rpm-build",
"configurePreset": "rpm-config"
},
{
"name": "rpm-rebuild",
"configurePreset": "rpm-config",
"targets": [ "rpm-rebuild" ]
},
{
"name": "act-build",
"configurePreset": "act-config",
"targets": ["act-build"]
}
],
"packagePresets": [
{
"name": "deb-package",
"configurePreset": "deb-config"
},
{
"name": "srpm-package",
"configurePreset": "rpm-config",
"configFile": "CPackSourceConfig.cmake",
"generators": ["RPM"]
}
],
"workflowPresets": [
{
"name": "deb-workflow",
"steps": [
{ "type": "configure", "name": "deb-config" },
{ "type": "build", "name": "deb-build" },
{ "type": "package", "name": "deb-package" }
]
},
{
"name": "rpm-workflow",
"steps": [
{ "type": "configure", "name": "rpm-config" },
{ "type": "build", "name": "rpm-build" },
{ "type": "package", "name": "srpm-package" }
]
}
]
}
+20
View File
@@ -0,0 +1,20 @@
# SPDX-FileCopyrightText: 2026 Christian Tosta
# SPDX-License-Identifier: GPL-2.0-or-later
# @file cmake/ActBuilder.cmake
# @brief Helper module to orchestrate local builds via act containerization
option(USE_ACT_CONTAINER "Enable local containerized build via act" OFF)
find_program(ACT_EXECUTABLE act)
if(ACT_EXECUTABLE)
message(STATUS "Found act utility: ${ACT_EXECUTABLE}")
add_custom_target(act-build
COMMAND ${ACT_EXECUTABLE} push --container-architecture linux/amd64
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
COMMENT "Running local CI pipeline using act..."
)
else()
message(WARNING "The 'act' utility was not found. Local containerized builds via act-build target will be unavailable.")
endif()
+29
View File
@@ -0,0 +1,29 @@
# This file will be configured to contain variables for CPack. These variables
# should be set in the CMake list file of the project before CPack module is
# included. Example variables are:
# CPACK_GENERATOR - Generator used to create package
# CPACK_INSTALL_CMAKE_PROJECTS - For each project (path, name, component)
# CPACK_CMAKE_GENERATOR - CMake Generator used for the projects
# CPACK_INSTALL_COMMANDS - Extra commands to install components
# CPACK_INSTALL_DIRECTORIES - Extra directories to install
# CPACK_PACKAGE_DESCRIPTION_FILE - Description file for the package
# CPACK_PACKAGE_DESCRIPTION_SUMMARY - Summary of the package
# CPACK_PACKAGE_EXECUTABLES - List of pairs of executables and labels
# CPACK_PACKAGE_FILE_NAME - Name of the package generated
# CPACK_PACKAGE_ICON - Icon used for the package
# CPACK_PACKAGE_INSTALL_DIRECTORY - Name of directory for the installer
# CPACK_PACKAGE_NAME - Package project name
# CPACK_PACKAGE_VENDOR - Package project vendor
# CPACK_PACKAGE_VERSION - Package project version
# CPACK_PACKAGE_VERSION_MAJOR - Package project version (major)
# CPACK_PACKAGE_VERSION_MINOR - Package project version (minor)
# CPACK_PACKAGE_VERSION_PATCH - Package project version (patch)
# There are certain generator specific ones
# NSIS Generator:
# CPACK_PACKAGE_INSTALL_REGISTRY_KEY - Name of the registry key for the installer
# CPACK_NSIS_EXTRA_UNINSTALL_COMMANDS - Extra commands used during uninstall
# CPACK_NSIS_EXTRA_INSTALL_COMMANDS - Extra commands used during install
@_CPACK_OTHER_VARIABLES_@
+79
View File
@@ -0,0 +1,79 @@
# SPDX-FileCopyrightText: 2026 Christian Tosta
# SPDX-License-Identifier: GPL-2.0-or-later
# @file targets/debian/cmake/CPackRules.cmake
# @brief Centralized CPack packaging rules for DEB and RPM
option(BUILD_DEB "Build DEB package" OFF)
option(BUILD_RPM "Build RPM package" OFF)
set(CPACK_SOURCE_IGNORE_FILES
"/.gitea$"
"/.gitignore$"
"/.git/"
"/[.]agignore$"
"/[.]dockerignore$"
"/[.]editorconfig$"
"/[.]gitea/"
"/[.]github/"
"/[.]vimrc$"
"/build/"
"/Makefile$"
"pkg\\.spec\\.in$"
"~$|\\.swp$"
)
set(CPACK_IGNORE_FILES "${CPACK_SOURCE_IGNORE_FILES}")
if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/cmake/ActBuilder.cmake")
include(cmake/ActBuilder.cmake)
endif()
file(READ "${CMAKE_CURRENT_SOURCE_DIR}/metadata.json" METADATA_JSON)
string(JSON CPACK_PACKAGE_NAME GET ${METADATA_JSON} "name")
string(JSON CPACK_PACKAGE_VERSION GET ${METADATA_JSON} "version")
string(JSON CPACK_PACKAGE_RELEASE GET ${METADATA_JSON} "release")
string(JSON CPACK_PACKAGE_VENDOR GET ${METADATA_JSON} "maintainer")
set(CPACK_VERBATIM_VARIABLES YES)
if(CPACK_PACKAGING_INSTALL_PREFIX AND NOT CPACK_PACKAGING_INSTALL_PREFIX STREQUAL "/")
set(PACKAGE_PREFIX "${CPACK_PACKAGING_INSTALL_PREFIX}")
elseif(CMAKE_INSTALL_PREFIX AND NOT CMAKE_INSTALL_PREFIX STREQUAL "/")
set(PACKAGE_PREFIX "${CMAKE_INSTALL_PREFIX}")
else()
set(PACKAGE_PREFIX "/usr/local")
endif()
set(CPACK_PACKAGING_INSTALL_PREFIX "${PACKAGE_PREFIX}")
set(CPACK_SET_DESTDIR ON)
set(CPACK_PACKAGE_RELOCATABLE "OFF")
if(BUILD_RPM)
set(CPACK_RPM_FILE_NAME "RPM-DEFAULT")
set(CPACK_SOURCE_PACKAGE_FILE_NAME "${CPACK_PACKAGE_NAME}-${CPACK_PACKAGE_VERSION}")
set(CPACK_RPM_USER_BINARY_SPECFILE "${CMAKE_BINARY_DIR}/${CPACK_PACKAGE_NAME}.spec")
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/pkg.spec.in"
"${CPACK_RPM_USER_BINARY_SPECFILE}"
@ONLY
IMMEDIATE
)
elseif(BUILD_DEB)
set(CPACK_GENERATOR "DEB")
string(JSON CPACK_DEBIAN_PACKAGE_MAINTAINER GET ${METADATA_JSON} "maintainer")
string(JSON CPACK_DEBIAN_PACKAGE_ARCHITECTURE GET ${METADATA_JSON} "architecture")
# Build and runtime dependencies
string(JSON DEPENDS_LEN LENGTH ${METADATA_JSON} "deb-depends")
set(CPACK_DEBIAN_PACKAGE_DEPENDS "")
math(EXPR DEPENDS_MAX "${DEPENDS_LEN} - 1")
foreach(i RANGE 0 ${DEPENDS_MAX})
string(JSON DEP GET ${METADATA_JSON} "deb-depends" ${i})
list(APPEND CPACK_DEBIAN_PACKAGE_DEPENDS ${DEP})
endforeach()
list(JOIN CPACK_DEBIAN_PACKAGE_DEPENDS ", " CPACK_DEBIAN_PACKAGE_DEPENDS)
set(CPACK_PACKAGE_FILE_NAME "${CPACK_PACKAGE_NAME}_${CPACK_PACKAGE_VERSION}_${CPACK_DEBIAN_PACKAGE_ARCHITECTURE}")
set(CPACK_DEBIAN_PACKAGE_SHLIBDEPS ON)
set(CPACK_COMPONENTS_ALL_GROUPS_IN_ONE_PACKAGE ON)
endif()
include(CPack)
+20
View File
@@ -0,0 +1,20 @@
{
"name": "pyenv",
"version": "2.8.3",
"release": "1",
"maintainer": "Christian Tosta <no-reply@ekaaty.com>",
"architecture": "all",
"source_url": "https://github.com/pyenv/pyenv/archive/refs/tags/v${self.version}.tar.gz",
"deb-depends": [
"bash",
"git",
"build-essential",
"libssl-dev",
"zlib1g-dev",
"libbz2-dev",
"libreadline-dev",
"libsqlite3-dev",
"libffi-dev",
"liblzma-dev"
]
}
+77
View File
@@ -0,0 +1,77 @@
# SPDX-FileCopyrightText: 2026 Christian Tosta
# SPDX-License-Identifier: GPL-2.0-or-later
%global plugins ccache virtualenv pip-migrate
%global _prefix @PACKAGE_PREFIX@
Name: @CPACK_PACKAGE_NAME@
Version: @CPACK_PACKAGE_VERSION@
Release: @CPACK_PACKAGE_RELEASE@%{?dist}
Summary: Simple Python version management
License: MIT
URL: https://github.com/pyenv/pyenv
Source0: %{url}/archive/refs/tags/v%{version}.tar.gz#/%{name}-%{version}.tar.gz
BuildArch: noarch
BuildRequires: git
Requires: bash
Requires: git
Requires: gcc
Requires: make
Requires: openssl-devel
Requires: bzip2-devel
Requires: readline-devel
Requires: sqlite-devel
Requires: libffi-devel
Requires: xz-devel
Requires: tk-devel
Requires: gdbm-devel
Requires: ncurses-devel
Requires: zlib-devel
Requires: libuuid-devel
%description
pyenv lets you easily switch between multiple versions of Python. It's simple,
unobtrusive, and follows the UNIX tradition of single-purpose tools that do one
thing well.
%prep
%setup -q -n %{name}-%{version}
%build
set +x
for plugin in %{plugins}; do
echo -n "Cloning plugin [${plugin}]... "
git clone -q https://github.com/pyenv/pyenv-${plugin} plugins/${plugin}
echo "done."
done
set -x
%install
rm -rf %{buildroot}
mkdir -p %{buildroot}%{_datadir}/%{name}/{versions,shims,hooks}
mkdir -p %{buildroot}%{_sysconfdir}/profile.d
pushd pyenv
cp -r bin libexec plugins pyenv.d %{buildroot}%{_datadir}/%{name}/
cp -r man %{buildroot}%{_datadir}
popd
install -p -m 0644 pyenv.sh %{buildroot}%{_sysconfdir}/profile.d/pyenv.sh
%files
%defattr(-,root,root,-)
%license pyenv/LICENSE
%doc pyenv/README.md pyenv/CHANGELOG.md
%{_sysconfdir}/profile.d/pyenv.sh
%{_mandir}/man1/*.1*
%{_datadir}/%{name}/
%changelog
* Thu Jun 18 2026 Ekaaty Build Service <noreply@ekaaty.com> - @CPACK_PACKAGE_VERSION@-@CPACK_PACKAGE_RELEASE@
- Initial RPM package release for enterprise multi-user environments.
- Added pyenv.sh into /etc/profile.d/ for automated initialization.
+40
View File
@@ -0,0 +1,40 @@
# ==============================================================================
# /etc/profile.d/pyenv.sh
# Global Pyenv Configuration for Multi-User Enterprise Environment
# ==============================================================================
# Add the globally compiled Pyenv core binaries to the system PATH
export PATH="/opt/pyenv/bin:$PATH"
# Isolate the Pyenv execution root to the current user's HOME directory
# This ensures that 'pyenv rehash' and shim generation have native write permissions
export PYENV_ROOT="$HOME/.pyenv"
# Bootstrap required directory structure inside the user's HOME if missing
if [ ! -d "$PYENV_ROOT/versions" ]; then
mkdir -p "$PYENV_ROOT/versions" "$PYENV_ROOT/shims"
fi
# Define the hook path required by Pyenv architecture plugins
export PYENV_HOOK_PATH="/opt/pyenv/hooks"
# SELF-HEALING: Detect and forcefully purge broken/orphaned symbolic links
# This prevents shell errors if an administrator uninstalls a global Python version
find "$PYENV_ROOT/versions/" -xtype l -delete 2>/dev/null
# SYNCHRONIZATION: Map globally available Python installations into the user's scope
# Individual symlinks are used so the user's Pyenv can correctly resolve each version
find /opt/pyenv/versions/ -type d -name '[23]*' | \
while read path; do
version=$(basename $path);
mkdir -p "$PYENV_ROOT/versions/$version/envs" 2>/dev/null
if [ -d "$PYENV_ROOT/versions/$version" ]; then
ln -snf /opt/pyenv/versions/$version/* \
"$PYENV_ROOT/versions/$version/" 2>/dev/null;
fi
done
# INITIALIZATION: Spawn the Pyenv environment and virtualenv managers
# into the shell session
eval "$(pyenv init -)"
eval "$(pyenv virtualenv-init -)"