Private/Install-NuPkgModule.ps1

function Install-NuPkgModule {
    <#
    .SYNOPSIS
        Install a PowerShell module from a NuPkg file.
     
    .PARAMETER PackageInfo
        Hashtable containing package information from Get-NuPkgInfo.
     
    .PARAMETER DestinationPath
        Path where the module should be installed.
     
    .PARAMETER Force
        Force reinstallation even if module already exists.
    #>

    [CmdletBinding()]
    param(
        [Parameter(Mandatory)]
        [hashtable]$PackageInfo,
        
        [Parameter(Mandatory)]
        [string]$DestinationPath,
        
        [switch]$Force
    )
    
    $moduleName = $PackageInfo.Name
    $moduleVersion = $PackageInfo.VersionString
    $nupkgPath = $PackageInfo.FilePath
    
    $moduleInstallPath = Join-Path -Path $DestinationPath -ChildPath $moduleName
    $versionInstallPath = Join-Path -Path $moduleInstallPath -ChildPath $moduleVersion
    
    Write-Host "Installing $moduleName v$moduleVersion..." -ForegroundColor Cyan
    
    # Check if module is already installed
    if (Test-Path -Path $versionInstallPath) {
        if ($Force) {
            Write-Host " [FORCE] Removing existing installation..." -ForegroundColor Yellow
            Remove-Item -Path $versionInstallPath -Recurse -Force
        } else {
            Write-Warning "Module $moduleName v$moduleVersion is already installed. Use -Force to reinstall."
            return $false
        }
    }
    
    try {
        # Create destination directory
        New-Item -Path $versionInstallPath -ItemType Directory -Force | Out-Null
        
        # Create temporary extraction directory
        $tempDir = Join-Path -Path ([System.IO.Path]::GetTempPath()) -ChildPath "NuPkgExtract_$(Get-Random)"
        New-Item -Path $tempDir -ItemType Directory -Force | Out-Null
        
        try {
            Write-Host " [EXTRACT] Extracting package..." -ForegroundColor Gray
            
            # Extract NuPkg (it's a ZIP file)
            Add-Type -AssemblyName System.IO.Compression.FileSystem
            [System.IO.Compression.ZipFile]::ExtractToDirectory($nupkgPath, $tempDir)
            
            # Find the content directory (should contain the module files)
            $contentDirs = @()
            
            # Look for version-specific directory first (e.g., "1.0.9")
            $versionDir = Join-Path -Path $tempDir -ChildPath $moduleVersion
            if (Test-Path -Path $versionDir) {
                $contentDirs += $versionDir
            }
            
            # Look for module name directory
            $moduleDir = Join-Path -Path $tempDir -ChildPath $moduleName
            if (Test-Path -Path $moduleDir) {
                $contentDirs += $moduleDir
            }
            
            # Look for any directory containing .psm1 files
            $psmDirs = Get-ChildItem -Path $tempDir -Directory | Where-Object {
                Get-ChildItem -Path $_.FullName -Filter "*.psm1" -ErrorAction SilentlyContinue
            }
            $contentDirs += $psmDirs.FullName
            
            if (-not $contentDirs) {
                # Fallback: look for .psm1 files in root
                if (Get-ChildItem -Path $tempDir -Filter "*.psm1" -ErrorAction SilentlyContinue) {
                    $contentDirs += $tempDir
                }
            }
            
            if (-not $contentDirs) {
                throw "Could not locate module content in NuPkg. Expected .psm1 files in extraction directory."
            }
            
            # Use the first valid content directory
            $sourceDir = $contentDirs[0]
            Write-Host " [INSTALL] Copying module files from: $sourceDir" -ForegroundColor Gray
            
            # Copy all files from source to destination
            $items = Get-ChildItem -Path $sourceDir -Force
            foreach ($item in $items) {
                $destItem = Join-Path -Path $versionInstallPath -ChildPath $item.Name
                if ($item.PSIsContainer) {
                    Copy-Item -Path $item.FullName -Destination $destItem -Recurse -Force
                } else {
                    Copy-Item -Path $item.FullName -Destination $destItem -Force
                }
            }
            
            # Verify installation
            $manifestPath = Join-Path -Path $versionInstallPath -ChildPath "$moduleName.psd1"
            $moduleFilePath = Join-Path -Path $versionInstallPath -ChildPath "$moduleName.psm1"
            
            if (-not (Test-Path -Path $moduleFilePath)) {
                throw "Module file $moduleName.psm1 not found after installation."
            }
            
            Write-Host " [OK] Module installed successfully" -ForegroundColor Green
            Write-Host " [PATH] $versionInstallPath" -ForegroundColor Gray
            
            # Show installed files
            $installedFiles = Get-ChildItem -Path $versionInstallPath -File | Measure-Object
            Write-Host " [FILES] $($installedFiles.Count) files installed" -ForegroundColor Gray
            
            return $true
            
        } finally {
            # Clean up temp directory
            if (Test-Path -Path $tempDir) {
                Remove-Item -Path $tempDir -Recurse -Force -ErrorAction SilentlyContinue
            }
        }
        
    } catch {
        Write-Error "Failed to install module: $($_.Exception.Message)"
        
        # Clean up partial installation
        if (Test-Path -Path $versionInstallPath) {
            Remove-Item -Path $versionInstallPath -Recurse -Force -ErrorAction SilentlyContinue
        }
        
        return $false
    }
}