Skip to content

Instantly share code, notes, and snippets.

@Fronix
Last active October 1, 2024 14:50
Show Gist options
  • Save Fronix/da7b33f92831087c1f4ef3ec4f111754 to your computer and use it in GitHub Desktop.
Save Fronix/da7b33f92831087c1f4ef3ec4f111754 to your computer and use it in GitHub Desktop.
Meilisearch installer/updater for windows
# Provided as is
# Make sure to check the code!
# Folder for Meilisearch should include config.toml, this is not created automatically atm
# Script will require you to have the meilisearch binary exe on the filesystem
# IT WIL NOT FETCH FROM GITHUB
function Show-Menu {
Write-Host "================================="
Write-Host " Meilisearch Management Program"
Write-Host "================================="
Write-Host "1: Install Meilisearch"
Write-Host "2: Update Meilisearch"
Write-Host "3: Exit"
}
# Define the source path for WinSW.exe
$sourceWinSWPath = "C:\winsw\winsw.exe"
# Define the default base URI for Meilisearch
$defaultBaseUri = "http://localhost:7700/"
# Define the base URI for importing the dump
$baseUriImport = "http://localhost:7701/"
function Check-WinSW {
param (
[string]$meilisearchDir
)
# Define the destination path for WinSW.exe in the Meilisearch directory
$winswPath = "$meilisearchDir\winsw.exe"
# Check if WinSW.exe exists in the destination directory
if (-Not (Test-Path -Path $winswPath)) {
# Try to copy from C:\winsw
if (Test-Path -Path $sourceWinSWPath) {
Copy-Item -Path $sourceWinSWPath -Destination $winswPath
Write-Host "Copied WinSW.exe to $meilisearchDir"
} else {
Write-Host "WinSW.exe not found in $meilisearchDir or C:\winsw. Please ensure it is available before proceeding."
Write-Host "Press any key to return to the main menu..."
[void][System.Console]::ReadKey($true) # Waits for the user to press a key
return $false
}
}
return $true
}
function WaitingForUser {
param (
[switch]$ExitProgram # Optional switch parameter to exit the program
)
Write-Host "Press any key to continue..."
[void][System.Console]::ReadKey($true) # Waits for the user to press a key
if ($ExitProgram.IsPresent) {
Write-Host "Exiting the program..."
exit
} else {
return $false
}
}
function Install-Meilisearch {
# Step 1: Ask for the full path of the Meilisearch executable
$meilisearchPath = Read-Host "Enter the full path of the Meilisearch executable (including the executable name)"
# Step 2: Ask for the Meilisearch version
$meilisearchVersion = Read-Host "Enter the Meilisearch version (e.g., v1.10.0)"
# Step 3: Ask for the drive where Meilisearch should be installed
$installDrive = Read-Host "Enter the drive letter where Meilisearch should be installed (e.g., E:)"
# Step 4: Create the Meilisearch folder on the specified drive if it doesn't exist
$meilisearchDir = "$installDrive\Meilisearch"
if (-Not (Test-Path -Path $meilisearchDir)) {
New-Item -Path $meilisearchDir -ItemType Directory
Write-Host "Created directory: $meilisearchDir"
}
# Check if WinSW is installed before proceeding
if (-Not (Check-WinSW -meilisearchDir $meilisearchDir)) {
return
}
# Step 5: Create a version-specific folder within the Meilisearch directory
$versionDir = "$meilisearchDir\$meilisearchVersion"
if (-Not (Test-Path -Path $versionDir)) {
New-Item -Path $versionDir -ItemType Directory
Write-Host "Created directory: $versionDir"
}
# Step 6: Copy the executable to the version directory, rename it, and delete the original
$destinationPath = "$versionDir\meilisearch.exe"
Copy-Item -Path $meilisearchPath -Destination $destinationPath
Write-Host "Copied Meilisearch executable to $destinationPath"
Write-Host "Don't forget to delete the copied file $meilisearchPath"
# Step 7: Setup or update the Meilisearch service using WinSW
Setup-MeilisearchService $meilisearchDir $destinationPath $meilisearchVersion
WaitingForUser
}
function Update-Meilisearch {
# Check if WinSW is installed before proceeding
if (-Not (Check-WinSW)) {
return
}
# Step 1: Ask for the new Meilisearch version
$newVersion = Read-Host "Enter the new Meilisearch version (e.g., v1.10.0)"
# Step 2: Ask for the drive where Meilisearch is installed
$installDrive = Read-Host "Enter the drive letter where Meilisearch is installed (e.g., E:)"
# Step 3: Ask for the full path of the new Meilisearch executable
$newMeilisearchPath = Read-Host "Enter the full path of the new Meilisearch executable (including the executable name)"
# Step 4: Ask for the URL and API key of the Meilisearch instance to update
$meilisearchUrl = Read-Host "Enter the URL of the instance (leave empty for http://localhost:7700)"
if ([string]::IsNullOrEmpty($meilisearchUrl)) {
$meilisearchUrl = $defaultBaseUri
}
$apiKey = Read-Host "Enter the API key for the instance"
$meiliHealth = Check-MeiliHealth -meilisearchUrl $meilisearchUrl
if (-Not $meiliHealth) {
Write-Host "The old meilisearch instance is not running, start the service and try again."
WaitingForUser -ExitProgram
return
}
# Step 5: Update the Meilisearch folder with the new version
$meilisearchDir = "$installDrive\Meilisearch"
$newVersionDir = "$meilisearchDir\$newVersion"
if (-Not (Test-Path -Path $newVersionDir)) {
New-Item -Path $newVersionDir -ItemType Directory
Write-Host "Created directory: $newVersionDir"
}
# Check if WinSW is installed before proceeding
if (-Not (Check-WinSW -meilisearchDir $meilisearchDir)) {
return
}
try {
# Step 6: Copy the new executable to the new version directory, rename it, and delete the original
$destinationPath = "$newVersionDir\meilisearch.exe"
Copy-Item -Path $newMeilisearchPath -Destination $destinationPath
Write-Host "Copied new Meilisearch executable to $destinationPath"
}
catch {
Write-Host "Copy error: $_"
WaitingForUser -ExitProgram
}
# Step 7: Create a dump of the current Meilisearch instance
New-MeiliearchDump -apiKey $apiKey -baseUri $meilisearchUrl
# Step 8: Import the dump into the new Meilisearch instance
Import-MeilisearchDump -dumpDir "$meilisearchDir\dumps" -newMeilisearchPath $newVersionDir
# Remove-Item -Path $newMeilisearchPath
Write-Host "Don't forget to delete the copied file $meilisearchPath"
Read-Host "Import is done, ready to update the service. Press any key to continue..."
# Step 9: Update the Meilisearch service using WinSW
Setup-MeilisearchService $meilisearchDir $destinationPath $newVersion
# Step 10: Optionally, remove the old version directory or keep it for rollback
# Remove-Item -Path "$meilisearchDir\$currentVersion" -Recurse
Write-Host "Old version directory kept for rollback purposes"
WaitingForUser
}
function Check-MeiliHealth {
param (
[string]$meilisearchUrl
)
$headers = @{
"Content-Type" = "application/json"
}
if (-not $meilisearchUrl.EndsWith("/")) {
$meilisearchUrl = $meilisearchUrl + "/"
}
$healthUrl = $meilisearchUrl + "health"
try {
$healthResponse = Invoke-WebRequest -Uri $healthUrl -Method Get -Headers $headers
if ($healthResponse.StatusCode -eq 200) {
Write-Host "Meilisearch is healthy and running!"
return $true
} else {
Write-Host "Meilisearch is not running or healthy. Status code: $($healthResponse.StatusCode)"
return $false
}
}
catch {
return $false
}
}
function New-MeiliearchDump {
param (
[string]$apiKey,
[string]$baseUri
)
# Step 1: Create a dump via Meilisearch API
$headers = @{
"Authorization" = "Bearer $apiKey"
"Content-Type" = "application/json"
}
if (-not $baseUri.EndsWith("/")) {
$baseUri = $baseUri + "/"
}
$dumpsUri = $baseUri + "dumps"
$meiliHealth = Check-MeiliHealth -meilisearchUrl $baseUri
if (-Not $meiliHealth) {
Write-Host "The old meilisearch instance is not running, start the service and try again."
WaitingForUser -ExitProgram
return
}
try {
$dumpResponse = Invoke-RestMethod -Uri $dumpsUri -Method Post -Headers $headers
$taskId = $dumpResponse.taskUid
Write-Host "Dump creation initiated: $($dumpResponse.dumpUid)"
# Step 2: Wait for dump to be ready
while ($true) {
$tasksUri = $baseUri + "tasks/$taskId"
$statusResponse = Invoke-RestMethod -Uri $tasksUri -Method Get -Headers $headers
if ($statusResponse.status -eq "succeeded") {
Write-Host "Dump is ready!"
break
} elseif ($statusResponse.status -eq "failed" -or $statusResponse.status -eq "canceled") {
Write-Host "Dump creation failed!"
return
}
Write-Host "Dump is not ready yet, waiting..."
Start-Sleep -Seconds 5
}
}
catch {
Write-Host "Error creating dump: $_"
WaitingForUser -ExitProgram
}
}
function Import-MeilisearchDump {
param (
[string]$dumpDir,
[string]$newMeilisearchPath
)
$headers = @{
"Content-Type" = "application/json"
}
# Get the latest dump file in the directory
$latestDump = Get-ChildItem -Path $dumpDir | Sort-Object LastWriteTime -Descending | Select-Object -First 1
try {
$baseUri = $baseUriImport
$healthUrl = $baseUri + "health"
# Step 1: Import the dump using Meilisearch binary
Write-Host "Starting dump import using the latest dump ($($latestDump.FullName))"
$meilisearchProcess = Start-Process -FilePath "meilisearch.exe" -WorkingDirectory $newMeilisearchPath -ArgumentList "--db-path", "./meili_db", "--import-dump", $latestDump.FullName, "--http-addr", "localhost:7701" -PassThru
Write-Host "Dump import started.... (Process ID: $($meilisearchProcess.Id))"
Write-Host "Waiting 10 seconds for the instance to start..."
Start-Sleep -Seconds 10 # Wait for the process to start
# Step 2: Wait for the dump to be fully loaded
Write-Host "Waiting for dump import to be processed..."
while ($true) {
try {
# Attempt to make a request to the health endpoint
$healthResponse = Invoke-WebRequest -Uri $healthUrl -Method Get -Headers $headers
# Check if the health response is successful (status code 200)
if ($healthResponse.StatusCode -eq 200) {
Write-Host "Dump import completed successfully! Stopping import instance..."
Stop-Process -Id $meilisearchProcess.Id -Force
break
}
}
catch {
# If there's a connection issue, catch the exception and continue trying
Write-Host "Connection failed, Still processing..."
}
# Wait before retrying
Start-Sleep -Seconds 5
Write-Host "Still processing..."
}
}
catch {
Write-Host "Error importing dump: $_"
WaitingForUser -ExitProgram
}
}
function Setup-MeilisearchService {
param (
[string]$meilisearchDir,
[string]$executablePath,
[string]$meilisearchVersion
)
# Define the service name as static and include the version in the description
$serviceName = "MeiliSearch"
$serviceDescription = "MeiliSearch Service - Version $meilisearchVersion"
$meilisearchConfigPath = "$meilisearchDir\config.toml"
$versionDir = "$meilisearchDir\$meilisearchVersion"
# Create the WinSW XML configuration file for the Meilisearch service with logging settings
$winswConfig = @"
<service>
<id>$serviceName</id>
<name>MeiliSearch</name>
<description>$serviceDescription</description>
<executable>$executablePath</executable>
<logpath>%BASE%\logs</logpath>
<arguments>"--config-file-path" ../config.toml "--db-path" ./meili_db</arguments>
<log mode="roll-by-time">
<pattern>yyyyMMdd</pattern>
</log>
<startmode>automatic</startmode>
<priority>high</priority>
<workingdirectory>$versionDir</workingdirectory>
</service>
"@
$winswConfigPath = "$meilisearchDir\meilisearch.xml"
$winswConfig | Out-File -FilePath $winswConfigPath -Encoding utf8
$winswDir = $meilisearchDir
Write-Host "Created or updated WinSW service configuration file at $winswConfigPath"
# If the service already exists, stop it before updating
if (Get-Service -Name $serviceName -ErrorAction SilentlyContinue) {
# winsw stop $serviceName
& "$winswDir\winsw.exe" stop "$winswDir\meilisearch.xml"
Write-Host "Stopped existing Meilisearch service"
}
# Uninstall old service using WinSW
& "$winswDir\winsw.exe" uninstall "$winswDir\meilisearch.xml"
Write-Host "Uninstalled old Meilisearch service using WinSW"
# Install or update the service using WinSW
& "$winswDir\winsw.exe" install "$winswDir\meilisearch.xml"
Write-Host "Installed new Meilisearch service using WinSW"
# Start the service after installation/update
& "$winswDir\winsw.exe" start "$winswDir\meilisearch.xml"
Write-Host "Started Meilisearch service"
}
function Main {
while ($true) {
Show-Menu
$choice = Read-Host "Select an option"
switch ($choice) {
"1" { Install-Meilisearch }
"2" { Update-Meilisearch }
"3" { Write-Host "Exiting..."; exit }
default { Write-Host "Invalid option. Please try again." }
}
}
}
# Start the program
Main
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment