diff --git a/.gitea/upstream-codex-release.txt b/.gitea/upstream-codex-release.txt new file mode 100644 index 0000000..1fd5602 --- /dev/null +++ b/.gitea/upstream-codex-release.txt @@ -0,0 +1 @@ +rust-v0.125.0 diff --git a/.gitea/workflows/rebuild-copr-on-upstream-release.yml b/.gitea/workflows/rebuild-copr-on-upstream-release.yml new file mode 100644 index 0000000..1764c7c --- /dev/null +++ b/.gitea/workflows/rebuild-copr-on-upstream-release.yml @@ -0,0 +1,148 @@ +name: Rebuild COPR on upstream Codex release + +on: + schedule: + - cron: "15 0 * * *" + workflow_dispatch: + inputs: + force: + description: "Trigger the COPR webhook even if the upstream tag is unchanged" + required: false + type: boolean + default: false + +permissions: + contents: write + +concurrency: + group: rebuild-copr-on-upstream-release + cancel-in-progress: false + +jobs: + rebuild: + name: Trigger COPR rebuild + runs-on: ubuntu-latest + env: + UPSTREAM_REPO: openai/codex + STATE_FILE: .github/upstream-codex-release.txt + FORCE_REBUILD: ${{ github.event_name == 'workflow_dispatch' && inputs.force }} + + steps: + - name: Check out packaging repository + uses: actions/checkout@v4 + + - name: Resolve latest upstream release + id: upstream + env: + GH_TOKEN: ${{ github.token }} + run: | + set -euo pipefail + + release_json="$( + curl -fsSL \ + -H "Accept: application/vnd.github+json" \ + -H "Authorization: Bearer ${GH_TOKEN}" \ + -H "X-GitHub-Api-Version: 2022-11-28" \ + "https://api.github.com/repos/${UPSTREAM_REPO}/releases/latest" + )" + + latest_tag="$(jq -r '.tag_name // empty' <<<"${release_json}")" + release_url="$(jq -r '.html_url // empty' <<<"${release_json}")" + is_draft="$(jq -r '.draft // false' <<<"${release_json}")" + + if [[ -z "${latest_tag}" ]]; then + echo "Could not determine latest upstream release tag." >&2 + exit 1 + fi + + if [[ "${is_draft}" == "true" ]]; then + echo "Latest upstream release ${latest_tag} is still a draft." >&2 + exit 1 + fi + + echo "latest_tag=${latest_tag}" >> "${GITHUB_OUTPUT}" + echo "release_url=${release_url}" >> "${GITHUB_OUTPUT}" + + - name: Decide whether rebuild is needed + id: decision + run: | + set -euo pipefail + + latest_tag="${{ steps.upstream.outputs.latest_tag }}" + previous_tag="" + if [[ -f "${STATE_FILE}" ]]; then + previous_tag="$(tr -d '[:space:]' < "${STATE_FILE}")" + fi + + if [[ "${FORCE_REBUILD}" == "true" || "${latest_tag}" != "${previous_tag}" ]]; then + echo "rebuild=true" >> "${GITHUB_OUTPUT}" + else + echo "rebuild=false" >> "${GITHUB_OUTPUT}" + fi + + echo "previous_tag=${previous_tag}" >> "${GITHUB_OUTPUT}" + echo "Latest upstream tag: ${latest_tag}" + echo "Previously recorded tag: ${previous_tag:-}" + + - name: Trigger COPR package webhook + if: steps.decision.outputs.rebuild == 'true' + env: + COPR_WEBHOOK_URL: ${{ secrets.COPR_CODEX_WEBHOOK_URL }} + run: | + set -euo pipefail + + webhook_url="$(printf '%s' "${COPR_WEBHOOK_URL}" | tr -d '\r\n')" + webhook_url="$(sed -E 's/^[[:space:]]+//; s/[[:space:]]+$//' <<<"${webhook_url}")" + + if [[ -z "${webhook_url}" ]]; then + echo "Missing COPR_CODEX_WEBHOOK_URL secret." >&2 + echo "Set it to the package-specific COPR custom webhook URL ending in /codex/." >&2 + exit 1 + fi + + if [[ ! "${webhook_url}" =~ ^https://[^[:space:]]+$ ]]; then + echo "COPR_CODEX_WEBHOOK_URL is not a valid URL after trimming whitespace." >&2 + echo "Expected format: https://copr.fedorainfracloud.org/webhooks/custom/.../codex/" >&2 + exit 1 + fi + + payload="$( + jq -n \ + --arg upstream_repository "${UPSTREAM_REPO}" \ + --arg tag "${{ steps.upstream.outputs.latest_tag }}" \ + --arg release_url "${{ steps.upstream.outputs.release_url }}" \ + --arg package_name "codex" \ + '{ + object_kind: "release", + upstream_repository: $upstream_repository, + tag_name: $tag, + release_url: $release_url, + package_name: $package_name + }' + )" + + curl -fsS \ + -X POST \ + -H "Content-Type: application/json" \ + --data "${payload}" \ + "${webhook_url}" + + - name: Record processed upstream tag + if: steps.decision.outputs.rebuild == 'true' + run: | + set -euo pipefail + + mkdir -p "$(dirname "${STATE_FILE}")" + printf '%s\n' "${{ steps.upstream.outputs.latest_tag }}" > "${STATE_FILE}" + + git config user.name "github-actions[bot]" + git config user.email "41898282+github-actions[bot]@users.noreply.github.com" + git add "${STATE_FILE}" + + if git diff --cached --quiet; then + echo "State file is already current." + exit 0 + fi + + git commit -m "Track upstream Codex ${{ steps.upstream.outputs.latest_tag }}" + git push diff --git a/.gitea/workflows/update-readme-version.yaml b/.gitea/workflows/update-readme-version.yaml new file mode 100644 index 0000000..16d8217 --- /dev/null +++ b/.gitea/workflows/update-readme-version.yaml @@ -0,0 +1,105 @@ +name: Update README version + +on: + push: + branches: + - master + schedule: + - cron: "17 2 * * *" + workflow_dispatch: + +permissions: + contents: write + +jobs: + update-readme-version: + runs-on: ubuntu-latest + env: + COPR_WEBHOOK_URL: ${{ secrets.COPR_WEBHOOK_URL }} + TARBALL_URL_AARCH64: https://packages.element.io/desktop/install/linux/glibc-aarch64/element-desktop.tar.gz + TARBALL_URL_X86_64: https://packages.element.io/desktop/install/linux/glibc-x86-64/element-desktop.tar.gz + steps: + - name: Check out repository + uses: actions/checkout@v4 + with: + token: ${{ secrets.GITEA_TOKEN }} + fetch-depth: 0 + ref: ${{ gitea.ref_name }} + + - name: Detect latest upstream version + id: version + shell: bash + run: | + set -euo pipefail + + topdir_x86_64="$(curl -fsSL "$TARBALL_URL_X86_64" | tar -tzf - | sed -n '1s#/##p')" + topdir_aarch64="$(curl -fsSL "$TARBALL_URL_AARCH64" | tar -tzf - | sed -n '1s#/##p')" + + latest_version_x86_64="${topdir_x86_64#element-desktop-}" + latest_version_aarch64="${topdir_aarch64#element-desktop-}" + latest_version_aarch64="${latest_version_aarch64%-arm64}" + current_version="$(sed -n 's/^Latest upstream version tracked in this repo: `\([^`]*\)`$/\1/p' README.md)" + + if [ -z "$latest_version_x86_64" ] || [ "$latest_version_x86_64" = "$topdir_x86_64" ]; then + echo "Failed to derive upstream x86_64 version from tarball root: $topdir_x86_64" >&2 + exit 1 + fi + + if [ -z "$latest_version_aarch64" ] || [ "$latest_version_aarch64" = "$topdir_aarch64" ]; then + echo "Failed to derive upstream aarch64 version from tarball root: $topdir_aarch64" >&2 + exit 1 + fi + + if [ -z "$current_version" ]; then + echo "Could not find tracked version marker in README.md" >&2 + exit 1 + fi + + if [ "$latest_version_x86_64" != "$latest_version_aarch64" ]; then + echo "Upstream version mismatch: x86_64=$latest_version_x86_64 aarch64=$latest_version_aarch64" >&2 + exit 1 + fi + + echo "latest=$latest_version_x86_64" >> "$GITHUB_OUTPUT" + echo "current=$current_version" >> "$GITHUB_OUTPUT" + + - name: Update README + if: steps.version.outputs.latest != steps.version.outputs.current + shell: bash + run: | + set -euo pipefail + + sed -i \ + "s/^Latest upstream version tracked in this repo: .*/Latest upstream version tracked in this repo: \`${{ steps.version.outputs.latest }}\`/" \ + README.md + + - name: Commit and push update + id: commit + if: steps.version.outputs.latest != steps.version.outputs.current + shell: bash + run: | + set -euo pipefail + + git config user.name "Gitea Actions" + git config user.email "actions@localhost" + git add README.md + git commit -m "docs: update tracked Element Desktop version to ${{ steps.version.outputs.latest }}" + git push + echo "pushed=true" >> "$GITHUB_OUTPUT" + + - name: Trigger COPR build + if: gitea.event_name == 'push' && steps.commit.outputs.pushed != 'true' + shell: bash + run: | + set -euo pipefail + + if [ -z "${COPR_WEBHOOK_URL:-}" ]; then + echo "COPR_WEBHOOK_URL secret is not set" >&2 + exit 1 + fi + + curl --fail --show-error --silent \ + --retry 3 \ + --retry-all-errors \ + -X POST \ + "$COPR_WEBHOOK_URL" diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..3b82785 --- /dev/null +++ b/.gitignore @@ -0,0 +1,7 @@ +*.tar.gz +*.rpm +results*/ +.rpmbuild/ +.idea/ +*.iml +*.xml \ No newline at end of file diff --git a/codex/.copr/Makefile b/codex/.copr/Makefile new file mode 100644 index 0000000..854ae9d --- /dev/null +++ b/codex/.copr/Makefile @@ -0,0 +1,9 @@ +.PHONY: srpm + +outdir ?= $(CURDIR)/.rpmbuild/SRPMS +TOPDIR ?= $(CURDIR)/.rpmbuild + +srpm: + $(MAKE) -C "$(CURDIR)" srpm TOPDIR="$(TOPDIR)" + mkdir -p "$(outdir)" + cp "$(TOPDIR)"/SRPMS/*.src.rpm "$(outdir)"/ diff --git a/codex/.github/upstream-codex-release.txt b/codex/.github/upstream-codex-release.txt new file mode 100644 index 0000000..1fd5602 --- /dev/null +++ b/codex/.github/upstream-codex-release.txt @@ -0,0 +1 @@ +rust-v0.125.0 diff --git a/codex/.github/workflows/rebuild-copr-on-upstream-release.yml b/codex/.github/workflows/rebuild-copr-on-upstream-release.yml new file mode 100644 index 0000000..1764c7c --- /dev/null +++ b/codex/.github/workflows/rebuild-copr-on-upstream-release.yml @@ -0,0 +1,148 @@ +name: Rebuild COPR on upstream Codex release + +on: + schedule: + - cron: "15 0 * * *" + workflow_dispatch: + inputs: + force: + description: "Trigger the COPR webhook even if the upstream tag is unchanged" + required: false + type: boolean + default: false + +permissions: + contents: write + +concurrency: + group: rebuild-copr-on-upstream-release + cancel-in-progress: false + +jobs: + rebuild: + name: Trigger COPR rebuild + runs-on: ubuntu-latest + env: + UPSTREAM_REPO: openai/codex + STATE_FILE: .github/upstream-codex-release.txt + FORCE_REBUILD: ${{ github.event_name == 'workflow_dispatch' && inputs.force }} + + steps: + - name: Check out packaging repository + uses: actions/checkout@v4 + + - name: Resolve latest upstream release + id: upstream + env: + GH_TOKEN: ${{ github.token }} + run: | + set -euo pipefail + + release_json="$( + curl -fsSL \ + -H "Accept: application/vnd.github+json" \ + -H "Authorization: Bearer ${GH_TOKEN}" \ + -H "X-GitHub-Api-Version: 2022-11-28" \ + "https://api.github.com/repos/${UPSTREAM_REPO}/releases/latest" + )" + + latest_tag="$(jq -r '.tag_name // empty' <<<"${release_json}")" + release_url="$(jq -r '.html_url // empty' <<<"${release_json}")" + is_draft="$(jq -r '.draft // false' <<<"${release_json}")" + + if [[ -z "${latest_tag}" ]]; then + echo "Could not determine latest upstream release tag." >&2 + exit 1 + fi + + if [[ "${is_draft}" == "true" ]]; then + echo "Latest upstream release ${latest_tag} is still a draft." >&2 + exit 1 + fi + + echo "latest_tag=${latest_tag}" >> "${GITHUB_OUTPUT}" + echo "release_url=${release_url}" >> "${GITHUB_OUTPUT}" + + - name: Decide whether rebuild is needed + id: decision + run: | + set -euo pipefail + + latest_tag="${{ steps.upstream.outputs.latest_tag }}" + previous_tag="" + if [[ -f "${STATE_FILE}" ]]; then + previous_tag="$(tr -d '[:space:]' < "${STATE_FILE}")" + fi + + if [[ "${FORCE_REBUILD}" == "true" || "${latest_tag}" != "${previous_tag}" ]]; then + echo "rebuild=true" >> "${GITHUB_OUTPUT}" + else + echo "rebuild=false" >> "${GITHUB_OUTPUT}" + fi + + echo "previous_tag=${previous_tag}" >> "${GITHUB_OUTPUT}" + echo "Latest upstream tag: ${latest_tag}" + echo "Previously recorded tag: ${previous_tag:-}" + + - name: Trigger COPR package webhook + if: steps.decision.outputs.rebuild == 'true' + env: + COPR_WEBHOOK_URL: ${{ secrets.COPR_CODEX_WEBHOOK_URL }} + run: | + set -euo pipefail + + webhook_url="$(printf '%s' "${COPR_WEBHOOK_URL}" | tr -d '\r\n')" + webhook_url="$(sed -E 's/^[[:space:]]+//; s/[[:space:]]+$//' <<<"${webhook_url}")" + + if [[ -z "${webhook_url}" ]]; then + echo "Missing COPR_CODEX_WEBHOOK_URL secret." >&2 + echo "Set it to the package-specific COPR custom webhook URL ending in /codex/." >&2 + exit 1 + fi + + if [[ ! "${webhook_url}" =~ ^https://[^[:space:]]+$ ]]; then + echo "COPR_CODEX_WEBHOOK_URL is not a valid URL after trimming whitespace." >&2 + echo "Expected format: https://copr.fedorainfracloud.org/webhooks/custom/.../codex/" >&2 + exit 1 + fi + + payload="$( + jq -n \ + --arg upstream_repository "${UPSTREAM_REPO}" \ + --arg tag "${{ steps.upstream.outputs.latest_tag }}" \ + --arg release_url "${{ steps.upstream.outputs.release_url }}" \ + --arg package_name "codex" \ + '{ + object_kind: "release", + upstream_repository: $upstream_repository, + tag_name: $tag, + release_url: $release_url, + package_name: $package_name + }' + )" + + curl -fsS \ + -X POST \ + -H "Content-Type: application/json" \ + --data "${payload}" \ + "${webhook_url}" + + - name: Record processed upstream tag + if: steps.decision.outputs.rebuild == 'true' + run: | + set -euo pipefail + + mkdir -p "$(dirname "${STATE_FILE}")" + printf '%s\n' "${{ steps.upstream.outputs.latest_tag }}" > "${STATE_FILE}" + + git config user.name "github-actions[bot]" + git config user.email "41898282+github-actions[bot]@users.noreply.github.com" + git add "${STATE_FILE}" + + if git diff --cached --quiet; then + echo "State file is already current." + exit 0 + fi + + git commit -m "Track upstream Codex ${{ steps.upstream.outputs.latest_tag }}" + git push diff --git a/codex/LICENSE b/codex/LICENSE new file mode 100644 index 0000000..261eeb9 --- /dev/null +++ b/codex/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/codex/Makefile b/codex/Makefile new file mode 100644 index 0000000..d4f90f7 --- /dev/null +++ b/codex/Makefile @@ -0,0 +1,15 @@ +TOPDIR ?= $(CURDIR)/.rpmbuild + +.PHONY: srpm srpm-x86_64 srpm-aarch64 clean + +srpm: + TOPDIR="$(TOPDIR)" ./make-srpm.sh + +srpm-x86_64: + TOPDIR="$(TOPDIR)" ./make-srpm.sh + +srpm-aarch64: + TOPDIR="$(TOPDIR)" ./make-srpm.sh + +clean: + rm -rf "$(TOPDIR)" diff --git a/codex/README.md b/codex/README.md new file mode 100644 index 0000000..d84a80f --- /dev/null +++ b/codex/README.md @@ -0,0 +1,19 @@ +# codex + +## Description + +Lightweight coding agent that runs in your terminal + +## Installation Instructions + +``` +dnf copr enable funkemunky/codex +dnf install codex +``` + +## Automatic COPR rebuilds + +Create an issue [1] to mark package as outdated or packaging issues. Report +codex related issues to upstream. + +[1] https://github.com/funkemunky/codex-copr diff --git a/codex/codex.spec b/codex/codex.spec new file mode 100644 index 0000000..f95162d --- /dev/null +++ b/codex/codex.spec @@ -0,0 +1,61 @@ +%global up_version %{?up_version}%{!?up_version:0} +%global debug_package %{nil} +%global _build_id_links none +%{!?bash_completions_dir:%global bash_completions_dir %{_datadir}/bash-completion/completions} +%{!?fish_completions_dir:%global fish_completions_dir %{_datadir}/fish/vendor_completions.d} +%{!?zsh_completions_dir:%global zsh_completions_dir %{_datadir}/zsh/site-functions} + +Name: codex +Version: %{up_version} +Release: 1%{?dist} +Summary: OpenAI Codex command-line interface + +License: Apache-2.0 +URL: https://github.com/openai/codex +Source0: %{name}-%{version}-x86_64-unknown-linux-musl.tar.gz +Source1: %{name}-%{version}-aarch64-unknown-linux-musl.tar.gz + +ExclusiveArch: x86_64 aarch64 +Requires: git + +%description +OpenAI Codex is a coding assistant that runs in your terminal. + +%prep +%setup -q -c -T +%ifarch x86_64 +tar -xzf %{SOURCE0} --strip-components=1 +%endif +%ifarch aarch64 +tar -xzf %{SOURCE1} --strip-components=1 +%endif + +%build + +%install +install -Dpm 0755 codex %{buildroot}%{_bindir}/codex + +# Generate shell completions from the packaged binary so the payload stays +# aligned with the shipped CLI. +%{buildroot}%{_bindir}/codex completion bash > codex.bash +%{buildroot}%{_bindir}/codex completion fish > codex.fish +%{buildroot}%{_bindir}/codex completion zsh > _codex + +install -Dpm 0644 codex.bash %{buildroot}%{bash_completions_dir}/codex +install -Dpm 0644 codex.fish %{buildroot}%{fish_completions_dir}/codex.fish +install -Dpm 0644 _codex %{buildroot}%{zsh_completions_dir}/_codex + +%check +%{buildroot}%{_bindir}/codex --version >/dev/null + +%files +%license LICENSE +%doc README.md +%{_bindir}/codex +%{bash_completions_dir}/codex +%{fish_completions_dir}/codex.fish +%{zsh_completions_dir}/_codex + +%changelog +* Wed Apr 29 2026 Codex - 0-1 +- Package the latest upstream musl release tarball as an RPM. diff --git a/codex/make-srpm.sh b/codex/make-srpm.sh new file mode 100755 index 0000000..34383cd --- /dev/null +++ b/codex/make-srpm.sh @@ -0,0 +1,82 @@ +#!/usr/bin/env bash + +set -euo pipefail + +TOPDIR="${TOPDIR:-$PWD/.rpmbuild}" +SOURCES_DIR="$TOPDIR/SOURCES" +SRPMS_DIR="$TOPDIR/SRPMS" +SPECS_DIR="$TOPDIR/SPECS" +WORK_DIR="$(mktemp -d)" +LATEST_RELEASE_API="https://api.github.com/repos/openai/codex/releases/latest" + +cleanup() { + rm -rf "$WORK_DIR" +} +trap cleanup EXIT + +mkdir -p "$SOURCES_DIR" "$SRPMS_DIR" "$SPECS_DIR" + +echo "Resolving latest release tag..." +TAG="$( + curl -fsSL --retry 3 --retry-delay 2 "$LATEST_RELEASE_API" \ + | sed -n 's/.*"tag_name":[[:space:]]*"\([^"]*\)".*/\1/p' \ + | head -n1 +)" +if [[ -z "$TAG" ]]; then + echo "Failed to determine latest release tag from GitHub API." >&2 + exit 1 +fi + +VERSION="${TAG#rust-v}" +if [[ -z "$VERSION" || "$VERSION" == "$TAG" ]]; then + echo "Unexpected tag format: $TAG (expected rust-v)." >&2 + exit 1 +fi + +echo "Downloading LICENSE and README for $TAG..." +curl -fL --retry 3 --retry-delay 2 \ + -o "$WORK_DIR/LICENSE" \ + "https://raw.githubusercontent.com/openai/codex/$TAG/LICENSE" +curl -fL --retry 3 --retry-delay 2 \ + -o "$WORK_DIR/README.md" \ + "https://raw.githubusercontent.com/openai/codex/$TAG/README.md" + +for ARCH in x86_64 aarch64; do + ASSET_BASENAME="codex-$ARCH-unknown-linux-musl" + LATEST_URL="https://github.com/openai/codex/releases/latest/download/$ASSET_BASENAME.tar.gz" + ARCHIVE="$WORK_DIR/$ASSET_BASENAME.tar.gz" + UNPACK_DIR="$WORK_DIR/unpack-$ARCH" + SOURCE_TREE="$WORK_DIR/codex-$VERSION-$ARCH" + + echo "Downloading latest Codex release tarball for $ARCH..." + curl -fL --retry 3 --retry-delay 2 -o "$ARCHIVE" "$LATEST_URL" + + mkdir -p "$UNPACK_DIR" + tar -xzf "$ARCHIVE" -C "$UNPACK_DIR" + + UPSTREAM_BINARY="$UNPACK_DIR/$ASSET_BASENAME" + if [[ ! -x "$UPSTREAM_BINARY" ]]; then + echo "Expected upstream binary $ASSET_BASENAME, but it was not found." >&2 + exit 1 + fi + + mkdir -p "$SOURCE_TREE/codex-$VERSION" + install -pm 0755 "$UPSTREAM_BINARY" "$SOURCE_TREE/codex-$VERSION/codex" + install -pm 0644 "$WORK_DIR/LICENSE" "$SOURCE_TREE/codex-$VERSION/LICENSE" + install -pm 0644 "$WORK_DIR/README.md" "$SOURCE_TREE/codex-$VERSION/README.md" + + SOURCE_ARCHIVE="$SOURCES_DIR/codex-$VERSION-$ARCH-unknown-linux-musl.tar.gz" + tar -C "$SOURCE_TREE" -czf "$SOURCE_ARCHIVE" "codex-$VERSION" +done + +sed "s/^%global up_version .*/%global up_version $VERSION/" \ + codex.spec > "$SPECS_DIR/codex.spec" + +echo "Building SRPM for version $VERSION..." +rpmbuild \ + --define "_topdir $TOPDIR" \ + -bs "$SPECS_DIR/codex.spec" + +echo +echo "SRPM written to:" +find "$SRPMS_DIR" -maxdepth 1 -type f -name "codex-$VERSION-*.src.rpm" -print diff --git a/element-desktop/Makefile b/element-desktop/Makefile new file mode 100644 index 0000000..df457ea --- /dev/null +++ b/element-desktop/Makefile @@ -0,0 +1,12 @@ +OUTDIR ?= $(CURDIR)/dist + +.PHONY: srpm rpm clean + +srpm: + ./scripts/build-srpm.sh "$(OUTDIR)" + +rpm: + ./scripts/build-rpm.sh "$(OUTDIR)" + +clean: + rm -rf "$(OUTDIR)" diff --git a/element-desktop/README.md b/element-desktop/README.md new file mode 100644 index 0000000..2e897ca --- /dev/null +++ b/element-desktop/README.md @@ -0,0 +1,51 @@ +# Element Desktop RPM packaging + +This repository builds an RPM package from the upstream Element Desktop Linux +tarballs: + +- `https://packages.element.io/desktop/install/linux/glibc-x86-64/element-desktop.tar.gz` +- `https://packages.element.io/desktop/install/linux/glibc-aarch64/element-desktop.tar.gz` + +Latest upstream version tracked in this repo: `1.12.15` + +## What it does + +- Downloads the current upstream x86_64 and aarch64 tarballs. +- Derives the version from both tarball root directories and requires them to + match. +- Renders a concrete spec file with that version before invoking `rpmbuild`. +- Repackages the prebuilt binaries into an RPM. +- Removes the upstream auto-update manifest so RPM remains the update path. +- Sets `resources/package-type` to `rpm`. +- Builds binary RPMs for `x86_64` and `aarch64`, while still forcing SRPM + generation to target `x86_64` so COPR source builders stay consistent. +- Supports COPR SCM builds through `.copr/Makefile`. + +## Local builds + +Build a source RPM: + +```sh +make srpm +``` + +Build a binary RPM and source RPM: + +```sh +make rpm +``` + +Artifacts are written to `dist/`. + +## COPR + +Use COPR's SCM source type with: + +- Clone URL: this repository +- Spec template: `SPECS/element-desktop.spec.in` +- SRPM build method: `make srpm` +- Enable `x86_64` and `aarch64` binary chroots for this package + +COPR will invoke `.copr/Makefile`, which calls the same SRPM generation script +used for local builds. That script downloads the upstream tarball during the +SRPM stage, so no vendored source archive is required in git. diff --git a/element-desktop/SOURCES/element-desktop.desktop b/element-desktop/SOURCES/element-desktop.desktop new file mode 100644 index 0000000..a5d272f --- /dev/null +++ b/element-desktop/SOURCES/element-desktop.desktop @@ -0,0 +1,12 @@ +[Desktop Entry] +Version=1.0 +Type=Application +Name=Element +Comment=Secure messaging and collaboration +Exec=element-desktop %U +Icon=element-desktop +Terminal=false +Categories=Network;InstantMessaging;Chat; +StartupWMClass=Element +MimeType=x-scheme-handler/element;x-scheme-handler/matrix;x-scheme-handler/matrix.to; +Keywords=Matrix;Chat;Messaging;Collaboration; diff --git a/element-desktop/SPECS/element-desktop.spec.in b/element-desktop/SPECS/element-desktop.spec.in new file mode 100644 index 0000000..26a7438 --- /dev/null +++ b/element-desktop/SPECS/element-desktop.spec.in @@ -0,0 +1,64 @@ +%global debug_package %{nil} +%ifarch aarch64 +%global upstream_dir %{name}-%{version}-arm64 +%global upstream_source %{SOURCE1} +%else +%global upstream_dir %{name}-%{version} +%global upstream_source %{SOURCE0} +%endif + +Name: element-desktop +Version: @VERSION@ +Release: 1%{?dist} +Summary: Secure messaging and collaboration desktop client +License: Apache-2.0 AND BSD-3-Clause AND MIT +URL: https://element.io/ +Source0: %{name}-%{version}.tar.gz +Source1: %{name}-%{version}-arm64.tar.gz +Source2: %{name}.desktop +ExclusiveArch: x86_64 aarch64 + +%description +Element Desktop is a Matrix client for secure messaging and collaboration. +This package repackages the upstream prebuilt Linux x86_64 and aarch64 +tarballs for RPM-based distributions. + +%prep +rm -rf %{upstream_dir} +tar -xzf %{upstream_source} +cd %{upstream_dir} +/usr/bin/chmod -Rf a+rX,u+w,g-w,o-w . + +%build +# Upstream ships prebuilt binaries in the source archive. + +%install +install -d %{buildroot}%{_libdir}/%{name} +cp -a . %{buildroot}%{_libdir}/%{name}/ + +rm -f %{buildroot}%{_libdir}/%{name}/resources/app-update.yml +printf 'rpm\n' > %{buildroot}%{_libdir}/%{name}/resources/package-type + +install -d %{buildroot}%{_bindir} +cat > %{buildroot}%{_bindir}/%{name} <<'EOF' +#!/bin/sh +exec %{_libdir}/%{name}/element-desktop "$@" +EOF +chmod 0755 %{buildroot}%{_bindir}/%{name} + +install -Dpm 0644 %{SOURCE2} \ + %{buildroot}%{_datadir}/applications/%{name}.desktop +install -Dpm 0644 resources/build/icon.png \ + %{buildroot}%{_datadir}/icons/hicolor/512x512/apps/%{name}.png + +%files +%license LICENSE.electron.txt +%doc LICENSES.chromium.html +%{_bindir}/%{name} +%{_libdir}/%{name} +%{_datadir}/applications/%{name}.desktop +%{_datadir}/icons/hicolor/512x512/apps/%{name}.png + +%changelog +* Mon Apr 27 2026 Codex - @VERSION@-1 +- Initial RPM packaging for upstream Element Desktop tarballs diff --git a/element-desktop/scripts/build-rpm.sh b/element-desktop/scripts/build-rpm.sh new file mode 100755 index 0000000..7967e2d --- /dev/null +++ b/element-desktop/scripts/build-rpm.sh @@ -0,0 +1,35 @@ +#!/bin/sh +set -eu + +ROOT_DIR="$(CDPATH= cd -- "$(dirname -- "$0")/.." && pwd)" +OUTDIR="${1:-$ROOT_DIR/dist}" +RPM_TARGET="${RPM_TARGET:-x86_64}" + +TOPDIR="$(mktemp -d)" +cleanup() { + rm -rf "$TOPDIR" +} +trap cleanup EXIT INT TERM + +mkdir -p \ + "$TOPDIR/BUILD" \ + "$TOPDIR/BUILDROOT" \ + "$TOPDIR/RPMS" \ + "$TOPDIR/SOURCES" \ + "$TOPDIR/SPECS" \ + "$TOPDIR/SRPMS" \ + "$OUTDIR" + +"$ROOT_DIR/scripts/fetch-source.sh" "$TOPDIR/SOURCES" >/dev/null +version="$(cat "$TOPDIR/SOURCES/.upstream-version")" + +cp "$ROOT_DIR/SOURCES/element-desktop.desktop" "$TOPDIR/SOURCES/" +"$ROOT_DIR/scripts/render-spec.sh" "$version" "$TOPDIR/SPECS/element-desktop.spec" + +rpmbuild -ba \ + --target "$RPM_TARGET" \ + --define "_topdir $TOPDIR" \ + "$TOPDIR/SPECS/element-desktop.spec" + +cp "$TOPDIR/SRPMS/"*.src.rpm "$OUTDIR/" +find "$TOPDIR/RPMS" -type f -name '*.rpm' -exec cp {} "$OUTDIR/" \; diff --git a/element-desktop/scripts/build-srpm.sh b/element-desktop/scripts/build-srpm.sh new file mode 100755 index 0000000..402b451 --- /dev/null +++ b/element-desktop/scripts/build-srpm.sh @@ -0,0 +1,35 @@ +#!/bin/sh +set -eu + +ROOT_DIR="$(CDPATH= cd -- "$(dirname -- "$0")/.." && pwd)" +OUTDIR="${1:-$ROOT_DIR/dist}" +RPM_TARGET="${RPM_TARGET:-x86_64}" + +TOPDIR="$(mktemp -d)" +cleanup() { + rm -rf "$TOPDIR" +} +trap cleanup EXIT INT TERM + +mkdir -p \ + "$TOPDIR/BUILD" \ + "$TOPDIR/BUILDROOT" \ + "$TOPDIR/RPMS" \ + "$TOPDIR/SOURCES" \ + "$TOPDIR/SPECS" \ + "$TOPDIR/SRPMS" \ + "$OUTDIR" + +"$ROOT_DIR/scripts/fetch-source.sh" "$TOPDIR/SOURCES" >/dev/null +version="$(cat "$TOPDIR/SOURCES/.upstream-version")" + +cp "$ROOT_DIR/SOURCES/element-desktop.desktop" "$TOPDIR/SOURCES/" +"$ROOT_DIR/scripts/render-spec.sh" "$version" "$TOPDIR/SPECS/element-desktop.spec" + +rpmbuild -bs \ + --target "$RPM_TARGET" \ + --define "_topdir $TOPDIR" \ + "$TOPDIR/SPECS/element-desktop.spec" + +cp "$TOPDIR/SRPMS/"*.src.rpm "$OUTDIR/" +printf '%s\n' "$OUTDIR"/element-desktop-"$version"-1*.src.rpm diff --git a/element-desktop/scripts/fetch-source.sh b/element-desktop/scripts/fetch-source.sh new file mode 100755 index 0000000..315f4b0 --- /dev/null +++ b/element-desktop/scripts/fetch-source.sh @@ -0,0 +1,55 @@ +#!/bin/sh +set -eu + +SOURCE_URL_X86_64="${SOURCE_URL_X86_64:-${SOURCE_URL:-https://packages.element.io/desktop/install/linux/glibc-x86-64/element-desktop.tar.gz}}" +SOURCE_URL_AARCH64="${SOURCE_URL_AARCH64:-https://packages.element.io/desktop/install/linux/glibc-aarch64/element-desktop.tar.gz}" +OUTDIR="${1:-}" + +if [ -z "$OUTDIR" ]; then + echo "usage: $0 OUTDIR" >&2 + exit 1 +fi + +mkdir -p "$OUTDIR" + +tmpdir="$(mktemp -d)" +cleanup() { + rm -rf "$tmpdir" +} +trap cleanup EXIT INT TERM + +archive_x86_64="$tmpdir/element-desktop-x86_64.tar.gz" +archive_aarch64="$tmpdir/element-desktop-aarch64.tar.gz" + +curl -fL "$SOURCE_URL_X86_64" -o "$archive_x86_64" +curl -fL "$SOURCE_URL_AARCH64" -o "$archive_aarch64" + +topdir_x86_64="$(tar -tzf "$archive_x86_64" | sed -n '1s#/##p')" +topdir_aarch64="$(tar -tzf "$archive_aarch64" | sed -n '1s#/##p')" + +version_x86_64="${topdir_x86_64#element-desktop-}" +version_aarch64="${topdir_aarch64#element-desktop-}" +version_aarch64="${version_aarch64%-arm64}" + +if [ -z "$version_x86_64" ] || [ "$version_x86_64" = "$topdir_x86_64" ]; then + echo "failed to derive x86_64 version from archive root: $topdir_x86_64" >&2 + exit 1 +fi + +if [ -z "$version_aarch64" ] || [ "$version_aarch64" = "$topdir_aarch64" ]; then + echo "failed to derive aarch64 version from archive root: $topdir_aarch64" >&2 + exit 1 +fi + +if [ "$version_x86_64" != "$version_aarch64" ]; then + echo "upstream version mismatch: x86_64=$version_x86_64 aarch64=$version_aarch64" >&2 + exit 1 +fi + +dest_x86_64="$OUTDIR/element-desktop-$version_x86_64.tar.gz" +dest_aarch64="$OUTDIR/element-desktop-$version_x86_64-arm64.tar.gz" + +cp "$archive_x86_64" "$dest_x86_64" +cp "$archive_aarch64" "$dest_aarch64" +printf '%s\n' "$version_x86_64" > "$OUTDIR/.upstream-version" +printf '%s\n%s\n' "$dest_x86_64" "$dest_aarch64" diff --git a/element-desktop/scripts/render-spec.sh b/element-desktop/scripts/render-spec.sh new file mode 100755 index 0000000..9d066f2 --- /dev/null +++ b/element-desktop/scripts/render-spec.sh @@ -0,0 +1,14 @@ +#!/bin/sh +set -eu + +ROOT_DIR="$(CDPATH= cd -- "$(dirname -- "$0")/.." && pwd)" +VERSION="${1:-}" +OUTFILE="${2:-}" +TEMPLATE="$ROOT_DIR/SPECS/element-desktop.spec.in" + +if [ -z "$VERSION" ] || [ -z "$OUTFILE" ]; then + echo "usage: $0 VERSION OUTFILE" >&2 + exit 1 +fi + +sed "s/@VERSION@/$VERSION/g" "$TEMPLATE" > "$OUTFILE" diff --git a/zed/zed.spec b/zed/zed.spec new file mode 100644 index 0000000..f9f9d9b --- /dev/null +++ b/zed/zed.spec @@ -0,0 +1,74 @@ +Name: zed +Version: 1.0.0 +Release: 2%{?dist} +Summary: Zed is a high-performance, multiplayer code editor + +License: ((Apache-2.0 OR MIT) AND BSD-3-Clause) AND ((MIT OR Apache-2.0) AND Unicode-3.0) AND (0BSD OR MIT OR Apache-2.0) AND (Apache-2.0 AND ISC) AND AGPL-3.0-only AND AGPL-3.0-or-later AND (Apache-2.0 OR BSL-1.0 OR MIT) AND (Apache-2.0 OR BSL-1.0) AND (Apache-2.0 OR ISC OR MIT) AND (Apache-2.0 OR MIT) AND (Apache-2.0 WITH LLVM-exception OR Apache-2.0 OR MIT) AND (Apache-2.0 WITH LLVM-exception) AND Apache-2.0 AND (BSD-2-Clause OR Apache-2.0 OR MIT) AND (BSD-2-Clause OR MIT OR Apache-2.0) AND BSD-2-Clause AND (CC0-1.0 OR Apache-2.0 OR Apache-2.0 WITH LLVM-exception) AND (CC0-1.0 OR Apache-2.0) AND (CC0-1.0 OR MIT-0 OR Apache-2.0) AND CC0-1.0 AND GPL-3.0-or-later AND (ISC AND (Apache-2.0 OR ISC) AND OpenSSL) AND (ISC AND (Apache-2.0 OR ISC)) AND ISC AND (MIT AND (MIT OR Apache-2.0)) AND (MIT AND BSD-3-Clause) AND (MIT OR Apache-2.0 OR CC0-1.0) AND (MIT OR Apache-2.0 OR NCSA) AND (MIT OR Apache-2.0 OR Zlib) AND (MIT OR Apache-2.0) AND (MIT OR Zlib OR Apache-2.0) AND MIT AND MPL-2.0 AND Unicode-3.0 AND (Unlicense OR MIT) AND (Zlib OR Apache-2.0 OR MIT) AND Zlib + +URL: https://zed.dev/ +Source0: https://github.com/zed-industries/zed/releases/download/v%{version}/zed-linux-x86_64.tar.gz + +ExclusiveArch: x86_64 + +%global debug_package %{nil} + +Requires: alsa-lib%{?_isa} +Requires: vulkan-loader%{?_isa} + +Suggests: gnome-keyring + +%description +Code at the speed of thought - Zed is a high-performance, multiplayer code editor from the creators of Atom and Tree-sitter. + +This package installs the official prebuilt binary from the Zed project. + +%prep +%autosetup -n zed.app -p1 + +%build +# nothing to build + +%install +# CLI wrapper +install -Dm755 bin/zed %{buildroot}%{_bindir}/zed + +# Editor binary (CLI finds it via relative path ../libexec/zed-editor) +install -Dm755 libexec/zed-editor %{buildroot}%{_libexecdir}/zed-editor + +# Bundled libraries +install -dm755 %{buildroot}%{_libdir}/zed +cp -a lib/. %{buildroot}%{_libdir}/zed/ + +# Icons +install -Dm644 share/icons/hicolor/512x512/apps/zed.png \ + %{buildroot}%{_iconsdir}/hicolor/512x512/apps/dev.zed.Zed.png +install -Dm644 share/icons/hicolor/1024x1024/apps/zed.png \ + %{buildroot}%{_iconsdir}/hicolor/1024x1024/apps/dev.zed.Zed.png + +# Desktop entry +install -dm755 %{buildroot}%{_datadir}/applications +sed 's|Icon=zed|Icon=dev.zed.Zed|g' share/applications/dev.zed.Zed.desktop \ + > %{buildroot}%{_datadir}/applications/dev.zed.Zed.desktop + +# License +install -Dm644 licenses.md %{buildroot}%{_licensedir}/%{name}/licenses.md + +%post +/usr/bin/update-desktop-database &>/dev/null || : +/usr/bin/gtk-update-icon-cache -f -t %{_iconsdir}/hicolor &>/dev/null || : + +%postun +/usr/bin/update-desktop-database &>/dev/null || : +/usr/bin/gtk-update-icon-cache -f -t %{_iconsdir}/hicolor &>/dev/null || : + +%files +%license %{_licensedir}/%{name}/licenses.md +%{_bindir}/zed +%{_libexecdir}/zed-editor +%{_libdir}/zed/ +%{_datadir}/applications/dev.zed.Zed.desktop +%{_iconsdir}/hicolor/512x512/apps/dev.zed.Zed.png +%{_iconsdir}/hicolor/1024x1024/apps/dev.zed.Zed.png + +%changelog +%autochangelog \ No newline at end of file