This commit is contained in:
itexpert228 2026-03-14 17:31:31 +03:00
parent 9654da5ddd
commit d2bab3b0d1
No known key found for this signature in database
4 changed files with 128 additions and 87 deletions

View file

@ -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
View 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
View 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
View 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!"