diff --git a/README.md b/README.md index 9500e8ae..b695c067 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,7 @@ Netsuke currently requires: ### Installation -To install from crates.io: +Netsuke v0.1.0 is available from crates.io: @@ -45,6 +45,23 @@ To install from crates.io: cargo install netsuke ``` +Pre-built installers are available from the +[v0.1.0 GitHub release](https://github.com/leynos/netsuke/releases/tag/v0.1.0): + +| Platform | Architectures | Packages | +| -------- | ------------------------------------ | -------------------------------- | +| Linux | x86-64 (`amd64`) and Arm64 (`arm64`) | Debian (`.deb`) and RPM (`.rpm`) | +| macOS | Intel x86-64 and Apple silicon Arm64 | Installer package (`.pkg`) | +| Windows | x64 and Arm64 | Windows Installer (`.msi`) | + +The Linux packages install the `netsuke` manual page and declare `ninja-build` +as a dependency. Ninja must be installed separately when using the macOS or +Windows installer. The Windows MSI installs to `C:\Program Files\netsuke` and +does not update `PATH`. SHA-256 checksum files accompany standalone binaries +and staged help and licence files. Installer packages do not have checksum +sidecars in v0.1.0. See the [user's guide](docs/users-guide.md#install-netsuke) +for platform-specific commands and Windows setup. + To install the current source checkout with Cargo: @@ -110,9 +127,8 @@ The core build-system compiler is implemented: - unit, behavioural, integration, property, snapshot, and initial Kani verification coverage. -Release automation is configured to build packages for Linux, macOS, and -Windows, including platform help artefacts. v0.1.0 will be the first public -release of this work. +The v0.1.0 release provides packages for Linux, macOS, and Windows, including +platform help artefacts. It is the first public release of this work. ______________________________________________________________________ diff --git a/docs/users-guide.md b/docs/users-guide.md index cd142a9f..fa188a4b 100644 --- a/docs/users-guide.md +++ b/docs/users-guide.md @@ -13,7 +13,7 @@ change before 1.0. Pin the Netsuke version in automated workflows. Netsuke requires [Ninja](https://ninja-build.org/) on `PATH`. A source build also requires Rust 1.89 or later. -To install a published release from crates.io: +Netsuke v0.1.0 is available from crates.io: @@ -21,6 +21,36 @@ To install a published release from crates.io: cargo install netsuke ``` +Pre-built installers are available from the +[v0.1.0 GitHub release](https://github.com/leynos/netsuke/releases/tag/v0.1.0): + +| Platform | Architectures | Packages | +| -------- | ------------------------------------ | -------------------------------- | +| Linux | x86-64 (`amd64`) and Arm64 (`arm64`) | Debian (`.deb`) and RPM (`.rpm`) | +| macOS | Intel x86-64 and Apple silicon Arm64 | Installer package (`.pkg`) | +| Windows | x64 and Arm64 | Windows Installer (`.msi`) | + +Download the package for the host architecture, then install it with the +platform tool. Replace `PACKAGE` with the downloaded filename: + +- Debian or Ubuntu: `sudo apt install ./PACKAGE.deb` +- Fedora, Rocky Linux, or another RPM-based distribution: + `sudo dnf install ./PACKAGE.rpm` +- macOS: `sudo installer -pkg ./PACKAGE.pkg -target /` +- Windows: `msiexec.exe /i PACKAGE.msi` + +The Linux packages install the binary under `/usr/bin`, add the `netsuke.1` +manual page and declare `ninja-build` as a dependency. The macOS packages +install the binary under `/usr/local/bin`, along with the manual page and +licence. Ninja must be installed separately when using the macOS or Windows +installer. The Windows MSI installs to `C:\Program Files\netsuke` and does not +update `PATH`. + +SHA-256 checksum files accompany standalone binaries and staged help and +licence files. Installer packages do not have checksum sidecars in v0.1.0. +Windows PowerShell help files are published beside each MSI as sidecar +artefacts rather than embedded in the installer. + To install the current source checkout with Cargo: @@ -31,9 +61,80 @@ cd netsuke cargo install --path . ``` -Release archives contain platform-specific packages and help artefacts. Unix -archives include a `netsuke.1` manual page. Windows archives include PowerShell -external help: +### Complete Windows setup + +The MSI does not add its installation directory to `PATH`. Add it to the +current user's persistent `PATH`, update the current PowerShell session, then +verify that the command resolves: + + + +```powershell +$netsukeDirectory = Join-Path $env:ProgramFiles 'netsuke' +$userPath = [Environment]::GetEnvironmentVariable('Path', 'User') +$userEntries = @($userPath -split ';' | Where-Object { $_ }) +if ($userEntries -notcontains $netsukeDirectory) { + $newUserPath = (($userEntries + $netsukeDirectory) -join ';') + [Environment]::SetEnvironmentVariable('Path', $newUserPath, 'User') +} +if (($env:Path -split ';') -notcontains $netsukeDirectory) { + $env:Path = "$env:Path;$netsukeDirectory" +} +netsuke --version +``` + +The release publishes PowerShell help separately for each Windows architecture. +The following script downloads the matching module script, manifest, Microsoft +Assistance Markup Language (MAML) help, and about-help file. It then restores +the versioned module layout under the current user's standard PowerShell module +directory and imports the module. Set `$architecture` to match the downloaded +MSI: + + + +```powershell +$architecture = 'amd64' # Use 'arm64' for the Arm64 MSI. +$releaseUri = 'https://api.github.com/repos/leynos/netsuke/releases/tags/v0.1.0' +$release = Invoke-RestMethod -Uri $releaseUri + +$documents = [Environment]::GetFolderPath('MyDocuments') +$editionDirectory = if ($PSVersionTable.PSEdition -eq 'Desktop') { + 'WindowsPowerShell' +} else { + 'PowerShell' +} +$moduleRoot = Join-Path $documents "$editionDirectory\Modules" +$moduleDirectory = Join-Path $moduleRoot 'Netsuke\0.1.0' +$helpDirectory = Join-Path $moduleDirectory 'en-US' +New-Item -ItemType Directory -Path $helpDirectory -Force | Out-Null + +$patterns = @{ + 'Netsuke.psm1' = '*Netsuke.psm1' + 'Netsuke.psd1' = '*Netsuke.psd1' + 'Netsuke-help.xml' = '*en-US-Netsuke-help.xml' + 'about_Netsuke.help.txt' = '*en-US-about_Netsuke.help.txt' +} +$localizedFiles = @('Netsuke-help.xml', 'about_Netsuke.help.txt') +foreach ($fileName in $patterns.Keys) { + $pattern = "*windows-$architecture*$($patterns[$fileName])" + $asset = $release.assets | Where-Object { $_.name -like $pattern } | Select-Object -First 1 + if ($null -eq $asset) { + throw "Release asset not found: $pattern" + } + $destinationDirectory = if ($localizedFiles -contains $fileName) { + $helpDirectory + } else { + $moduleDirectory + } + $destination = Join-Path $destinationDirectory $fileName + Invoke-WebRequest -Uri $asset.browser_download_url -OutFile $destination -UseBasicParsing +} + +Import-Module (Join-Path $moduleDirectory 'Netsuke.psd1') -Force +``` + +The versioned directory is discoverable in later PowerShell sessions. After the +import, inspect the external help with: diff --git a/tests/documentation_examples_tests.rs b/tests/documentation_examples_tests.rs index 4f6d65a3..b6618336 100644 --- a/tests/documentation_examples_tests.rs +++ b/tests/documentation_examples_tests.rs @@ -34,6 +34,8 @@ const EXPECTED_EXAMPLE_IDS: &[&str] = &[ "guide-source-install", "guide-utility-commands", "guide-windows-help", + "guide-windows-help-install", + "guide-windows-path", "readme-crates-io-install", "readme-first-build-commands", "readme-first-build-manifest", @@ -153,15 +155,26 @@ fn installation_examples_match_source_and_release_contracts() -> Result<()> { let readme_release = documented_example("readme-crates-io-install")?; let guide_release = documented_example("guide-crates-io-install")?; let expected_release = "cargo install netsuke\n"; - ensure!( - readme_release.body == expected_release, - "README crates.io install drifted" - ); - ensure!( - guide_release.body == expected_release, - "user's guide crates.io install drifted" - ); - + ensure!(readme_release.body == expected_release, "README drifted"); + ensure!(guide_release.body == expected_release, "user guide drifted"); + let expected_release_details = [ + "https://github.com/leynos/netsuke/releases/tag/v0.1.0", + "Debian (`.deb`) and RPM (`.rpm`)", + "Installer package (`.pkg`)", + "Windows Installer (`.msi`)", + "x86-64 (`amd64`) and Arm64 (`arm64`)", + "Installer packages do not have checksum", + "The Windows MSI installs to `C:\\Program Files\\netsuke`", + ]; + for path in ["README.md", "docs/users-guide.md"] { + let document = test_fs::read_to_string(path).with_context(|| format!("read {path}"))?; + for expected in expected_release_details { + ensure!( + document.contains(expected), + "{path} should document v0.1.0 release detail: {expected}" + ); + } + } let readme = documented_example("readme-source-install")?; let guide = documented_example("guide-source-install")?; let expected = concat!( @@ -170,15 +183,33 @@ fn installation_examples_match_source_and_release_contracts() -> Result<()> { "cargo install --path .\n" ); ensure!(readme.body == expected, "README source install drifted"); + ensure!(guide.body == expected, "user guide source install drifted"); + let windows = documented_example("guide-windows-help")?; + ensure!(windows.body == "Get-Help Netsuke -Full\n", "help drifted"); + let windows_path = documented_example("guide-windows-path")?; + let windows_path_fragments = [ + "SetEnvironmentVariable", + "$netsukeDirectory", + "SetEnvironmentVariable('Path', $newUserPath, 'User')", + ]; ensure!( - guide.body == expected, - "user's guide source install drifted" + windows_path_fragments + .into_iter() + .all(|fragment| windows_path.body.contains(fragment)), + "Windows PATH setup should persist the MSI installation directory" ); - - let windows = documented_example("guide-windows-help")?; + let windows_help_install = documented_example("guide-windows-help-install")?; + let windows_help_fragments = [ + "Import-Module", + "$moduleDirectory = Join-Path $moduleRoot 'Netsuke\\0.1.0'", + "Import-Module (Join-Path $moduleDirectory 'Netsuke.psd1')", + "*windows-$architecture*", + ]; ensure!( - windows.body == "Get-Help Netsuke -Full\n", - "PowerShell help command drifted" + windows_help_fragments + .into_iter() + .all(|fragment| windows_help_install.body.contains(fragment)), + "Windows help setup should import the downloaded sidecars" ); let staging = test_fs::read_to_string(".github/release-staging.toml") .context("read release staging configuration")?;