feat: windows-devshell
This commit is contained in:
@@ -109,6 +109,9 @@
|
||||
};
|
||||
dbToolPkgs = pkgs.callPackage ./db-tool { inherit self; };
|
||||
linuxDevShellPkgs = pkgs.callPackage ./linux-devshell {};
|
||||
windowsDevShellPkgs = pkgs.callPackage ./windows-devshell {
|
||||
inherit (linuxDevShellPkgs) linux-devshell-standalone;
|
||||
};
|
||||
in {
|
||||
py3-datetime = pkgs.callPackage ./py3-datetime.nix {};
|
||||
py3-marzban = pkgs.callPackage ./py3-marzban.nix { inherit self; };
|
||||
@@ -149,6 +152,7 @@ in {
|
||||
"hectic-inheritance" = dbToolPkgs."hectic-inheritance";
|
||||
"linux-devshell" = linuxDevShellPkgs.linux-devshell;
|
||||
"linux-devshell-standalone" = linuxDevShellPkgs.linux-devshell-standalone;
|
||||
"windows-devshell-standalone" = windowsDevShellPkgs.windows-devshell-standalone;
|
||||
nbt2json = pkgs.callPackage ./nbt2json {};
|
||||
hemar-parser = pkgs.callPackage ./hemar/parser {};
|
||||
AstroTuxLauncher = pkgs.callPackage ./AstroTuxLauncher.nix {};
|
||||
|
||||
26
package/windows-devshell/default.nix
Normal file
26
package/windows-devshell/default.nix
Normal file
@@ -0,0 +1,26 @@
|
||||
{ pkgs, writeTextFile, lib, linux-devshell-standalone }:
|
||||
let
|
||||
psScriptTemplate = builtins.readFile ./windows-devshell.ps1;
|
||||
|
||||
# Get the linux-devshell standalone script content and base64 encode it
|
||||
linuxDevShellBase64 = lib.removeSuffix "\n"
|
||||
(builtins.readFile
|
||||
(pkgs.runCommand "base64-linux-devshell" {}
|
||||
''
|
||||
${pkgs.coreutils}/bin/base64 -w 0 ${linux-devshell-standalone} > $out
|
||||
''));
|
||||
|
||||
# Standalone PowerShell script (single file for Windows)
|
||||
windowsDevShellStandalone = writeTextFile {
|
||||
name = "windows-devshell.ps1";
|
||||
executable = false;
|
||||
text = lib.replaceStrings ["@LINUX_DEVSHELL_BASE64@"] [linuxDevShellBase64] psScriptTemplate;
|
||||
meta = {
|
||||
description = "Standalone windows-devshell PowerShell script (single file)";
|
||||
};
|
||||
};
|
||||
|
||||
in
|
||||
{
|
||||
windows-devshell-standalone = windowsDevShellStandalone;
|
||||
}
|
||||
173
package/windows-devshell/windows-devshell.ps1
Normal file
173
package/windows-devshell/windows-devshell.ps1
Normal file
@@ -0,0 +1,173 @@
|
||||
# windows-devshell.ps1
|
||||
# Install WSL (if needed) and enter Nix development shell
|
||||
|
||||
function Write-Info($msg) {
|
||||
Write-Host "[INFO] $msg" -ForegroundColor Cyan
|
||||
}
|
||||
|
||||
function Write-Success($msg) {
|
||||
Write-Host "[OK] $msg" -ForegroundColor Green
|
||||
}
|
||||
|
||||
function Write-Error($msg) {
|
||||
Write-Host "[ERROR] $msg" -ForegroundColor Red
|
||||
}
|
||||
|
||||
function Write-Warning($msg) {
|
||||
Write-Host "[WARN] $msg" -ForegroundColor Yellow
|
||||
}
|
||||
|
||||
function Test-Admin {
|
||||
$currentPrincipal = New-Object Security.Principal.WindowsPrincipal([Security.Principal.WindowsIdentity]::GetCurrent())
|
||||
return $currentPrincipal.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)
|
||||
}
|
||||
|
||||
# Check if WSL is installed
|
||||
Write-Info "Checking WSL installation..."
|
||||
$wslInstalled = $false
|
||||
try {
|
||||
$wslCheck = wsl --status 2>&1
|
||||
if ($LASTEXITCODE -eq 0) {
|
||||
$wslInstalled = $true
|
||||
Write-Success "WSL is already installed"
|
||||
}
|
||||
} catch {}
|
||||
|
||||
# Check if a distro is installed
|
||||
$distroInstalled = $false
|
||||
if ($wslInstalled) {
|
||||
Write-Info "Checking WSL distributions..."
|
||||
try {
|
||||
$distros = wsl --list --quiet 2>$null
|
||||
if ($distros) {
|
||||
$distroInstalled = $true
|
||||
Write-Success "WSL distribution found"
|
||||
}
|
||||
} catch {}
|
||||
}
|
||||
|
||||
# If WSL or distro is missing, we need admin to install
|
||||
if (-not $wslInstalled -or -not $distroInstalled) {
|
||||
if (-not (Test-Admin)) {
|
||||
Write-Error "WSL setup requires Administrator privileges."
|
||||
Write-Info "Please run PowerShell as Administrator for first-time setup."
|
||||
exit 1
|
||||
}
|
||||
}
|
||||
|
||||
# Install WSL if not present
|
||||
if (-not $wslInstalled) {
|
||||
Write-Info "Installing WSL..."
|
||||
|
||||
Write-Info "Enabling WSL feature..."
|
||||
dism.exe /online /enable-feature /featurename:Microsoft-Windows-Subsystem-Linux /all /norestart | Out-Null
|
||||
|
||||
Write-Info "Enabling Virtual Machine Platform..."
|
||||
dism.exe /online /enable-feature /featurename:VirtualMachinePlatform /all /norestart | Out-Null
|
||||
|
||||
Write-Info "Downloading WSL2 kernel update..."
|
||||
$kernelUrl = "https://wslstorestorage.blob.core.windows.net/wslblob/wsl_update_x64.msi"
|
||||
$kernelInstaller = "$env:TEMP\wsl_update_x64.msi"
|
||||
try {
|
||||
Invoke-WebRequest -Uri $kernelUrl -OutFile $kernelInstaller -UseBasicParsing
|
||||
} catch {
|
||||
Write-Warning "Could not download WSL2 kernel update. Will try to continue..."
|
||||
}
|
||||
|
||||
if (Test-Path $kernelInstaller) {
|
||||
Write-Info "Installing WSL2 kernel update..."
|
||||
Start-Process -FilePath msiexec.exe -ArgumentList "/i", $kernelInstaller, "/quiet", "/norestart" -Wait
|
||||
}
|
||||
|
||||
Write-Info "Setting WSL default version to 2..."
|
||||
wsl --set-default-version 2 2>$null
|
||||
|
||||
Write-Info "Installing WSL core..."
|
||||
wsl --install --no-distribution
|
||||
|
||||
Write-Success "WSL installed. You may need to restart your computer."
|
||||
Write-Info "Please restart and run this script again."
|
||||
exit 0
|
||||
}
|
||||
|
||||
# Install Ubuntu if no distro
|
||||
if (-not $distroInstalled) {
|
||||
Write-Info "No WSL distribution found. Installing Ubuntu..."
|
||||
wsl --install -d Ubuntu --no-launch
|
||||
|
||||
Write-Info "Waiting for Ubuntu installation to complete..."
|
||||
$maxAttempts = 60
|
||||
$attempt = 0
|
||||
while ($attempt -lt $maxAttempts) {
|
||||
Start-Sleep -Seconds 5
|
||||
$attempt++
|
||||
try {
|
||||
$distros = wsl --list --quiet 2>$null
|
||||
if ($distros) {
|
||||
break
|
||||
}
|
||||
} catch {}
|
||||
Write-Info "Waiting... ($attempt/$maxAttempts)"
|
||||
}
|
||||
|
||||
if (-not $distros) {
|
||||
Write-Error "Ubuntu installation timed out. Please check WSL status manually."
|
||||
exit 1
|
||||
}
|
||||
Write-Success "Ubuntu installed"
|
||||
}
|
||||
|
||||
# Check if a distro is installed
|
||||
Write-Info "Checking WSL distributions..."
|
||||
$distros = @()
|
||||
try {
|
||||
$distros = wsl --list --quiet 2>$null
|
||||
} catch {}
|
||||
|
||||
if (-not $distros) {
|
||||
Write-Info "No WSL distribution found. Installing Ubuntu..."
|
||||
wsl --install -d Ubuntu --no-launch
|
||||
|
||||
# Wait for installation
|
||||
Write-Info "Waiting for Ubuntu installation to complete..."
|
||||
$maxAttempts = 60
|
||||
$attempt = 0
|
||||
while ($attempt -lt $maxAttempts) {
|
||||
Start-Sleep -Seconds 5
|
||||
$attempt++
|
||||
try {
|
||||
$distros = wsl --list --quiet 2>$null
|
||||
if ($distros) {
|
||||
break
|
||||
}
|
||||
} catch {}
|
||||
Write-Info "Waiting... ($attempt/$maxAttempts)"
|
||||
}
|
||||
|
||||
if (-not $distros) {
|
||||
Write-Error "Ubuntu installation timed out. Please check WSL status manually."
|
||||
exit 1
|
||||
}
|
||||
Write-Success "Ubuntu installed"
|
||||
} else {
|
||||
Write-Success "WSL distribution found"
|
||||
}
|
||||
|
||||
# Create the linux-devshell script inside WSL
|
||||
Write-Info "Preparing linux-devshell script..."
|
||||
|
||||
$linuxDevShellBase64 = "@LINUX_DEVSHELL_BASE64@"
|
||||
|
||||
$wslTempPath = "/tmp/windows-devshell.sh"
|
||||
$psTempPath = wsl wslpath -w $wslTempPath
|
||||
|
||||
# Decode base64 and write to temp file
|
||||
$decoded = [System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($linuxDevShellBase64))
|
||||
Set-Content -Path $psTempPath -Value $decoded -Encoding UTF8 -NoNewline
|
||||
|
||||
# Make it executable and run
|
||||
Write-Info "Running linux-devshell inside WSL..."
|
||||
Write-Info "This will install Nix (if needed) and enter the development shell."
|
||||
Write-Host ""
|
||||
|
||||
wsl -e bash -c "chmod +x $wslTempPath && exec $wslTempPath"
|
||||
@@ -3,4 +3,5 @@
|
||||
(import ./hemar { inherit system inputs self pkgs; }) //
|
||||
(import (./. + "/sentinèlla") { inherit system inputs self pkgs; }) //
|
||||
(import ./db-tool { inherit system inputs self pkgs; }) //
|
||||
(import ./linux-devshell { inherit system inputs self pkgs; })
|
||||
(import ./linux-devshell { inherit system inputs self pkgs; }) //
|
||||
(import ./windows-devshell { inherit system inputs self pkgs; })
|
||||
|
||||
44
test/package/windows-devshell/default.nix
Normal file
44
test/package/windows-devshell/default.nix
Normal file
@@ -0,0 +1,44 @@
|
||||
{ system, inputs, self, pkgs }:
|
||||
let
|
||||
lib = inputs.nixpkgs.lib;
|
||||
|
||||
windowsDevShellStandalone = self.packages.${system}.windows-devshell-standalone;
|
||||
|
||||
mkTest = testName: testDrv: pkgs.runCommand "windows-devshell-test-${testName}"
|
||||
{
|
||||
nativeBuildInputs = [ pkgs.coreutils pkgs.gnugrep ];
|
||||
windowsDevShellStandalone = windowsDevShellStandalone;
|
||||
} ''
|
||||
${builtins.readFile self.legacyPackages.${system}.helpers.posix-shell.log}
|
||||
test=${testDrv}
|
||||
${builtins.readFile ./launch.sh}
|
||||
mkdir -p "$out"
|
||||
'';
|
||||
|
||||
testDir = builtins.readDir ./test;
|
||||
testDrvs =
|
||||
lib.mapAttrs' (n: v:
|
||||
lib.nameValuePair (lib.removeSuffix ".sh" n) v
|
||||
) (lib.filterAttrs (_: v: v != null)
|
||||
(lib.mapAttrs (n: t:
|
||||
if t == "directory" then
|
||||
pkgs.runCommand "test-${n}" {} ''
|
||||
if ! [ -f ${./test + "/${n}" + /run.sh} ]; then
|
||||
echo "no run.sh in test/${n}"
|
||||
exit 1
|
||||
fi
|
||||
mkdir -p "$out"
|
||||
cp -r ${./test + "/${n}"}/* "$out/"
|
||||
chmod +x "$out/run.sh"
|
||||
''
|
||||
else if lib.hasSuffix ".sh" n then
|
||||
pkgs.runCommand "test-${lib.removeSuffix ".sh" n}" {} ''
|
||||
mkdir -p "$out"
|
||||
install -Dm755 ${./test + "/${n}"} "$out/run.sh"
|
||||
''
|
||||
else
|
||||
null
|
||||
) testDir));
|
||||
|
||||
in
|
||||
(lib.mapAttrs' (name: drv: lib.nameValuePair "windows-${name}" (mkTest "windows-${name}" drv)) testDrvs)
|
||||
3
test/package/windows-devshell/launch.sh
Normal file
3
test/package/windows-devshell/launch.sh
Normal file
@@ -0,0 +1,3 @@
|
||||
set -eu
|
||||
|
||||
. "$test/run.sh"
|
||||
64
test/package/windows-devshell/test/standalone-structure.sh
Normal file
64
test/package/windows-devshell/test/standalone-structure.sh
Normal file
@@ -0,0 +1,64 @@
|
||||
#!/bin/dash
|
||||
set -eu
|
||||
|
||||
log info "Checking windows-devshell standalone script structure..."
|
||||
|
||||
# Check file exists
|
||||
if ! [ -f "${windowsDevShellStandalone}" ]; then
|
||||
log error "windows-devshell standalone script not found"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Check it's a PowerShell script (should NOT have hardcoded #Requires -RunAsAdministrator)
|
||||
if head -1 "${windowsDevShellStandalone}" | grep -q "#Requires -RunAsAdministrator"; then
|
||||
log error "Script should not hardcode #Requires -RunAsAdministrator"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Check it contains base64 placeholder replacement (should be actual base64 now)
|
||||
if grep -q "@LINUX_DEVSHELL_BASE64@" "${windowsDevShellStandalone}"; then
|
||||
log error "Base64 placeholder was not replaced"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Check it contains the base64 decode logic
|
||||
if ! grep -q "FromBase64String" "${windowsDevShellStandalone}"; then
|
||||
log error "Script missing base64 decode logic"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Check it contains WSL installation logic
|
||||
if ! grep -q "wsl --status" "${windowsDevShellStandalone}"; then
|
||||
log error "Script missing WSL status check"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! grep -q "wsl --install" "${windowsDevShellStandalone}"; then
|
||||
log error "Script missing WSL install command"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Check it contains admin check
|
||||
if ! grep -q "Administrator" "${windowsDevShellStandalone}"; then
|
||||
log error "Script missing admin privilege check"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
log success "Standalone script has correct structure"
|
||||
|
||||
# Verify the embedded base64 is valid by checking it's non-empty and only contains base64 chars
|
||||
base64_content=$(grep '^\$linuxDevShellBase64 = ' "${windowsDevShellStandalone}" | sed 's/.*= "//;s/"$//')
|
||||
if [ -z "$base64_content" ]; then
|
||||
log error "Embedded base64 content is empty"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Check base64 content length is reasonable (should be at least a few hundred chars for the linux script)
|
||||
content_len=${#base64_content}
|
||||
if [ "$content_len" -lt 100 ]; then
|
||||
log error "Embedded base64 content too short ($content_len chars)"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
log success "Embedded base64 content looks valid ($content_len chars)"
|
||||
log success "Standalone structure test passed"
|
||||
40
test/package/windows-devshell/test/syntax-check.sh
Normal file
40
test/package/windows-devshell/test/syntax-check.sh
Normal file
@@ -0,0 +1,40 @@
|
||||
#!/bin/dash
|
||||
set -eu
|
||||
|
||||
log info "Checking PowerShell script syntax (basic validation)..."
|
||||
|
||||
# Since we can't run PowerShell in Nix, we do basic structural validation
|
||||
|
||||
# Check for balanced braces
|
||||
open_braces=$(grep -o '{' "${windowsDevShellStandalone}" | wc -l)
|
||||
close_braces=$(grep -o '}' "${windowsDevShellStandalone}" | wc -l)
|
||||
if [ "$open_braces" -ne "$close_braces" ]; then
|
||||
log error "Unbalanced braces: $open_braces open, $close_braces close"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Check for balanced parentheses
|
||||
open_parens=$(grep -o '(' "${windowsDevShellStandalone}" | wc -l)
|
||||
close_parens=$(grep -o ')' "${windowsDevShellStandalone}" | wc -l)
|
||||
if [ "$open_parens" -ne "$close_parens" ]; then
|
||||
log error "Unbalanced parentheses: $open_parens open, $close_parens close"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Check no obvious syntax errors (unclosed strings)
|
||||
# Count quotes - should be even
|
||||
quotes=$(grep -o '"' "${windowsDevShellStandalone}" | wc -l)
|
||||
if [ $((quotes % 2)) -ne 0 ]; then
|
||||
log error "Unbalanced quotes: $quotes total (should be even)"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Check script has reasonable length
|
||||
lines=$(wc -l < "${windowsDevShellStandalone}")
|
||||
if [ "$lines" -lt 50 ]; then
|
||||
log error "Script too short ($lines lines)"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
log success "PowerShell script passes basic structural validation"
|
||||
log success "Script is $lines lines, braces/parentheses/quotes balanced"
|
||||
Reference in New Issue
Block a user