pisi
This commit is contained in:
parent
9654da5ddd
commit
d2bab3b0d1
4 changed files with 128 additions and 87 deletions
105
cmd/install.go
105
cmd/install.go
|
|
@ -89,7 +89,7 @@ var InstallCmd = &cobra.Command{
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
builtPackage, err := session.buildPackage(target, false, nil)
|
builtPackage, err := session.buildPackageWithFallback(target, false, false, []string{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
@ -245,7 +245,7 @@ func (s *autoBuildSession) refreshBuildEnv() {
|
||||||
s.builder.SetEnvOverride("CMAKE_PREFIX_PATH", joinPathListUnique(cmakePrefixes))
|
s.builder.SetEnvOverride("CMAKE_PREFIX_PATH", joinPathListUnique(cmakePrefixes))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *autoBuildSession) buildPackage(requestName string, asBuildDep bool, stack []string) (string, error) {
|
func (s *autoBuildSession) buildPackageWithFallback(requestName string, asBuildDep bool, allowFailure bool, stack []string) (string, error) {
|
||||||
requestName = normalizePackageName(requestName)
|
requestName = normalizePackageName(requestName)
|
||||||
if requestName == "" {
|
if requestName == "" {
|
||||||
return "", fmt.Errorf("invalid package name")
|
return "", fmt.Errorf("invalid package name")
|
||||||
|
|
@ -270,16 +270,20 @@ func (s *autoBuildSession) buildPackage(requestName string, asBuildDep bool, sta
|
||||||
s.buildingPackages[requestName] = struct{}{}
|
s.buildingPackages[requestName] = struct{}{}
|
||||||
defer delete(s.buildingPackages, requestName)
|
defer delete(s.buildingPackages, requestName)
|
||||||
|
|
||||||
fmt.Printf("Resolving Debian source for %s...\n", requestName)
|
// Resolve source
|
||||||
srcInfo, err := s.resolver.ResolveSource(requestName)
|
srcInfo, err := s.resolver.ResolveSource(requestName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
if !allowFailure {
|
||||||
return "", fmt.Errorf("failed to resolve source for %s: %w", requestName, err)
|
return "", fmt.Errorf("failed to resolve source for %s: %w", requestName, err)
|
||||||
}
|
}
|
||||||
|
fmt.Printf("Warning: failed to resolve source for %s: %v (continuing anyway)\n", requestName, err)
|
||||||
|
return "", nil
|
||||||
|
}
|
||||||
|
|
||||||
rcp := autoRecipeFromDebian(srcInfo)
|
rcp := autoRecipeFromDebian(srcInfo)
|
||||||
normalizedRecipeName := normalizePackageName(rcp.Name)
|
normalizedRecipeName := normalizePackageName(rcp.Name)
|
||||||
if normalizedRecipeName != "" && normalizedRecipeName != requestName {
|
if normalizedRecipeName != "" && normalizedRecipeName != requestName {
|
||||||
// Alias the resolved source package name to the requested name.
|
// Alias resolved source package name to requested name.
|
||||||
if _, exists := s.buildingPackages[normalizedRecipeName]; exists {
|
if _, exists := s.buildingPackages[normalizedRecipeName]; exists {
|
||||||
return "", fmt.Errorf("dependency cycle detected: %s", strings.Join(append(stack, requestName, normalizedRecipeName), " -> "))
|
return "", fmt.Errorf("dependency cycle detected: %s", strings.Join(append(stack, requestName, normalizedRecipeName), " -> "))
|
||||||
}
|
}
|
||||||
|
|
@ -301,52 +305,22 @@ func (s *autoBuildSession) buildPackage(requestName string, asBuildDep bool, sta
|
||||||
}
|
}
|
||||||
bar.finish(false, fmt.Sprintf("%s: failed", rcp.Name))
|
bar.finish(false, fmt.Sprintf("%s: failed", rcp.Name))
|
||||||
|
|
||||||
if !s.autoBuildDeps || attempt == 1 {
|
if !allowFailure {
|
||||||
hint := buildFailureHint(requestName, buildErr)
|
hint := buildFailureHint(requestName, buildErr)
|
||||||
if hint != "" {
|
if hint != "" {
|
||||||
return "", fmt.Errorf("failed to auto-build %s: %w\n%s", requestName, buildErr, hint)
|
return "", fmt.Errorf("failed to auto-build %s: %w\n%s", requestName, buildErr, hint)
|
||||||
}
|
}
|
||||||
return "", fmt.Errorf("failed to auto-build %s: %w", requestName, buildErr)
|
return "", fmt.Errorf("failed to auto-build %s: %w", requestName, buildErr)
|
||||||
}
|
}
|
||||||
|
|
||||||
missingDeps := inferMissingBuildDeps(buildErr)
|
|
||||||
if len(missingDeps) == 0 {
|
|
||||||
hint := buildFailureHint(requestName, buildErr)
|
|
||||||
if hint != "" {
|
|
||||||
return "", fmt.Errorf("failed to auto-build %s: %w\n%s", requestName, buildErr, hint)
|
|
||||||
}
|
|
||||||
return "", fmt.Errorf("failed to auto-build %s: %w", requestName, buildErr)
|
|
||||||
}
|
|
||||||
|
|
||||||
fmt.Printf("Detected missing build dependencies for %s: %s\n", requestName, strings.Join(missingDeps, ", "))
|
|
||||||
for _, dep := range missingDeps {
|
|
||||||
if dep == requestName || dep == normalizedRecipeName {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if _, ready := s.toolDepsReady[dep]; ready {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if err := s.ensureBuildDependency(dep, append(stack, requestName)); err != nil {
|
|
||||||
return "", fmt.Errorf("failed to satisfy build dependency %s for %s: %w", dep, requestName, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fmt.Printf("Retrying build for %s after auto-installing dependencies...\n", requestName)
|
|
||||||
}
|
|
||||||
|
|
||||||
if buildErr != nil {
|
|
||||||
return "", fmt.Errorf("failed to auto-build %s: %w", requestName, buildErr)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
builtPackage := filepath.Join(rcp.GetPackageDir(s.workDir), rcp.GetPackageFileName())
|
builtPackage := filepath.Join(rcp.GetPackageDir(s.workDir), rcp.GetPackageFileName())
|
||||||
fmt.Printf("Built package: %s\n", builtPackage)
|
s.builtPackages[rcp.Name] = builtPackage
|
||||||
|
|
||||||
s.builtPackages[requestName] = builtPackage
|
if buildErr != nil {
|
||||||
if normalizedRecipeName != "" {
|
if !allowFailure {
|
||||||
s.builtPackages[normalizedRecipeName] = builtPackage
|
return "", fmt.Errorf("failed to auto-build %s: %w", requestName, buildErr)
|
||||||
}
|
}
|
||||||
|
|
||||||
if asBuildDep {
|
|
||||||
if err := s.installBuildDependency(requestName, builtPackage); err != nil {
|
if err := s.installBuildDependency(requestName, builtPackage); err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
@ -369,11 +343,11 @@ func (s *autoBuildSession) ensureBuildDependency(dep string, stack []string) err
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
packagePath, err := s.buildPackage(dep, true, stack)
|
fmt.Printf("Installing build dependency %s into %s...\n", dep, s.toolRoot)
|
||||||
|
packagePath, err := s.buildPackageWithFallback(dep, true, false, append(stack, dep))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return fmt.Errorf("failed to build dependency %s: %w", dep, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return s.installBuildDependency(dep, packagePath)
|
return s.installBuildDependency(dep, packagePath)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -700,50 +674,11 @@ func autoRecipeFromDebian(src *debian.SourceInfo) *recipe.Recipe {
|
||||||
version = "0"
|
version = "0"
|
||||||
}
|
}
|
||||||
|
|
||||||
// Map package names to binary names for common packages
|
// Use external install script to avoid shell escaping issues
|
||||||
binaryName := name
|
installCommands := []string{
|
||||||
switch name {
|
"PKGDIR={{pkgdir}} bash /tmp/install-script.sh",
|
||||||
case "lua5.1":
|
|
||||||
binaryName = "lua"
|
|
||||||
case "python3":
|
|
||||||
binaryName = "python3"
|
|
||||||
case "python3-dev":
|
|
||||||
binaryName = "python3-config"
|
|
||||||
case "gcc":
|
|
||||||
binaryName = "gcc"
|
|
||||||
case "make":
|
|
||||||
binaryName = "make"
|
|
||||||
case "git":
|
|
||||||
binaryName = "git"
|
|
||||||
case "cmake":
|
|
||||||
binaryName = "cmake"
|
|
||||||
case "pkgconf":
|
|
||||||
binaryName = "pkgconf"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// More robust install command with proper fallbacks
|
|
||||||
installCmd := fmt.Sprintf(
|
|
||||||
"if [ -f build/cmake_install.cmake ]; then DESTDIR={{pkgdir}} cmake --install build; "+
|
|
||||||
"elif [ -f build/meson-private/coredata.dat ]; then DESTDIR={{pkgdir}} meson install -C build ${ZSVO_MESON_INSTALL_ARGS}; "+
|
|
||||||
"elif [ -f Makefile ] || [ -f makefile ] || [ -f GNUmakefile ]; then make DESTDIR={{pkgdir}} PREFIX=/usr ${ZSVO_MAKE_INSTALL_FLAGS} install; "+
|
|
||||||
"else "+
|
|
||||||
" # Try to find and install binaries manually "+
|
|
||||||
" bin_found=false; "+
|
|
||||||
" for bin_dir in src .; do "+
|
|
||||||
" if [ -f \"$$bin_dir/%s\" ]; then "+
|
|
||||||
" install -Dm755 \"$$bin_dir/%s\" \"{{pkgdir}}/usr/bin/%s\"; "+
|
|
||||||
" bin_found=true; "+
|
|
||||||
" break; "+
|
|
||||||
" fi; "+
|
|
||||||
" done; "+
|
|
||||||
" if [ \"$$bin_found\" = \"false\" ]; then "+
|
|
||||||
" echo \"Warning: No binary found for %s, installing common files\"; "+
|
|
||||||
" mkdir -p \"{{pkgdir}}/usr/bin\" \"{{pkgdir}}/usr/lib\" \"{{pkgdir}}/usr/include\" 2>/dev/null || true; "+
|
|
||||||
" fi; "+
|
|
||||||
"fi",
|
|
||||||
binaryName, binaryName, binaryName, name,
|
|
||||||
)
|
|
||||||
|
|
||||||
return &recipe.Recipe{
|
return &recipe.Recipe{
|
||||||
Name: name,
|
Name: name,
|
||||||
Version: version,
|
Version: version,
|
||||||
|
|
@ -758,7 +693,7 @@ func autoRecipeFromDebian(src *debian.SourceInfo) *recipe.Recipe {
|
||||||
"elif [ -f meson.build ]; then meson setup build --prefix=/usr ${ZSVO_MESON_SETUP_ARGS} && meson compile -C build -j${jobs} ${ZSVO_MESON_COMPILE_ARGS}; " +
|
"elif [ -f meson.build ]; then meson setup build --prefix=/usr ${ZSVO_MESON_SETUP_ARGS} && meson compile -C build -j${jobs} ${ZSVO_MESON_COMPILE_ARGS}; " +
|
||||||
"elif [ -f Makefile ] || [ -f makefile ] || [ -f GNUmakefile ]; then make -j${jobs} ${ZSVO_MAKE_FLAGS}; fi",
|
"elif [ -f Makefile ] || [ -f makefile ] || [ -f GNUmakefile ]; then make -j${jobs} ${ZSVO_MAKE_FLAGS}; fi",
|
||||||
},
|
},
|
||||||
Install: []string{installCmd},
|
Install: installCommands,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
32
install-script.sh
Normal file
32
install-script.sh
Normal file
|
|
@ -0,0 +1,32 @@
|
||||||
|
#!/bin/bash
|
||||||
|
# Simple install script for auto-generated packages
|
||||||
|
set -e
|
||||||
|
|
||||||
|
PKGDIR="$1"
|
||||||
|
|
||||||
|
echo "Installing to $PKGDIR"
|
||||||
|
|
||||||
|
# Try CMake
|
||||||
|
if [ -f build/cmake_install.cmake ]; then
|
||||||
|
echo "Using CMake install"
|
||||||
|
DESTDIR="$PKGDIR" cmake --install build
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Try Meson
|
||||||
|
if [ -f build/meson-private/coredata.dat ]; then
|
||||||
|
echo "Using Meson install"
|
||||||
|
DESTDIR="$PKGDIR" meson install -C build ${ZSVO_MESON_INSTALL_ARGS}
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Try Makefile
|
||||||
|
if [ -f Makefile ] || [ -f makefile ] || [ -f GNUmakefile ]; then
|
||||||
|
echo "Using Makefile install"
|
||||||
|
make DESTDIR="$PKGDIR" PREFIX=/usr install ${ZSVO_MAKE_INSTALL_FLAGS}
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Fallback - create minimal structure in PKGDIR
|
||||||
|
echo "Warning: No standard build system found, installing common directories"
|
||||||
|
mkdir -p "$PKGDIR/usr/bin" "$PKGDIR/usr/lib" "$PKGDIR/usr/include"
|
||||||
41
test-env.dockerfile
Normal file
41
test-env.dockerfile
Normal file
|
|
@ -0,0 +1,41 @@
|
||||||
|
# Test environment for ZSVO on Debian 13
|
||||||
|
FROM debian:13
|
||||||
|
|
||||||
|
# Install basic build tools
|
||||||
|
RUN apt-get update && apt-get install -y \
|
||||||
|
build-essential \
|
||||||
|
cmake \
|
||||||
|
git \
|
||||||
|
make \
|
||||||
|
pkg-config \
|
||||||
|
wget \
|
||||||
|
curl \
|
||||||
|
golang-go \
|
||||||
|
sudo \
|
||||||
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
|
# Create zsvo user with sudo access
|
||||||
|
RUN useradd -m -s /bin/bash -G sudo zsvo
|
||||||
|
RUN echo "zsvo ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers
|
||||||
|
|
||||||
|
# Set working directory
|
||||||
|
WORKDIR /home/zsvo
|
||||||
|
|
||||||
|
# Copy zsvo binary and install script
|
||||||
|
COPY zsvo /usr/local/bin/zsvo
|
||||||
|
COPY install-script.sh /tmp/install-script.sh
|
||||||
|
RUN chmod +x /usr/local/bin/zsvo /tmp/install-script.sh
|
||||||
|
|
||||||
|
# Create necessary directories with proper permissions
|
||||||
|
RUN mkdir -p /tmp/pkg-work /home/zsvo/packages /var/lib/pkgdb && \
|
||||||
|
chown -R zsvo:zsvo /tmp/pkg-work /home/zsvo/packages /var/lib/pkgdb
|
||||||
|
|
||||||
|
# Switch to zsvo user
|
||||||
|
USER zsvo
|
||||||
|
|
||||||
|
# Set environment
|
||||||
|
ENV PATH=/usr/local/bin:/usr/bin:/bin
|
||||||
|
ENV HOME=/home/zsvo
|
||||||
|
|
||||||
|
# Test command
|
||||||
|
CMD ["/bin/bash"]
|
||||||
33
test-linux.sh
Executable file
33
test-linux.sh
Executable file
|
|
@ -0,0 +1,33 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Test script for ZSVO on Debian 13
|
||||||
|
set -e
|
||||||
|
|
||||||
|
echo "🚀 Building ZSVO for Linux AMD64..."
|
||||||
|
GOOS=linux GOARCH=amd64 go build -o zsvo .
|
||||||
|
|
||||||
|
echo "🐧 Building test Docker image..."
|
||||||
|
docker build -f test-env.dockerfile -t zsvo-test .
|
||||||
|
|
||||||
|
echo "🧪 Running tests in container..."
|
||||||
|
docker run --rm -it -v $(pwd)/zsvo:/usr/local/bin/zsvo zsvo-test /bin/bash -c "
|
||||||
|
echo '📋 ZSVO version:'
|
||||||
|
zsvo --help | head -3
|
||||||
|
|
||||||
|
echo ''
|
||||||
|
echo '🔍 Testing help command:'
|
||||||
|
zsvo install --help
|
||||||
|
|
||||||
|
echo ''
|
||||||
|
echo '📦 Testing dry-run with htop:'
|
||||||
|
zsvo install --dry-run htop
|
||||||
|
|
||||||
|
echo ''
|
||||||
|
echo '🎯 Testing neovim installation (this will try to build cmake, git, lua5.1):'
|
||||||
|
zsvo install --dry-run neovim
|
||||||
|
|
||||||
|
echo ''
|
||||||
|
echo '✅ All tests completed!'
|
||||||
|
"
|
||||||
|
|
||||||
|
echo "🎉 Test completed!"
|
||||||
Loading…
Reference in a new issue