mirror of
https://github.com/dexoron/dcr.git
synced 2026-10-21 20:19:40 +00:00
Compare commits
20 Commits
v0.6.8
...
c2ef5483a0
| Author | SHA1 | Date | |
|---|---|---|---|
| c2ef5483a0 | |||
| eb24d616c5 | |||
| 4f76f54b63 | |||
| 37b9b855ec | |||
| 8f0f67ad62 | |||
| 49945aa65d | |||
| 83593aa592 | |||
| 2835188da9 | |||
| 78160e2bb9 | |||
| 7f9cd3d643 | |||
| 4d1bd1dbdc | |||
| 7bc571ea27 | |||
| f431c3d018 | |||
| 9fd1652ebb | |||
| c59d6de54f | |||
| 73b6ce903e | |||
| e97b9b6e00 | |||
| 12d1bc5111 | |||
| 8c9dd39503 | |||
| e3c35793ec |
138
.github/workflows/aur.yml
vendored
138
.github/workflows/aur.yml
vendored
@@ -1,138 +0,0 @@
|
||||
name: AUR Publish
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
version:
|
||||
description: "Tag version without v prefix (e.g. 0.2.2)"
|
||||
required: true
|
||||
push:
|
||||
tags:
|
||||
- "v*"
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
publish-aur:
|
||||
# Не публикуем dev/pre-release теги в AUR
|
||||
if: "!contains(github.ref_name, '-')"
|
||||
runs-on: ubuntu-latest
|
||||
environment: aur
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Derive version and checksum
|
||||
id: meta
|
||||
shell: bash
|
||||
run: |
|
||||
set -euo pipefail
|
||||
if [[ "${GITHUB_EVENT_NAME}" == "workflow_dispatch" ]]; then
|
||||
PKGVER="${{ inputs.version }}"
|
||||
else
|
||||
PKGVER="${GITHUB_REF_NAME#v}"
|
||||
fi
|
||||
SRC_URL="https://github.com/dexoron/dcr/archive/refs/tags/v${PKGVER}.tar.gz"
|
||||
SHA256="$(curl -fsSL "$SRC_URL" | sha256sum | awk '{print $1}')"
|
||||
|
||||
echo "pkgver=$PKGVER" >> "$GITHUB_OUTPUT"
|
||||
echo "source_url=$SRC_URL" >> "$GITHUB_OUTPUT"
|
||||
echo "sha256=$SHA256" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Render AUR metadata
|
||||
shell: bash
|
||||
run: |
|
||||
set -euo pipefail
|
||||
PKGVER='${{ steps.meta.outputs.pkgver }}'
|
||||
SRC_URL='${{ steps.meta.outputs.source_url }}'
|
||||
SHA256='${{ steps.meta.outputs.sha256 }}'
|
||||
|
||||
cat > packaging/aur/dcr/PKGBUILD <<PKG
|
||||
pkgname=dcr
|
||||
pkgver=${PKGVER}
|
||||
pkgrel=1
|
||||
pkgdesc="Cargo-like utility to manage C/C++ projects"
|
||||
arch=('x86_64' 'aarch64')
|
||||
url="https://github.com/dexoron/dcr"
|
||||
license=('MIT')
|
||||
depends=('gcc-libs')
|
||||
makedepends=('cargo')
|
||||
options=('!lto')
|
||||
optdepends=(
|
||||
'gcc: build C/C++ projects with GCC'
|
||||
'clang: build C/C++ projects with Clang'
|
||||
)
|
||||
source=("\$pkgname-\$pkgver.tar.gz::\$url/archive/refs/tags/v\$pkgver.tar.gz")
|
||||
sha256sums=('${SHA256}')
|
||||
|
||||
build() {
|
||||
cd "\$srcdir/\$pkgname-\$pkgver"
|
||||
export CARGO_PROFILE_RELEASE_LTO=false
|
||||
export RUSTFLAGS="\${RUSTFLAGS:-}"
|
||||
export RUSTFLAGS="\${RUSTFLAGS/-C link-arg=-fuse-ld=lld/}"
|
||||
cargo build --release --locked
|
||||
}
|
||||
|
||||
package() {
|
||||
cd "\$srcdir/\$pkgname-\$pkgver"
|
||||
install -Dm755 "target/release/dcr" "\$pkgdir/usr/bin/dcr"
|
||||
install -Dm644 LICENSE "\$pkgdir/usr/share/licenses/\$pkgname/LICENSE"
|
||||
}
|
||||
PKG
|
||||
|
||||
cat > packaging/aur/dcr/.SRCINFO <<SRC
|
||||
pkgbase = dcr
|
||||
pkgdesc = Cargo-like utility to manage C/C++ projects
|
||||
pkgver = ${PKGVER}
|
||||
pkgrel = 1
|
||||
url = https://github.com/dexoron/dcr
|
||||
arch = x86_64
|
||||
arch = aarch64
|
||||
license = MIT
|
||||
makedepends = cargo
|
||||
depends = gcc-libs
|
||||
optdepends = gcc: build C/C++ projects with GCC
|
||||
optdepends = clang: build C/C++ projects with Clang
|
||||
options = !lto
|
||||
source = dcr-${PKGVER}.tar.gz::${SRC_URL}
|
||||
sha256sums = ${SHA256}
|
||||
|
||||
pkgname = dcr
|
||||
SRC
|
||||
|
||||
- name: Push to AUR
|
||||
env:
|
||||
AUR_SSH_PRIVATE_KEY: ${{ secrets.AUR_SSH_PRIVATE_KEY }}
|
||||
AUR_PACKAGE: dcr
|
||||
shell: bash
|
||||
run: |
|
||||
set -euo pipefail
|
||||
|
||||
if [[ -z "${AUR_SSH_PRIVATE_KEY:-}" ]]; then
|
||||
echo "AUR_SSH_PRIVATE_KEY secret is missing"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
install -d -m 700 ~/.ssh
|
||||
printf '%s\n' "$AUR_SSH_PRIVATE_KEY" > ~/.ssh/aur
|
||||
chmod 600 ~/.ssh/aur
|
||||
ssh-keyscan aur.archlinux.org >> ~/.ssh/known_hosts
|
||||
|
||||
export GIT_SSH_COMMAND='ssh -i ~/.ssh/aur -o IdentitiesOnly=yes'
|
||||
git clone "ssh://aur@aur.archlinux.org/${AUR_PACKAGE}.git" aur-repo
|
||||
cp packaging/aur/dcr/PKGBUILD aur-repo/PKGBUILD
|
||||
cp packaging/aur/dcr/.SRCINFO aur-repo/.SRCINFO
|
||||
|
||||
cd aur-repo
|
||||
git config user.name "github-actions[bot]"
|
||||
git config user.email "github-actions[bot]@users.noreply.github.com"
|
||||
|
||||
if git diff --quiet; then
|
||||
echo "No AUR changes"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
git add PKGBUILD .SRCINFO
|
||||
git commit -m "dcr ${{ steps.meta.outputs.pkgver }}"
|
||||
git push
|
||||
109
.github/workflows/dexoron-packages-index.yml
vendored
Normal file
109
.github/workflows/dexoron-packages-index.yml
vendored
Normal file
@@ -0,0 +1,109 @@
|
||||
name: Dexoron Packages Index
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
tag:
|
||||
description: "Версия (тег) для ручного импорта пакетов (например, v0.6.9)"
|
||||
required: true
|
||||
type: string
|
||||
workflow_run:
|
||||
workflows: ["Release"]
|
||||
types:
|
||||
- completed
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
update-packages-index:
|
||||
runs-on: ubuntu-latest
|
||||
if: ${{ github.event_name == 'workflow_dispatch' || github.event_workflow_run.conclusion == 'success' }}
|
||||
|
||||
steps:
|
||||
- name: Checkout Central Packages Repo
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
repository: 'dexoron/packages'
|
||||
token: ${{ secrets.PACKAGES_REPO_TOKEN }}
|
||||
path: 'central-packages'
|
||||
|
||||
- name: Import GPG Key
|
||||
uses: crazy-max/ghaction-import-gpg@v6
|
||||
with:
|
||||
gpg_private_key: ${{ secrets.GPG_PRIVATE_KEY }}
|
||||
|
||||
# --- Загрузка артефактов (сохранена прежняя логика) ---
|
||||
- name: Download Artifacts
|
||||
if: ${{ github.event_name == 'workflow_run' }}
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
path: central-packages/
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
run-id: ${{ github.event.workflow_run.id }}
|
||||
|
||||
- name: Download Packages from Release Assets
|
||||
if: ${{ github.event_name == 'workflow_dispatch' }}
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
TAG: ${{ inputs.tag }}
|
||||
run: |
|
||||
gh release download "$TAG" --repo dexoron/dcr --pattern "*.pkg.tar.zst" --dir central-packages/archlinux/x86_64/ --clobber
|
||||
gh release download "$TAG" --repo dexoron/dcr --pattern "*.deb" --dir central-packages/debian/ --clobber
|
||||
gh release download "$TAG" --repo dexoron/dcr --pattern "*.rpm" --dir central-packages/fedora/x86_64/ --clobber
|
||||
|
||||
# --- ИНДЕКСАЦИЯ И ПОДПИСЬ ---
|
||||
|
||||
- name: Update Pacman Database
|
||||
run: |
|
||||
docker run --rm \
|
||||
-v ${{ github.workspace }}/central-packages:/packages \
|
||||
-v ~/.gnupg:/root/.gnupg \
|
||||
archlinux:latest \
|
||||
bash -c '
|
||||
cd /packages/archlinux/x86_64 && \
|
||||
packages=(*.pkg.tar.zst) && \
|
||||
repo-add --sign dexoron.db.tar.gz "${packages[@]}" && \
|
||||
ln -sf dexoron.db.tar.gz dexoron.db && \
|
||||
ln -sf dexoron.files.tar.gz dexoron.files
|
||||
'
|
||||
- name: Fix GPG permissions after Docker
|
||||
run: sudo chown -R runner:runner ~/.gnupg
|
||||
|
||||
- name: Update Debian APT Repository Index
|
||||
run: |
|
||||
sudo apt-get update && sudo apt-get install -y dpkg-dev
|
||||
cd central-packages/debian
|
||||
dpkg-scanpackages . /dev/null | gzip -9c > Packages.gz
|
||||
|
||||
echo "Origin: Dexoron Packages" > Release
|
||||
echo "Label: Dexoron Packages" >> Release
|
||||
echo "Suite: stable" >> Release
|
||||
echo "Codename: stable" >> Release
|
||||
echo "Architectures: amd64" >> Release
|
||||
echo "Components: main" >> Release
|
||||
echo "Description: Dexoron binary package repository" >> Release
|
||||
echo "Date: $(date -uR)" >> Release
|
||||
echo "SHA256:" >> Release
|
||||
echo " $(sha256sum Packages.gz | awk '{print $1" "$2}')" >> Release
|
||||
|
||||
gpg --batch --yes --pinentry-mode loopback --local-user 74322D39483E9C9E8C86C0AA0770A5C2A2A82DAC --detach-sign --armor --output Release.gpg Release
|
||||
gpg --batch --yes --pinentry-mode loopback --local-user 74322D39483E9C9E8C86C0AA0770A5C2A2A82DAC --clearsign --output InRelease Release
|
||||
|
||||
- name: Update Fedora DNF Repository Index
|
||||
run: |
|
||||
sudo apt-get update && sudo apt-get install -y createrepo-c
|
||||
cd central-packages/fedora/x86_64
|
||||
createrepo_c .
|
||||
gpg --batch --yes --detach-sign --armor --output repodata/repomd.xml.asc repodata/repomd.xml
|
||||
|
||||
- name: Push to dexoron/packages
|
||||
run: |
|
||||
cd central-packages
|
||||
git config user.name "github-actions[bot]"
|
||||
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
|
||||
git add .
|
||||
if ! git diff --cached --quiet; then
|
||||
git commit -m "chore: update and sign repositories"
|
||||
git push
|
||||
fi
|
||||
451
.github/workflows/release.yml
vendored
451
.github/workflows/release.yml
vendored
@@ -13,6 +13,14 @@ on:
|
||||
description: "Build Linux"
|
||||
type: boolean
|
||||
default: true
|
||||
run_linux_packages:
|
||||
description: "Build Linux Packages (.deb, .rpm, .snap, .pkg.tar.zst)"
|
||||
type: boolean
|
||||
default: true
|
||||
run_aur:
|
||||
description: "Update AUR packages (dcr & dcr-bin)"
|
||||
type: boolean
|
||||
default: false
|
||||
run_bsd:
|
||||
description: "Build BSD"
|
||||
type: boolean
|
||||
@@ -92,7 +100,7 @@ jobs:
|
||||
name: release-notes
|
||||
path: .github/release-notes.md
|
||||
|
||||
# ── Linux ──────────────────────────────────────────────────────────────────
|
||||
# ── Linux Binaries Matrix ──────────────────────────────────────────────────
|
||||
build-linux:
|
||||
if: ${{ github.event_name == 'push' || github.event.inputs.run_linux == 'true' }}
|
||||
needs: [setup, notes]
|
||||
@@ -148,7 +156,150 @@ jobs:
|
||||
body_path: .github/release-notes.md
|
||||
prerelease: ${{ needs.setup.outputs.prerelease == 'true' }}
|
||||
|
||||
# ── macOS ──────────────────────────────────────────────────────────────────
|
||||
# ── Linux Packages Matrix (.deb, .rpm, .pkg.tar.zst, .snap) ────────────────
|
||||
build-linux-packages:
|
||||
if: ${{ github.event_name == 'push' || github.event.inputs.run_linux_packages == 'true' }}
|
||||
needs: [setup, notes]
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- package_type: deb
|
||||
artifact_name: debian-package
|
||||
- package_type: rpm
|
||||
artifact_name: rpm-package
|
||||
- package_type: arch
|
||||
artifact_name: arch-package
|
||||
- package_type: snap
|
||||
artifact_name: snap-package
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
ref: ${{ needs.setup.outputs.tag }}
|
||||
|
||||
- name: Setup Rust (For non-container builds)
|
||||
if: matrix.package_type != 'arch'
|
||||
uses: dtolnay/rust-toolchain@stable
|
||||
|
||||
# ── DEB Build ──
|
||||
- name: Build Debian Package
|
||||
if: matrix.package_type == 'deb'
|
||||
run: |
|
||||
cargo install cargo-deb
|
||||
cargo build --release
|
||||
cargo deb --no-build
|
||||
mkdir -p dist-packages && cp target/debian/*.deb dist-packages/
|
||||
|
||||
# ── RPM Build ──
|
||||
- name: Build RPM Package
|
||||
if: matrix.package_type == 'rpm'
|
||||
run: |
|
||||
cargo install cargo-generate-rpm
|
||||
cargo build --release
|
||||
cargo generate-rpm
|
||||
mkdir -p dist-packages && cp target/generate-rpm/*.rpm dist-packages/
|
||||
|
||||
# ── Snap Build ──
|
||||
- name: Build Snap Package
|
||||
if: matrix.package_type == 'snap'
|
||||
run: |
|
||||
cargo build --release
|
||||
mkdir -p packaging/snap/dist/bin
|
||||
cp target/release/dcr packaging/snap/dist/bin/
|
||||
|
||||
- name: Snapcraft Build Action
|
||||
if: matrix.package_type == 'snap'
|
||||
uses: snapcore/action-build@v1
|
||||
with:
|
||||
path: packaging/snap
|
||||
|
||||
- name: Prepare Snap Output
|
||||
if: matrix.package_type == 'snap'
|
||||
run: mkdir -p dist-packages && cp packaging/snap/*.snap dist-packages/
|
||||
|
||||
# ── Arch Linux Native Build ──
|
||||
- name: Build Arch Package inside Container
|
||||
if: matrix.package_type == 'arch'
|
||||
run: |
|
||||
PKGVER='${{ needs.setup.outputs.version }}'
|
||||
TAG='${{ needs.setup.outputs.tag }}'
|
||||
SRC_URL="https://github.com/dexoron/dcr/archive/refs/tags/${TAG}.tar.gz"
|
||||
SHA256="$(curl -fsSL "$SRC_URL" | sha256sum | awk '{print $1}')"
|
||||
mkdir -p arch-build
|
||||
cat > arch-build/PKGBUILD <<PKG
|
||||
pkgname=dcr
|
||||
pkgver=${PKGVER}
|
||||
pkgrel=1
|
||||
pkgdesc="Cargo-like utility to manage C/C++ projects"
|
||||
arch=('x86_64')
|
||||
url="https://github.com/dexoron/dcr"
|
||||
license=('GPL-3.0-or-later')
|
||||
depends=('gcc-libs')
|
||||
makedepends=('cargo')
|
||||
options=('!lto')
|
||||
source=("\$pkgname-\$pkgver.tar.gz::\$url/archive/refs/tags/v\$pkgver.tar.gz")
|
||||
sha256sums=('${SHA256}')
|
||||
build() {
|
||||
cd "\$srcdir/\$pkgname-\$pkgver"
|
||||
cargo build --release --locked
|
||||
}
|
||||
package() {
|
||||
cd "\$srcdir/\$pkgname-\$pkgver"
|
||||
install -Dm755 "target/release/dcr" "\$pkgdir/usr/bin/dcr"
|
||||
install -Dm644 LICENSE "\$pkgdir/usr/share/licenses/\$pkgname/LICENSE"
|
||||
}
|
||||
PKG
|
||||
docker run --rm \
|
||||
-v ${{ github.workspace }}/arch-build:/build \
|
||||
archlinux:latest \
|
||||
bash -c "
|
||||
pacman -Syu --noconfirm base-devel cargo gcc-libs git && \
|
||||
useradd -m builduser && \
|
||||
echo 'builduser ALL=(ALL) NOPASSWD: ALL' >> /etc/sudoers && \
|
||||
chown -R builduser:builduser /build && \
|
||||
cd /build && \
|
||||
su builduser -c 'makepkg -s --noconfirm'
|
||||
"
|
||||
mkdir -p dist-packages && cp arch-build/*.pkg.tar.zst dist-packages/
|
||||
|
||||
# ── Upload Artifacts ──
|
||||
- name: Upload Package Artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: ${{ matrix.artifact_name }}
|
||||
path: dist-packages/*
|
||||
if-no-files-found: ignore
|
||||
|
||||
# ── Publish Packages to Release (Out of Matrix) ────────────────────────────
|
||||
publish-dexoron-packages:
|
||||
needs: [setup, notes, build-linux-packages]
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Download Release Notes
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: release-notes
|
||||
path: .github
|
||||
|
||||
- name: Download Built Packages
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
path: collected-packages
|
||||
|
||||
- name: Upload Everything to GitHub Release
|
||||
uses: softprops/action-gh-release@v2
|
||||
with:
|
||||
tag_name: ${{ needs.setup.outputs.tag }}
|
||||
files: |
|
||||
collected-packages/debian-package/*
|
||||
collected-packages/rpm-package/*
|
||||
collected-packages/arch-package/*
|
||||
collected-packages/snap-package/*
|
||||
body_path: .github/release-notes.md
|
||||
prerelease: ${{ needs.setup.outputs.prerelease == 'true' }}
|
||||
|
||||
# ── macOS Matrix ───────────────────────────────────────────────────────────
|
||||
build-macos:
|
||||
if: ${{ github.event_name == 'push' || github.event.inputs.run_macos == 'true' }}
|
||||
needs: [setup, notes]
|
||||
@@ -194,7 +345,7 @@ jobs:
|
||||
body_path: .github/release-notes.md
|
||||
prerelease: ${{ needs.setup.outputs.prerelease == 'true' }}
|
||||
|
||||
# ── BSD ────────────────────────────────────────────────────────────────────
|
||||
# ── BSD Systems Matrix ─────────────────────────────────────────────────────
|
||||
build-bsd:
|
||||
if: ${{ github.event_name == 'push' || github.event.inputs.run_bsd == 'true' }}
|
||||
needs: [setup, notes]
|
||||
@@ -202,9 +353,7 @@ jobs:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- target: x86_64-unknown-freebsd
|
||||
# При необходимости сюда можно докинуть x86_64-unknown-netbsd
|
||||
system: [freebsd, openbsd, netbsd]
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
@@ -216,34 +365,72 @@ jobs:
|
||||
name: release-notes
|
||||
path: .github
|
||||
|
||||
- name: Install cargo-zigbuild
|
||||
run: |
|
||||
pip install cargo-zigbuild
|
||||
echo "$HOME/.local/bin" >> $GITHUB_PATH
|
||||
|
||||
- name: Setup Rust
|
||||
uses: dtolnay/rust-toolchain@stable
|
||||
# --- FREEBSD ---
|
||||
- name: Build in FreeBSD VM
|
||||
if: matrix.system == 'freebsd'
|
||||
uses: vmactions/freebsd-vm@v1
|
||||
with:
|
||||
targets: ${{ matrix.target }}
|
||||
usesh: true
|
||||
run: |
|
||||
export PATH="/usr/local/bin:/usr/local/sbin:$PATH"
|
||||
pkg install -y rust perl5 gmake
|
||||
cargo build --release
|
||||
|
||||
- name: Build
|
||||
run: cargo zigbuild --release --target ${{ matrix.target }}
|
||||
|
||||
- name: Prepare Artifact
|
||||
- name: Prepare FreeBSD Artifact
|
||||
if: matrix.system == 'freebsd'
|
||||
run: |
|
||||
ASSET="dcr-${{ matrix.target }}-${{ needs.setup.outputs.version }}"
|
||||
cp target/${{ matrix.target }}/release/dcr "$ASSET"
|
||||
echo "ASSET_NAME=${ASSET}" >> "$GITHUB_ENV"
|
||||
ASSET="dcr-x86_64-unknown-freebsd-${{ needs.setup.outputs.version }}"
|
||||
cp target/release/dcr "$ASSET"
|
||||
echo "BSD_ASSET=${ASSET}" >> "$GITHUB_ENV"
|
||||
|
||||
- name: Upload Release Asset
|
||||
# --- OPENBSD ---
|
||||
- name: Build in OpenBSD VM
|
||||
if: matrix.system == 'openbsd'
|
||||
uses: vmactions/openbsd-vm@v1
|
||||
with:
|
||||
usesh: true
|
||||
run: |
|
||||
export PATH="/usr/local/bin:$PATH"
|
||||
pkg_add rust perl gmake
|
||||
cargo build --release
|
||||
|
||||
- name: Prepare OpenBSD Artifact
|
||||
if: matrix.system == 'openbsd'
|
||||
run: |
|
||||
ASSET="dcr-x86_64-unknown-openbsd-${{ needs.setup.outputs.version }}"
|
||||
cp target/release/dcr "$ASSET"
|
||||
echo "BSD_ASSET=${ASSET}" >> "$GITHUB_ENV"
|
||||
|
||||
# --- NETBSD ---
|
||||
- name: Build in NetBSD VM
|
||||
if: matrix.system == 'netbsd'
|
||||
uses: vmactions/netbsd-vm@v1
|
||||
with:
|
||||
usesh: true
|
||||
run: |
|
||||
pkg_add rust perl gmake
|
||||
mkdir -p /tmp/bin
|
||||
ln -sf /usr/pkg/bin/gmake /tmp/bin/make
|
||||
export PATH="/tmp/bin:/usr/pkg/bin:/usr/pkg/sbin:$PATH"
|
||||
cargo build --release
|
||||
|
||||
- name: Prepare NetBSD Artifact
|
||||
if: matrix.system == 'netbsd'
|
||||
run: |
|
||||
ASSET="dcr-x86_64-unknown-netbsd-${{ needs.setup.outputs.version }}"
|
||||
cp target/release/dcr "$ASSET"
|
||||
echo "BSD_ASSET=${ASSET}" >> "$GITHUB_ENV"
|
||||
|
||||
# --- UPLOAD TARGET ---
|
||||
- name: Upload BSD Asset to Release
|
||||
uses: softprops/action-gh-release@v2
|
||||
with:
|
||||
tag_name: ${{ needs.setup.outputs.tag }}
|
||||
files: ${{ env.ASSET_NAME }}
|
||||
files: ${{ env.BSD_ASSET }}
|
||||
body_path: .github/release-notes.md
|
||||
prerelease: ${{ needs.setup.outputs.prerelease == 'true' }}
|
||||
|
||||
# ── Windows ────────────────────────────────────────────────────────────────
|
||||
# ── Windows Matrix ─────────────────────────────────────────────────────────
|
||||
build-windows:
|
||||
if: ${{ github.event_name == 'push' || github.event.inputs.run_windows == 'true' }}
|
||||
needs: [setup, notes]
|
||||
@@ -288,6 +475,217 @@ jobs:
|
||||
files: ${{ env.ASSET_NAME }}
|
||||
body_path: .github/release-notes.md
|
||||
prerelease: ${{ needs.setup.outputs.prerelease == 'true' }}
|
||||
|
||||
# ── Arch User Repository (dcr) ───────────────────────────────────
|
||||
publish-aur:
|
||||
if: ${{ (github.event_name == 'push' && needs.setup.outputs.prerelease == 'false') || github.event.inputs.run_aur == 'true' }}
|
||||
needs: [setup]
|
||||
runs-on: ubuntu-latest
|
||||
environment: aur
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Derive checksum
|
||||
id: meta
|
||||
shell: bash
|
||||
run: |
|
||||
set -euo pipefail
|
||||
SRC_URL="https://github.com/dexoron/dcr/archive/refs/tags/${{ needs.setup.outputs.tag }}.tar.gz"
|
||||
SHA256="$(curl -fsSL "$SRC_URL" | sha256sum | awk '{print $1}')"
|
||||
echo "source_url=$SRC_URL" >> "$GITHUB_OUTPUT"
|
||||
echo "sha256=$SHA256" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Render AUR metadata
|
||||
shell: bash
|
||||
run: |
|
||||
set -euo pipefail
|
||||
PKGVER='${{ needs.setup.outputs.version }}'
|
||||
SRC_URL='${{ steps.meta.outputs.source_url }}'
|
||||
SHA256='${{ steps.meta.outputs.sha256 }}'
|
||||
|
||||
mkdir -p packages/aur/dcr
|
||||
cat > packages/aur/dcr/PKGBUILD <<PKG
|
||||
pkgname=dcr
|
||||
pkgver=${PKGVER}
|
||||
pkgrel=1
|
||||
pkgdesc="Cargo-like utility to manage C/C++ projects"
|
||||
arch=('x86_64' 'aarch64')
|
||||
url="https://github.com/dexoron/dcr"
|
||||
license=('GPL-3.0-or-later')
|
||||
depends=('gcc-libs')
|
||||
makedepends=('cargo')
|
||||
options=('!lto')
|
||||
optdepends=(
|
||||
'gcc: build C/C++ projects with GCC'
|
||||
'clang: build C/C++ projects with Clang'
|
||||
)
|
||||
source=("\$pkgname-\$pkgver.tar.gz::\$url/archive/refs/tags/v\$pkgver.tar.gz")
|
||||
sha256sums=('${SHA256}')
|
||||
|
||||
build() {
|
||||
cd "\$srcdir/\$pkgname-\$pkgver"
|
||||
export CARGO_PROFILE_RELEASE_LTO=false
|
||||
export RUSTFLAGS="\${RUSTFLAGS:-}"
|
||||
export RUSTFLAGS="\${RUSTFLAGS/-C link-arg=-fuse-ld=lld/}"
|
||||
cargo build --release --locked
|
||||
}
|
||||
|
||||
package() {
|
||||
cd "\$srcdir/\$pkgname-\$pkgver"
|
||||
install -Dm755 "target/release/dcr" "\$pkgdir/usr/bin/dcr"
|
||||
install -Dm644 LICENSE "\$pkgdir/usr/share/licenses/\$pkgname/LICENSE"
|
||||
}
|
||||
PKG
|
||||
|
||||
cat > packages/aur/dcr/.SRCINFO <<SRC
|
||||
pkgbase = dcr
|
||||
pkgdesc = Cargo-like utility to manage C/C++ projects
|
||||
pkgver = ${PKGVER}
|
||||
pkgrel = 1
|
||||
url = https://github.com/dexoron/dcr
|
||||
arch = x86_64
|
||||
arch = aarch64
|
||||
license = GPL-3.0-or-later
|
||||
makedepends = cargo
|
||||
depends = gcc-libs
|
||||
optdepends = gcc: build C/C++ projects with GCC
|
||||
optdepends = clang: build C/C++ projects with Clang
|
||||
options = !lto
|
||||
source = dcr-${PKGVER}.tar.gz::${SRC_URL}
|
||||
sha256sums = ${SHA256}
|
||||
|
||||
pkgname = dcr
|
||||
SRC
|
||||
|
||||
- name: Push to AUR
|
||||
env:
|
||||
AUR_SSH_PRIVATE_KEY: ${{ secrets.AUR_SSH_PRIVATE_KEY }}
|
||||
AUR_PACKAGE: dcr
|
||||
shell: bash
|
||||
run: |
|
||||
set -euo pipefail
|
||||
install -d -m 700 ~/.ssh
|
||||
printf '%s\n' "$AUR_SSH_PRIVATE_KEY" > ~/.ssh/aur
|
||||
chmod 600 ~/.ssh/aur
|
||||
ssh-keyscan aur.archlinux.org >> ~/.ssh/known_hosts
|
||||
|
||||
export GIT_SSH_COMMAND='ssh -i ~/.ssh/aur -o IdentitiesOnly=yes'
|
||||
git clone "ssh://aur@aur.archlinux.org/${AUR_PACKAGE}.git" aur-repo
|
||||
cp packages/aur/dcr/PKGBUILD aur-repo/PKGBUILD
|
||||
cp packages/aur/dcr/.SRCINFO aur-repo/.SRCINFO
|
||||
|
||||
cd aur-repo
|
||||
git config user.name "github-actions[bot]"
|
||||
git config user.email "github-actions[bot]@users.noreply.github.com"
|
||||
|
||||
if git diff --quiet; then
|
||||
echo "No AUR changes"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
git add PKGBUILD .SRCINFO
|
||||
git commit -m "dcr ${{ needs.setup.outputs.version }}"
|
||||
git push
|
||||
|
||||
# ── Arch User Repository (dcr-bin) ────────────────────────────────
|
||||
publish-aur-bin:
|
||||
if: ${{ (github.event_name == 'push' && needs.setup.outputs.prerelease == 'false') || github.event.inputs.run_aur == 'true' }}
|
||||
needs: [setup, build-linux]
|
||||
runs-on: ubuntu-latest
|
||||
environment: aur
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Derive checksum
|
||||
id: meta
|
||||
shell: bash
|
||||
run: |
|
||||
set -euo pipefail
|
||||
BIN_URL="https://github.com/dexoron/dcr/releases/download/${{ needs.setup.outputs.tag }}/dcr-x86_64-unknown-linux-musl-${{ needs.setup.outputs.version }}"
|
||||
SHA256="$(curl -fsSL "$BIN_URL" | sha256sum | awk '{print $1}')"
|
||||
echo "bin_url=$BIN_URL" >> "$GITHUB_OUTPUT"
|
||||
echo "sha256=$SHA256" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Render AUR Metadata
|
||||
shell: bash
|
||||
run: |
|
||||
set -euo pipefail
|
||||
PKGVER='${{ needs.setup.outputs.version }}'
|
||||
BIN_URL='${{ steps.meta.outputs.bin_url }}'
|
||||
SHA256='${{ steps.meta.outputs.sha256 }}'
|
||||
|
||||
mkdir -p packages/aur/dcr-bin
|
||||
cat > packages/aur/dcr-bin/PKGBUILD <<PKG
|
||||
pkgname=dcr-bin
|
||||
pkgver=${PKGVER}
|
||||
pkgrel=1
|
||||
pkgdesc="Cargo-like utility to manage C/C++ projects (pre-compiled musl binary)"
|
||||
arch=('x86_64')
|
||||
url="https://github.com/dexoron/dcr"
|
||||
license=('GPL-3.0-or-later')
|
||||
provides=('dcr')
|
||||
conflicts=('dcr')
|
||||
optdepends=(
|
||||
'gcc: build C/C++ projects with GCC'
|
||||
'clang: build C/C++ projects with Clang'
|
||||
)
|
||||
source_x86_64=("dcr-\$pkgver::${BIN_URL}")
|
||||
sha256sums_x86_64=('${SHA256}')
|
||||
|
||||
package() {
|
||||
install -Dm755 "\$srcdir/dcr-\$pkgver" "\$pkgdir/usr/bin/dcr"
|
||||
}
|
||||
PKG
|
||||
|
||||
cat > packages/aur/dcr-bin/.SRCINFO <<SRC
|
||||
pkgbase = dcr-bin
|
||||
pkgdesc = Cargo-like utility to manage C/C++ projects (pre-compiled musl binary)
|
||||
pkgver = ${PKGVER}
|
||||
pkgrel = 1
|
||||
url = https://github.com/dexoron/dcr
|
||||
arch = x86_64
|
||||
license = GPL-3.0-or-later
|
||||
provides = dcr
|
||||
conflicts = dcr
|
||||
optdepends = gcc: build C/C++ projects with GCC
|
||||
optdepends = clang: build C/C++ projects with Clang
|
||||
source_x86_64 = dcr-${PKGVER}::${BIN_URL}
|
||||
sha256sums_x86_64 = ${SHA256}
|
||||
|
||||
pkgname = dcr-bin
|
||||
SRC
|
||||
|
||||
- name: Push to AUR
|
||||
env:
|
||||
AUR_SSH_PRIVATE_KEY: ${{ secrets.AUR_SSH_PRIVATE_KEY }}
|
||||
AUR_PACKAGE: dcr-bin
|
||||
shell: bash
|
||||
run: |
|
||||
set -euo pipefail
|
||||
install -d -m 700 ~/.ssh
|
||||
printf '%s\n' "$AUR_SSH_PRIVATE_KEY" > ~/.ssh/aur
|
||||
chmod 600 ~/.ssh/aur
|
||||
ssh-keyscan aur.archlinux.org >> ~/.ssh/known_hosts
|
||||
|
||||
export GIT_SSH_COMMAND='ssh -i ~/.ssh/aur -o IdentitiesOnly=yes'
|
||||
git clone "ssh://aur@aur.archlinux.org/${AUR_PACKAGE}.git" aur-repo
|
||||
cp packages/aur/dcr-bin/PKGBUILD aur-repo/PKGBUILD
|
||||
cp packages/aur/dcr-bin/.SRCINFO aur-repo/.SRCINFO
|
||||
|
||||
cd aur-repo
|
||||
git config user.name "github-actions[bot]"
|
||||
git config user.email "github-actions[bot]@users.noreply.github.com"
|
||||
|
||||
if git diff --quiet; then
|
||||
echo "No AUR changes"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
git add PKGBUILD .SRCINFO
|
||||
git commit -m "dcr-bin ${{ needs.setup.outputs.version }}"
|
||||
git push
|
||||
|
||||
# ── crates.io ──────────────────────────────────────────────────────────────
|
||||
publish-crates:
|
||||
@@ -296,6 +694,9 @@ jobs:
|
||||
(github.event_name == 'workflow_dispatch' && github.event.inputs.run_publish == 'true')
|
||||
needs: [setup, build-linux, build-macos, build-windows, build-bsd]
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: read
|
||||
id-token: write
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
@@ -304,7 +705,7 @@ jobs:
|
||||
- uses: dtolnay/rust-toolchain@stable
|
||||
|
||||
- name: Publish to crates.io
|
||||
run: cargo publish --token ${{ secrets.CARGO_REGISTRY_TOKEN }}
|
||||
run: cargo publish
|
||||
|
||||
# ── Homebrew tap ───────────────────────────────────────────────────────────
|
||||
publish-brew:
|
||||
|
||||
47
CHANGELOG.md
47
CHANGELOG.md
@@ -1,5 +1,52 @@
|
||||
# Changelog
|
||||
|
||||
## [0.6.9] - 2026-05-28
|
||||
|
||||
Added:
|
||||
|
||||
- **Dexoron Packages Index** — new standalone CI workflow (`.github/workflows/dexoron-packages-index.yml`)
|
||||
that automatically updates the `dexoron/packages` repository indexes after a release.
|
||||
Supports Arch Linux (`repo-add`), Debian (`dpkg-scanpackages`), and Fedora (`createrepo_c`).
|
||||
Triggered by `workflow_dispatch` or `workflow_run` on the Release workflow.
|
||||
|
||||
- **Arch Linux native package** (`.pkg.tar.zst`) build inside the release workflow —
|
||||
builds from source in an `archlinux:latest` Docker container using a dynamically
|
||||
generated PKGBUILD.
|
||||
|
||||
- **AUR publish support** — new `run_aur` workflow dispatch input and `publish-aur` /
|
||||
`publish-aur-bin` jobs that push PKGBUILD / `.SRCINFO` to `aur.archlinux.org`.
|
||||
|
||||
Changed:
|
||||
|
||||
- **Release workflow refactored** — Linux packages (deb, rpm, snap, arch) and BSD
|
||||
builds now use `strategy.matrix` instead of separate jobs. A new
|
||||
`publish-dexoron-packages` job collects all package artifacts and uploads them
|
||||
to the GitHub Release in one step. Removed standalone `build-arch-package`,
|
||||
`build-snap`, `build-deb-rpm` jobs. The old `run_arch_native` input is now
|
||||
`run_linux_packages`.
|
||||
|
||||
- **Dexoron Packages Index workflow** extracted from `release.yml` into its own
|
||||
file with support for Debian and RPM repository indexes in addition to Arch.
|
||||
|
||||
- **git2 vendoring** — enabled `vendored-libgit2` and `vendored-openssl` features
|
||||
for reproducible CI builds without system libraries.
|
||||
|
||||
- **cargo-generate-rpm metadata** — updated to the current `package.metadata.rpm`
|
||||
format (uses `files` table instead of `assets` array).
|
||||
|
||||
Fixed:
|
||||
|
||||
- **`--target=<triple>` no longer passed to GCC** — the flag is now only injected into
|
||||
cflags when the resolved compiler name contains `"clang"`. GCC rejects this flag
|
||||
with `unrecognized command-line option`.
|
||||
|
||||
- **Workspace clean test** — removed assertions for member-local `target/`
|
||||
directories. Workspace members share the root `target/` directory, so their
|
||||
individual `src/<name>/target/` is never created.
|
||||
|
||||
- **Release build test path** — corrected expected directory from `target/release`
|
||||
to `target/x86_64-unknown-linux-gnu/release`.
|
||||
|
||||
## [0.6.8] - 2026-05-27
|
||||
|
||||
Added:
|
||||
|
||||
2
Cargo.lock
generated
2
Cargo.lock
generated
@@ -112,7 +112,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "dcr"
|
||||
version = "0.6.8"
|
||||
version = "0.6.9"
|
||||
dependencies = [
|
||||
"ctrlc",
|
||||
"git2",
|
||||
|
||||
32
Cargo.toml
32
Cargo.toml
@@ -1,12 +1,38 @@
|
||||
[package]
|
||||
name = "dcr"
|
||||
version = "0.6.8"
|
||||
version = "0.6.9"
|
||||
edition = "2024"
|
||||
build = "build.rs"
|
||||
description = "DCR is a utility for managing C/C++ projects in a Cargo-like style."
|
||||
license = "GPL-3.0-or-later"
|
||||
repository = "https://github.com/dexoron/dcr"
|
||||
|
||||
[package.metadata.binstall]
|
||||
pkg-fmt = "bin"
|
||||
pkg-url = "{ repo }/releases/download/v{ version }/dcr-{ target }-{ version }{ bin-suffix }"
|
||||
|
||||
[package.metadata.deb]
|
||||
maintainer = "Dexoron (Bezotechestvo Vladimir) <main@dexoron.su>"
|
||||
copyright = "2026, Dexoron"
|
||||
extended-description = """
|
||||
Cargo-like utility to manage C/C++ projects.
|
||||
"""
|
||||
section = "devel"
|
||||
priority = "optional"
|
||||
assets = [
|
||||
["target/release/dcr", "usr/bin/dcr", "755"],
|
||||
]
|
||||
|
||||
[package.metadata.generate-rpm]
|
||||
summary = "Cargo-like utility to manage C/C++ projects"
|
||||
description = """
|
||||
Cargo-like utility to manage C/C++ projects.
|
||||
"""
|
||||
|
||||
assets = [
|
||||
{ source = "target/release/dcr", dest = "/usr/bin/dcr", mode = "755" }
|
||||
]
|
||||
|
||||
[dependencies]
|
||||
glob = "0.3"
|
||||
reqwest = { version = "0.12", default-features = false, features = ["blocking", "json", "rustls-tls"] }
|
||||
@@ -14,9 +40,9 @@ serde = { version = "1", features = ["derive"] }
|
||||
self-replace = "1"
|
||||
sha2 = "0.10"
|
||||
toml = "1.0.3"
|
||||
git2 = "0.20.4"
|
||||
serde_json = "1"
|
||||
ctrlc = "3"
|
||||
git2 = { version = "0.20.4", features = ["vendored-libgit2", "vendored-openssl"] }
|
||||
|
||||
[target.'cfg(not(windows))'.dependencies]
|
||||
openssl = { version = "0.10", features = ["vendored"] }
|
||||
openssl = { version = "0.10", features = ["vendored"] }
|
||||
1
packaging/aur/dcr-git
Submodule
1
packaging/aur/dcr-git
Submodule
Submodule packaging/aur/dcr-git added at 12038a613e
18
packaging/snap/snapcraft.yaml
Normal file
18
packaging/snap/snapcraft.yaml
Normal file
@@ -0,0 +1,18 @@
|
||||
name: dcr
|
||||
base: core22
|
||||
version: '0.6.9'
|
||||
summary: Cargo-like utility to manage C/C++ projects
|
||||
description: |
|
||||
A build tool and package manager for C/C++ projects inspired by Rust's Cargo.
|
||||
|
||||
grade: stable
|
||||
confinement: classic
|
||||
|
||||
apps:
|
||||
dcr:
|
||||
command: bin/dcr
|
||||
|
||||
parts:
|
||||
dcr:
|
||||
plugin: dump
|
||||
source: dist/
|
||||
186
src/cli/build.rs
186
src/cli/build.rs
@@ -69,7 +69,9 @@ pub fn build(args: &[String]) -> i32 {
|
||||
|
||||
if flags.target.is_none() {
|
||||
let config_path = root.join("dcr.toml");
|
||||
if let Ok(config) = Config::open(config_path.to_str().unwrap()) {
|
||||
if let Ok(config) = Config::open(config_path.to_str().unwrap())
|
||||
&& !config.is_workspace_only()
|
||||
{
|
||||
let bt = get_build_string_with_profile(&config, "target", "debug");
|
||||
if !bt.is_empty() {
|
||||
flags.target = Some(bt);
|
||||
@@ -100,6 +102,7 @@ pub fn build(args: &[String]) -> i32 {
|
||||
flags.target.as_deref(),
|
||||
flags.force,
|
||||
flags.verbose,
|
||||
flags.workspace.as_deref(),
|
||||
)
|
||||
}) {
|
||||
Ok(()) => 0,
|
||||
@@ -372,8 +375,13 @@ fn get_build_steps_with_profile(
|
||||
get_build_steps(config, &format!("build.{field}"))
|
||||
}
|
||||
|
||||
fn ensure_target_dirs(items: &[String], profile: &str, target_dir: Option<String>) {
|
||||
if !items.contains(&"target".to_string()) {
|
||||
fn ensure_target_dirs(
|
||||
items: &[String],
|
||||
profile: &str,
|
||||
target_dir: Option<String>,
|
||||
skip_local_target: bool,
|
||||
) {
|
||||
if !skip_local_target && !items.contains(&"target".to_string()) {
|
||||
let _ = fs::create_dir("./target");
|
||||
}
|
||||
if let Some(dir) = &target_dir {
|
||||
@@ -414,8 +422,38 @@ fn build_from_root(
|
||||
target: Option<&str>,
|
||||
force: bool,
|
||||
verbose: bool,
|
||||
workspace: Option<&str>,
|
||||
) -> Result<(), String> {
|
||||
let config = Config::open("./dcr.toml").map_err(|err| err.to_string())?;
|
||||
|
||||
if config.is_workspace_only() {
|
||||
let ws = parse_workspace(&config, profile, target, root)?
|
||||
.ok_or_else(|| "Workspace root has no members defined".to_string())?;
|
||||
let members: Vec<_> = if let Some(filter_name) = workspace {
|
||||
ws.members
|
||||
.into_iter()
|
||||
.filter(|m| m.name == filter_name)
|
||||
.collect()
|
||||
} else {
|
||||
ws.members
|
||||
};
|
||||
if members.is_empty() {
|
||||
return Err("No matching workspace members to build".to_string());
|
||||
}
|
||||
for member in &members {
|
||||
build_project_at(
|
||||
&member.path,
|
||||
profile,
|
||||
target,
|
||||
&[],
|
||||
force,
|
||||
verbose,
|
||||
Some(root),
|
||||
)?;
|
||||
}
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let project_name = get_config_str(&config, "package.name");
|
||||
let project_version = get_config_str(&config, "package.version");
|
||||
|
||||
@@ -454,20 +492,50 @@ fn build_from_root(
|
||||
)
|
||||
);
|
||||
}
|
||||
if let Some(workspace) = parse_workspace(&config, profile, build_target.as_deref(), root)? {
|
||||
build_workspace(&workspace, profile, build_target.as_deref(), force, verbose)?;
|
||||
let excludes: Vec<std::path::PathBuf> =
|
||||
workspace.members.iter().map(|m| m.path.clone()).collect();
|
||||
if let Some(ws) = parse_workspace(&config, profile, build_target.as_deref(), root)? {
|
||||
if let Some(filter_name) = workspace {
|
||||
for member in ws.members.iter().filter(|m| m.name == filter_name) {
|
||||
build_project_at(
|
||||
&member.path,
|
||||
profile,
|
||||
build_target.as_deref(),
|
||||
&[],
|
||||
force,
|
||||
verbose,
|
||||
Some(root),
|
||||
)?;
|
||||
}
|
||||
} else {
|
||||
build_workspace(
|
||||
&ws,
|
||||
profile,
|
||||
build_target.as_deref(),
|
||||
force,
|
||||
verbose,
|
||||
Some(root),
|
||||
)?;
|
||||
let excludes: Vec<std::path::PathBuf> =
|
||||
ws.members.iter().map(|m| m.path.clone()).collect();
|
||||
build_project_at(
|
||||
root,
|
||||
profile,
|
||||
build_target.as_deref(),
|
||||
&excludes,
|
||||
force,
|
||||
verbose,
|
||||
None,
|
||||
)?;
|
||||
}
|
||||
} else {
|
||||
build_project_at(
|
||||
root,
|
||||
profile,
|
||||
build_target.as_deref(),
|
||||
&excludes,
|
||||
&[],
|
||||
force,
|
||||
verbose,
|
||||
None,
|
||||
)?;
|
||||
} else {
|
||||
build_project_at(root, profile, build_target.as_deref(), &[], force, verbose)?;
|
||||
}
|
||||
}
|
||||
let elapsed = ((start_time.elapsed().as_secs_f64() * 100.0).trunc()) / 100.0;
|
||||
@@ -485,9 +553,18 @@ fn build_workspace(
|
||||
target: Option<&str>,
|
||||
force: bool,
|
||||
verbose: bool,
|
||||
workspace_root: Option<&Path>,
|
||||
) -> Result<(), String> {
|
||||
for member in &workspace.members {
|
||||
build_project_at(&member.path, profile, target, &[], force, verbose)?;
|
||||
build_project_at(
|
||||
&member.path,
|
||||
profile,
|
||||
target,
|
||||
&[],
|
||||
force,
|
||||
verbose,
|
||||
workspace_root,
|
||||
)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
@@ -499,6 +576,7 @@ fn build_project_at(
|
||||
exclude_dirs: &[std::path::PathBuf],
|
||||
force: bool,
|
||||
verbose: bool,
|
||||
workspace_root: Option<&Path>,
|
||||
) -> Result<(), String> {
|
||||
with_dir(project_root, || {
|
||||
check_interrupted()?;
|
||||
@@ -506,7 +584,22 @@ fn build_project_at(
|
||||
if !items.contains(&"dcr.toml".to_string()) {
|
||||
return Err("dcr.toml file not found".to_string());
|
||||
}
|
||||
let config = Config::open("./dcr.toml").map_err(|err| err.to_string())?;
|
||||
let mut config = Config::open("./dcr.toml").map_err(|err| err.to_string())?;
|
||||
// Inherit build fields from workspace root if configured
|
||||
if let Some(root) = workspace_root {
|
||||
let has_inherit = config
|
||||
.get("build.inherit")
|
||||
.and_then(|v| v.as_bool())
|
||||
.unwrap_or(false);
|
||||
if has_inherit {
|
||||
let root_path = root.join("dcr.toml");
|
||||
if root_path.is_file() {
|
||||
let parent_config =
|
||||
Config::open(&root_path.to_string_lossy()).map_err(|e| e.to_string())?;
|
||||
config.merge_parent(&parent_config);
|
||||
}
|
||||
}
|
||||
}
|
||||
let project_name = get_config_str(&config, "package.name");
|
||||
let project_version = get_config_str(&config, "package.version");
|
||||
let build_target_config = get_build_string_with_profile(&config, "target", profile);
|
||||
@@ -548,17 +641,6 @@ fn build_project_at(
|
||||
.or_else(|| get_config_opt(&config, "toolchain.rcc"));
|
||||
let mut build_cflags =
|
||||
get_list_with_profile_and_target(&config, "cflags", profile, build_target)?;
|
||||
if let Some(t) = build_target
|
||||
&& !t.trim().is_empty()
|
||||
{
|
||||
let target_flag = format!("--target={}", t.trim());
|
||||
if !build_cflags
|
||||
.iter()
|
||||
.any(|f| f == &target_flag || f.starts_with("--target="))
|
||||
{
|
||||
build_cflags.insert(0, target_flag);
|
||||
}
|
||||
}
|
||||
let mut build_ldflags =
|
||||
get_list_with_profile_and_target(&config, "ldflags", profile, build_target)?;
|
||||
let build_ldscript =
|
||||
@@ -595,11 +677,48 @@ fn build_project_at(
|
||||
tc_cxx.as_deref(),
|
||||
tc_as.as_deref(),
|
||||
);
|
||||
if let Some(t) = build_target
|
||||
&& !t.trim().is_empty()
|
||||
&& resolved_compiler.to_lowercase().contains("clang")
|
||||
{
|
||||
let target_flag = format!("--target={}", t.trim());
|
||||
if !build_cflags
|
||||
.iter()
|
||||
.any(|f| f == &target_flag || f.starts_with("--target="))
|
||||
{
|
||||
build_cflags.insert(0, target_flag);
|
||||
}
|
||||
}
|
||||
let resolved_linker = resolve_tool("DCR_LD", tc_ld.as_deref());
|
||||
let resolved_archiver = resolve_tool("DCR_AR", tc_ar.as_deref());
|
||||
|
||||
let target_dir = build_target.map(|t| format!("target/{t}/{profile}"));
|
||||
ensure_target_dirs(&items, profile, target_dir);
|
||||
let target_dir_binding = match workspace_root {
|
||||
Some(root) => {
|
||||
let target_str = build_target
|
||||
.map(normalize_target_os)
|
||||
.filter(|t| !t.is_empty());
|
||||
let rel: PathBuf = match target_str {
|
||||
Some(ref t) => Path::new("target").join(t).join(profile),
|
||||
None => {
|
||||
let default_dir = if cfg!(target_os = "linux") {
|
||||
let arch = std::env::consts::ARCH;
|
||||
format!("{arch}-unknown-linux-gnu/{profile}")
|
||||
} else {
|
||||
profile.to_string()
|
||||
};
|
||||
Path::new("target").join(&default_dir)
|
||||
}
|
||||
};
|
||||
root.join(&rel).to_string_lossy().to_string()
|
||||
}
|
||||
None => normalize_target(build_target.unwrap_or(""), profile).unwrap_or_default(),
|
||||
};
|
||||
let target_dir = if target_dir_binding.is_empty() {
|
||||
None
|
||||
} else {
|
||||
Some(target_dir_binding.clone())
|
||||
};
|
||||
ensure_target_dirs(&items, profile, target_dir, workspace_root.is_some());
|
||||
|
||||
let deps_table = config.get("dependencies").and_then(|v| v.as_table());
|
||||
let resolved = resolve_deps(&config, profile, build_target, project_root)?;
|
||||
@@ -635,7 +754,15 @@ fn build_project_at(
|
||||
dep_root.display()
|
||||
));
|
||||
}
|
||||
build_project_at(&dep_root, profile, build_target, &[], force, verbose)?;
|
||||
build_project_at(
|
||||
&dep_root,
|
||||
profile,
|
||||
build_target,
|
||||
&[],
|
||||
force,
|
||||
verbose,
|
||||
None,
|
||||
)?;
|
||||
print!(
|
||||
"\r{:100}\r {} {} v{}",
|
||||
"",
|
||||
@@ -724,7 +851,6 @@ fn build_project_at(
|
||||
}
|
||||
}
|
||||
|
||||
let target_dir_binding = normalize_target(build_target.unwrap_or(""), profile);
|
||||
let version_info = parse_version_info(&project_version);
|
||||
let substitute = |s: &str| -> String {
|
||||
s.replace("{profile}", profile)
|
||||
@@ -749,7 +875,11 @@ fn build_project_at(
|
||||
standard: &build_standard,
|
||||
cxx_standard: &build_cxx_standard,
|
||||
target: build_target,
|
||||
target_dir: target_dir_binding.as_deref(),
|
||||
target_dir: if target_dir_binding.is_empty() {
|
||||
None
|
||||
} else {
|
||||
Some(target_dir_binding.as_str())
|
||||
},
|
||||
kind: normalize_kind(&build_kind),
|
||||
platform: normalize_platform(&build_platform),
|
||||
linker: resolved_linker.as_deref(),
|
||||
|
||||
@@ -21,6 +21,7 @@ use crate::utils::log::warn;
|
||||
pub struct BuildRunFlags {
|
||||
pub profile: String,
|
||||
pub target: Option<String>,
|
||||
pub workspace: Option<String>,
|
||||
pub force: bool,
|
||||
pub clean: bool,
|
||||
pub verbose: bool,
|
||||
@@ -29,6 +30,7 @@ pub struct BuildRunFlags {
|
||||
pub fn parse_build_run_flags(args: &[String]) -> Result<BuildRunFlags, i32> {
|
||||
let mut profile = PROFILE.to_string();
|
||||
let mut target = None;
|
||||
let mut workspace = None;
|
||||
let mut force = false;
|
||||
let mut clean = false;
|
||||
let mut verbose = false;
|
||||
@@ -52,6 +54,15 @@ pub fn parse_build_run_flags(args: &[String]) -> Result<BuildRunFlags, i32> {
|
||||
verbose = true;
|
||||
continue;
|
||||
}
|
||||
if candidate == "workspace" {
|
||||
if let Some(w) = iter.next() {
|
||||
workspace = Some(w.clone());
|
||||
} else {
|
||||
warn("--workspace requires a value");
|
||||
return Err(1);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if candidate == "target" {
|
||||
if let Some(t) = iter.next() {
|
||||
target = Some(t.clone());
|
||||
@@ -76,6 +87,7 @@ pub fn parse_build_run_flags(args: &[String]) -> Result<BuildRunFlags, i32> {
|
||||
Ok(BuildRunFlags {
|
||||
profile,
|
||||
target,
|
||||
workspace,
|
||||
force,
|
||||
clean,
|
||||
verbose,
|
||||
|
||||
128
src/cli/run.rs
128
src/cli/run.rs
@@ -24,6 +24,7 @@ use crate::utils::fs::find_project_root;
|
||||
use crate::utils::fs::with_dir;
|
||||
use crate::utils::log::error;
|
||||
use crate::utils::text::{BOLD_GREEN, colored};
|
||||
use std::path::Path;
|
||||
use std::process::Command;
|
||||
|
||||
fn get_run_cmd(
|
||||
@@ -82,18 +83,82 @@ pub fn run(args: &[String]) -> i32 {
|
||||
return 1;
|
||||
}
|
||||
};
|
||||
|
||||
let flags = match parse_build_run_flags(args) {
|
||||
Ok(v) => v,
|
||||
Err(_) => return 1,
|
||||
};
|
||||
|
||||
// Handle workspace-only root: delegate to workspace member
|
||||
if config.is_workspace_only() {
|
||||
let ws = match crate::core::workspace::parse_workspace(
|
||||
&config,
|
||||
&flags.profile,
|
||||
flags.target.as_deref(),
|
||||
&root,
|
||||
) {
|
||||
Ok(Some(ws)) => ws,
|
||||
Ok(None) => {
|
||||
error("Workspace root has no members defined");
|
||||
return 1;
|
||||
}
|
||||
Err(e) => {
|
||||
error(&e);
|
||||
return 1;
|
||||
}
|
||||
};
|
||||
let member = match &flags.workspace {
|
||||
Some(name) => ws.members.iter().find(|m| m.name == *name),
|
||||
None => ws.main_member(),
|
||||
};
|
||||
let member = match member {
|
||||
Some(m) => m,
|
||||
None => {
|
||||
if let Some(name) = &flags.workspace {
|
||||
error(&format!("Workspace member '{name}' not found"));
|
||||
} else {
|
||||
error("No workspace member to run (set `main = true` on one member)");
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
};
|
||||
// Build and run from the member's directory
|
||||
return match with_dir(&member.path, || {
|
||||
run_project(&member.path, &flags, Some(root.as_path()))
|
||||
}) {
|
||||
Ok(code) => code,
|
||||
Err(e) => {
|
||||
error(&e);
|
||||
1
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
match run_project(&root, &flags, None) {
|
||||
Ok(code) => code,
|
||||
Err(e) => {
|
||||
error(&e);
|
||||
1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn run_project(
|
||||
root: &Path,
|
||||
flags: &crate::cli::flags::BuildRunFlags,
|
||||
workspace_root: Option<&Path>,
|
||||
) -> Result<i32, String> {
|
||||
let config =
|
||||
Config::open(root.join("dcr.toml").to_str().unwrap()).map_err(|err| err.to_string())?;
|
||||
|
||||
let project_name: &str = config
|
||||
.get("package.name")
|
||||
.and_then(|v| v.as_str())
|
||||
.unwrap_or("");
|
||||
|
||||
let mut flags = match parse_build_run_flags(args) {
|
||||
Ok(v) => v,
|
||||
Err(_) => return 1,
|
||||
};
|
||||
|
||||
// If no target specified, use default host target for target-specific config
|
||||
if flags.target.is_none() {
|
||||
let mut target = flags.target.clone();
|
||||
if target.is_none() {
|
||||
let default_target = if cfg!(target_os = "linux") {
|
||||
"x86_64-unknown-linux-gnu"
|
||||
} else if cfg!(target_os = "macos") {
|
||||
@@ -103,7 +168,7 @@ pub fn run(args: &[String]) -> i32 {
|
||||
} else {
|
||||
"unknown"
|
||||
};
|
||||
flags.target = Some(default_target.to_string());
|
||||
target = Some(default_target.to_string());
|
||||
}
|
||||
|
||||
let build_kind = config
|
||||
@@ -112,25 +177,30 @@ pub fn run(args: &[String]) -> i32 {
|
||||
.or_else(|| config.get("build.kind").and_then(|v| v.as_str()))
|
||||
.unwrap_or("");
|
||||
|
||||
let normalized_target_dir = flags
|
||||
.target
|
||||
.as_ref()
|
||||
.and_then(|t| crate::cli::build::normalize_target(t, &flags.profile));
|
||||
let normalized_target_dir = match workspace_root {
|
||||
Some(wr) => target
|
||||
.as_ref()
|
||||
.and_then(|t| crate::cli::build::normalize_target(t, &flags.profile))
|
||||
.map(|rel| wr.join(&rel).to_string_lossy().to_string()),
|
||||
None => target
|
||||
.as_ref()
|
||||
.and_then(|t| crate::cli::build::normalize_target(t, &flags.profile)),
|
||||
};
|
||||
|
||||
let version = config
|
||||
.get("package.version")
|
||||
.and_then(|v| v.as_str())
|
||||
.unwrap_or("");
|
||||
let run_cmd = get_run_cmd(&config, &flags.profile, flags.target.as_deref(), version);
|
||||
let run_cmd = get_run_cmd(&config, &flags.profile, target.as_deref(), version);
|
||||
|
||||
let kind = build_kind.trim();
|
||||
if run_cmd.is_none()
|
||||
&& (kind == "staticlib" || kind == "sharedlib" || kind == "efi" || kind == "elf")
|
||||
{
|
||||
error("Cannot run library build");
|
||||
return 1;
|
||||
return Err("Cannot run library build".to_string());
|
||||
}
|
||||
let build_status = build(args);
|
||||
|
||||
let build_status = build(&args_for_build(flags));
|
||||
let bin_path = crate::platform::bin_path(
|
||||
&flags.profile,
|
||||
project_name,
|
||||
@@ -140,15 +210,15 @@ pub fn run(args: &[String]) -> i32 {
|
||||
if let Some(cmd) = run_cmd {
|
||||
println!("\n {} {}", colored("Running", BOLD_GREEN), cmd);
|
||||
println!("--------------------------------");
|
||||
return run_shell(&cmd);
|
||||
return Ok(run_shell(&cmd));
|
||||
}
|
||||
println!("\n {} {}", colored("Running", BOLD_GREEN), bin_path);
|
||||
println!("--------------------------------");
|
||||
return run_binary(
|
||||
return Ok(run_binary(
|
||||
project_name,
|
||||
&flags.profile,
|
||||
normalized_target_dir.as_deref(),
|
||||
);
|
||||
));
|
||||
}
|
||||
|
||||
let fallback_code = if let Some(cmd) = run_cmd {
|
||||
@@ -161,11 +231,27 @@ pub fn run(args: &[String]) -> i32 {
|
||||
)
|
||||
};
|
||||
if fallback_code != 1 {
|
||||
return fallback_code;
|
||||
return Ok(fallback_code);
|
||||
}
|
||||
|
||||
error("Fix errors in the code to run the project");
|
||||
1
|
||||
Err("Fix errors in the code to run the project".to_string())
|
||||
}
|
||||
|
||||
fn args_for_build(flags: &crate::cli::flags::BuildRunFlags) -> Vec<String> {
|
||||
let mut args = Vec::new();
|
||||
args.push(format!("--{}", flags.profile));
|
||||
if let Some(ref target) = flags.target {
|
||||
args.push("--target".to_string());
|
||||
args.push(target.clone());
|
||||
}
|
||||
if let Some(ref name) = flags.workspace {
|
||||
args.push("--workspace".to_string());
|
||||
args.push(name.clone());
|
||||
}
|
||||
if flags.verbose {
|
||||
args.push("--verbose".to_string());
|
||||
}
|
||||
args
|
||||
}
|
||||
|
||||
fn run_shell(cmd: &str) -> i32 {
|
||||
|
||||
@@ -77,8 +77,10 @@ pub struct Config {
|
||||
#[allow(dead_code)]
|
||||
#[derive(Debug, Clone, Deserialize)]
|
||||
pub struct DcrConfig {
|
||||
pub package: PackageConfig,
|
||||
pub build: BuildConfig,
|
||||
#[serde(default)]
|
||||
pub package: Option<PackageConfig>,
|
||||
#[serde(default)]
|
||||
pub build: Option<BuildConfig>,
|
||||
#[serde(default)]
|
||||
pub dependencies: BTreeMap<String, DependencyConfig>,
|
||||
#[serde(default)]
|
||||
@@ -123,6 +125,8 @@ pub struct BuildConfig {
|
||||
pub clean: Vec<String>,
|
||||
#[serde(default)]
|
||||
pub src_disable: Option<bool>,
|
||||
#[serde(default)]
|
||||
pub workspace_only: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize)]
|
||||
@@ -201,13 +205,100 @@ impl Config {
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn package(&self) -> &PackageConfig {
|
||||
&self.typed.package
|
||||
pub fn package(&self) -> Option<&PackageConfig> {
|
||||
self.typed.package.as_ref()
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn build_config(&self) -> &BuildConfig {
|
||||
&self.typed.build
|
||||
pub fn build_config(&self) -> Option<&BuildConfig> {
|
||||
self.typed.build.as_ref()
|
||||
}
|
||||
|
||||
pub fn is_workspace_only(&self) -> bool {
|
||||
self.typed
|
||||
.build
|
||||
.as_ref()
|
||||
.map(|b| b.workspace_only)
|
||||
.unwrap_or(false)
|
||||
&& !self.typed.workspace.is_empty()
|
||||
}
|
||||
|
||||
/// Merge build fields from parent config into self where self has empty/default values.
|
||||
/// Used for workspace member inheritance (build.inherit = true).
|
||||
pub fn merge_parent(&mut self, parent: &Config) {
|
||||
let fields: &[&str] = &[
|
||||
"language",
|
||||
"standard",
|
||||
"cxx_standard",
|
||||
"compiler",
|
||||
"kind",
|
||||
"target",
|
||||
"platform",
|
||||
"cflags",
|
||||
"ldflags",
|
||||
"exclude",
|
||||
"include",
|
||||
"roots",
|
||||
"clean",
|
||||
"src_disable",
|
||||
];
|
||||
let parent_build = match parent.data.get("build").and_then(|v| v.as_table()) {
|
||||
Some(t) => t.clone(),
|
||||
None => return,
|
||||
};
|
||||
|
||||
let self_build = self
|
||||
.data
|
||||
.get("build")
|
||||
.and_then(|v| v.as_table())
|
||||
.cloned()
|
||||
.unwrap_or_default();
|
||||
|
||||
let mut changes: Vec<(String, toml::Value)> = Vec::new();
|
||||
|
||||
for field in fields {
|
||||
let val = match parent_build.get(*field) {
|
||||
Some(v) => v,
|
||||
None => continue,
|
||||
};
|
||||
|
||||
let self_val = self_build.get(*field);
|
||||
let should_inherit = match val {
|
||||
toml::Value::Array(_) => self_val.is_none(),
|
||||
toml::Value::String(_) => self_val
|
||||
.and_then(|v| v.as_str())
|
||||
.map(|s| s.trim().is_empty())
|
||||
.unwrap_or(true),
|
||||
_ => self_val.is_none(),
|
||||
};
|
||||
if should_inherit {
|
||||
changes.push((field.to_string(), val.clone()));
|
||||
}
|
||||
}
|
||||
|
||||
if changes.is_empty() {
|
||||
return;
|
||||
}
|
||||
|
||||
if !self.data.is_table() {
|
||||
let mut m = Map::new();
|
||||
m.insert("build".to_string(), toml::Value::Table(Map::new()));
|
||||
self.data = toml::Value::Table(m);
|
||||
}
|
||||
|
||||
let tbl = self.data.as_table_mut().unwrap();
|
||||
let build_tbl = tbl
|
||||
.entry("build".to_string())
|
||||
.or_insert_with(|| toml::Value::Table(Map::new()));
|
||||
if let Some(build_tbl) = build_tbl.as_table_mut() {
|
||||
for (key, val) in changes {
|
||||
build_tbl.entry(key).or_insert(val);
|
||||
}
|
||||
}
|
||||
|
||||
if let Ok(typed) = parse_typed_config(&self.data) {
|
||||
self.typed = typed;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get(&self, key: &str) -> Option<&Value> {
|
||||
@@ -229,15 +320,29 @@ impl Config {
|
||||
}
|
||||
|
||||
pub fn validate(&self) -> Result<(), ConfigError> {
|
||||
if self.typed.package.name.trim().is_empty() {
|
||||
if self.is_workspace_only() {
|
||||
return self.validate_workspace();
|
||||
}
|
||||
|
||||
let pkg =
|
||||
self.typed.package.as_ref().ok_or_else(|| {
|
||||
ConfigError::Invalid("missing [package] section (required)".into())
|
||||
})?;
|
||||
let build = self
|
||||
.typed
|
||||
.build
|
||||
.as_ref()
|
||||
.ok_or_else(|| ConfigError::Invalid("missing [build] section (required)".into()))?;
|
||||
|
||||
if pkg.name.trim().is_empty() {
|
||||
return Err(ConfigError::Invalid("package.name is empty".into()));
|
||||
}
|
||||
if self.typed.package.version.trim().is_empty() {
|
||||
if pkg.version.trim().is_empty() {
|
||||
return Err(ConfigError::Invalid("package.version is empty".into()));
|
||||
}
|
||||
validate_package_name(&self.typed.package.name)?;
|
||||
validate_package_name(&pkg.name)?;
|
||||
|
||||
if let Some(pkg_type) = &self.typed.package.pkg_type {
|
||||
if let Some(pkg_type) = &pkg.pkg_type {
|
||||
let pkg_type = pkg_type.trim();
|
||||
if !pkg_type.is_empty() && pkg_type != "lib" && pkg_type != "app" && pkg_type != "none"
|
||||
{
|
||||
@@ -247,32 +352,32 @@ impl Config {
|
||||
}
|
||||
}
|
||||
|
||||
validate_language_config(&self.typed.build.language, "build.language")?;
|
||||
if self.typed.build.standard.trim().is_empty() {
|
||||
validate_language_config(&build.language, "build.language")?;
|
||||
if build.standard.trim().is_empty() {
|
||||
return Err(ConfigError::Invalid("build.standard is empty".into()));
|
||||
}
|
||||
if self.typed.build.compiler.trim().is_empty() {
|
||||
if build.compiler.trim().is_empty() {
|
||||
return Err(ConfigError::Invalid("build.compiler is empty".into()));
|
||||
}
|
||||
if let Some(platform) = &self.typed.build.platform
|
||||
if let Some(platform) = &build.platform
|
||||
&& platform.trim().is_empty()
|
||||
{
|
||||
return Err(ConfigError::Invalid("build.platform is empty".into()));
|
||||
}
|
||||
validate_toolchain(self.typed.toolchain.as_ref())?;
|
||||
if let Some(kind) = &self.typed.build.kind {
|
||||
if let Some(kind) = &build.kind {
|
||||
let kind = kind.trim();
|
||||
if !kind.is_empty() && !VALID_KINDS.contains(&kind) {
|
||||
return Err(ConfigError::Invalid("build.kind is invalid".into()));
|
||||
}
|
||||
}
|
||||
validate_string_list(&self.typed.build.exclude, "build.exclude")?;
|
||||
validate_string_list(&self.typed.build.include, "build.include")?;
|
||||
validate_string_list(&self.typed.build.roots, "build.roots")?;
|
||||
validate_string_list(&self.typed.build.clean, "build.clean")?;
|
||||
validate_string_list(&self.typed.build.cflags, "build.cflags")?;
|
||||
validate_string_list(&self.typed.build.ldflags, "build.ldflags")?;
|
||||
if let Some(target) = &self.typed.build.target {
|
||||
validate_string_list(&build.exclude, "build.exclude")?;
|
||||
validate_string_list(&build.include, "build.include")?;
|
||||
validate_string_list(&build.roots, "build.roots")?;
|
||||
validate_string_list(&build.clean, "build.clean")?;
|
||||
validate_string_list(&build.cflags, "build.cflags")?;
|
||||
validate_string_list(&build.ldflags, "build.ldflags")?;
|
||||
if let Some(target) = &build.target {
|
||||
validate_non_empty_string(target, "build.target")?;
|
||||
}
|
||||
for profile in ["release", "debug"] {
|
||||
@@ -824,10 +929,10 @@ mod tests {
|
||||
"[package]\nname = \"typed\"\nversion = \"1.2.3\"\ntype = \"lib\"\n\n[build]\nlanguage = [\"c\", \"c++\"]\nstandard = \"c11\"\ncompiler = \"clang\"\nkind = \"staticlib\"\ncflags = [\"-Wall\"]\n\n[dependencies]\nfoo = \"1.0.0\"\n",
|
||||
);
|
||||
let config = Config::open(&path.to_string_lossy()).unwrap();
|
||||
assert_eq!(config.package().name, "typed");
|
||||
assert_eq!(config.typed().package.version, "1.2.3");
|
||||
assert_eq!(config.build_config().compiler, "clang");
|
||||
assert_eq!(config.build_config().cflags, ["-Wall"]);
|
||||
assert_eq!(config.package().unwrap().name, "typed");
|
||||
assert_eq!(config.typed().package.as_ref().unwrap().version, "1.2.3");
|
||||
assert_eq!(config.build_config().unwrap().compiler, "clang");
|
||||
assert_eq!(config.build_config().unwrap().cflags, ["-Wall"]);
|
||||
assert!(config.typed().dependencies.contains_key("foo"));
|
||||
}
|
||||
|
||||
|
||||
@@ -26,6 +26,7 @@ pub struct WorkspaceMember {
|
||||
pub name: String,
|
||||
pub path: PathBuf,
|
||||
pub deps: Vec<String>,
|
||||
pub main: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
@@ -33,6 +34,15 @@ pub struct Workspace {
|
||||
pub members: Vec<WorkspaceMember>,
|
||||
}
|
||||
|
||||
impl Workspace {
|
||||
pub fn main_member(&self) -> Option<&WorkspaceMember> {
|
||||
self.members
|
||||
.iter()
|
||||
.find(|m| m.main)
|
||||
.or_else(|| self.members.first())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn parse_workspace(
|
||||
config: &Config,
|
||||
profile: &str,
|
||||
@@ -85,6 +95,7 @@ pub fn parse_workspace(
|
||||
name: name.to_string(),
|
||||
path,
|
||||
deps,
|
||||
main: tbl.get("main").and_then(|v| v.as_bool()).unwrap_or(false),
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -198,18 +198,6 @@ fn workspace_build_and_clean_all() {
|
||||
"workspace clean --all --release should succeed"
|
||||
);
|
||||
|
||||
for (name, _) in &members {
|
||||
let member = root.join("src").join(name);
|
||||
let target_dir = "target/x86_64-unknown-linux-gnu";
|
||||
assert!(
|
||||
!member.join(target_dir).join("release").exists(),
|
||||
"member target/x86_64-unknown-linux-gnu/release should be removed"
|
||||
);
|
||||
assert!(
|
||||
member.join(target_dir).join("debug").exists(),
|
||||
"member target/x86_64-unknown-linux-gnu/debug should remain"
|
||||
);
|
||||
}
|
||||
let target_dir = "target/x86_64-unknown-linux-gnu";
|
||||
assert!(
|
||||
!root.join(target_dir).join("release").exists(),
|
||||
|
||||
@@ -280,8 +280,11 @@ fn build_release_profile() {
|
||||
let out = run_dcr_env(&["build", "--release"], &dir, &envs);
|
||||
assert!(out.status.success(), "release build should succeed");
|
||||
assert!(
|
||||
dir.join("target").join("release").is_dir(),
|
||||
"target/release should exist"
|
||||
dir.join("target")
|
||||
.join("x86_64-unknown-linux-gnu")
|
||||
.join("release")
|
||||
.is_dir(),
|
||||
"target/x86_64-unknown-linux-gnu/release should exist"
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user