diff --git a/app/lifecycle/lifecycle.go b/app/lifecycle/lifecycle.go index 521ed74a..14a85b11 100644 --- a/app/lifecycle/lifecycle.go +++ b/app/lifecycle/lifecycle.go @@ -6,6 +6,8 @@ import ( "log" "log/slog" "os" + "os/signal" + "syscall" "github.com/jmorganca/ollama/app/store" "github.com/jmorganca/ollama/app/tray" @@ -23,12 +25,18 @@ func Run() { } callbacks := t.GetCallbacks() + signals := make(chan os.Signal, 1) + signal.Notify(signals, syscall.SIGINT, syscall.SIGTERM) + go func() { slog.Debug("starting callback loop") for { select { case <-callbacks.Quit: - slog.Debug("QUIT called") + slog.Debug("quit called") + t.Quit() + case <-signals: + slog.Debug("shutting down due to signal") t.Quit() case <-callbacks.Update: err := DoUpgrade(cancel, done) diff --git a/app/lifecycle/server.go b/app/lifecycle/server.go index bc558d24..1cb689a2 100644 --- a/app/lifecycle/server.go +++ b/app/lifecycle/server.go @@ -31,11 +31,15 @@ func getCLIFullPath(command string) string { return cmdPath } } - cmdPath = filepath.Join(".", command) - _, err = os.Stat(cmdPath) + pwd, err := os.Getwd() if err == nil { - return cmdPath + cmdPath = filepath.Join(pwd, command) + _, err = os.Stat(cmdPath) + if err == nil { + return cmdPath + } } + return command } diff --git a/app/lifecycle/updater.go b/app/lifecycle/updater.go index 456e6f9c..da69c327 100644 --- a/app/lifecycle/updater.go +++ b/app/lifecycle/updater.go @@ -23,8 +23,9 @@ import ( ) var ( - UpdateCheckURLBase = "https://ollama.com/api/update" - UpdateDownloaded = false + UpdateCheckURLBase = "https://ollama.com/api/update" + UpdateDownloaded = false + UpdateCheckInterval = 60 * 60 * time.Second ) // TODO - maybe move up to the API package? @@ -112,7 +113,6 @@ func IsNewReleaseAvailable(ctx context.Context) (bool, UpdateResponse) { return true, updateResp } -// Returns true if we downloaded a new update, false if we already had it func DownloadNewRelease(ctx context.Context, updateResp UpdateResponse) error { // Do a head first to check etag info req, err := http.NewRequestWithContext(ctx, http.MethodHead, updateResp.UpdateURL, nil) @@ -144,7 +144,7 @@ func DownloadNewRelease(ctx context.Context, updateResp UpdateResponse) error { // Check to see if we already have it downloaded _, err = os.Stat(stageFilename) if err == nil { - slog.Debug("update already downloaded") + slog.Info("update already downloaded") return nil } @@ -231,7 +231,7 @@ func StartBackgroundUpdaterChecker(ctx context.Context, cb func(string) error) { slog.Debug("stopping background update checker") return default: - time.Sleep(60 * 60 * time.Second) + time.Sleep(UpdateCheckInterval) } } }() diff --git a/app/tray/wintray/menus.go b/app/tray/wintray/menus.go index 40235d47..74defa67 100644 --- a/app/tray/wintray/menus.go +++ b/app/tray/wintray/menus.go @@ -33,27 +33,28 @@ func (t *winTray) initMenus() error { } func (t *winTray) UpdateAvailable(ver string) error { - slog.Debug("updating menu and sending notification for new update") - if err := t.addOrUpdateMenuItem(updatAvailableMenuID, 0, updateAvailableMenuTitle, true); err != nil { - return fmt.Errorf("unable to create menu entries %w", err) - } - if err := t.addOrUpdateMenuItem(updateMenuID, 0, updateMenutTitle, false); err != nil { - return fmt.Errorf("unable to create menu entries %w", err) - } - if err := t.addSeparatorMenuItem(separatorMenuID, 0); err != nil { - return fmt.Errorf("unable to create menu entries %w", err) - } - iconFilePath, err := iconBytesToFilePath(wt.updateIcon) - if err != nil { - return fmt.Errorf("unable to write icon data to temp file: %w", err) - } - if err := wt.setIcon(iconFilePath); err != nil { - return fmt.Errorf("unable to set icon: %w", err) - } - - t.pendingUpdate = true - // Now pop up the notification if !t.updateNotified { + slog.Debug("updating menu and sending notification for new update") + if err := t.addOrUpdateMenuItem(updatAvailableMenuID, 0, updateAvailableMenuTitle, true); err != nil { + return fmt.Errorf("unable to create menu entries %w", err) + } + if err := t.addOrUpdateMenuItem(updateMenuID, 0, updateMenutTitle, false); err != nil { + return fmt.Errorf("unable to create menu entries %w", err) + } + if err := t.addSeparatorMenuItem(separatorMenuID, 0); err != nil { + return fmt.Errorf("unable to create menu entries %w", err) + } + iconFilePath, err := iconBytesToFilePath(wt.updateIcon) + if err != nil { + return fmt.Errorf("unable to write icon data to temp file: %w", err) + } + if err := wt.setIcon(iconFilePath); err != nil { + return fmt.Errorf("unable to set icon: %w", err) + } + t.updateNotified = true + + t.pendingUpdate = true + // Now pop up the notification t.muNID.Lock() defer t.muNID.Unlock() copy(t.nid.InfoTitle[:], windows.StringToUTF16(updateTitle)) @@ -65,7 +66,6 @@ func (t *winTray) UpdateAvailable(ver string) error { if err != nil { return err } - t.updateNotified = true } return nil } diff --git a/llm/generate/gen_windows.ps1 b/llm/generate/gen_windows.ps1 index ba0f954c..e605b528 100644 --- a/llm/generate/gen_windows.ps1 +++ b/llm/generate/gen_windows.ps1 @@ -3,6 +3,7 @@ $ErrorActionPreference = "Stop" function init_vars { + $script:SRC_DIR = $(resolve-path "..\..\") $script:llamacppDir = "../llama.cpp" $script:cmakeDefs = @("-DBUILD_SHARED_LIBS=on", "-DLLAMA_NATIVE=off", "-A", "x64") $script:cmakeTargets = @("ext_server") @@ -33,6 +34,9 @@ function init_vars { } # Note: 10 Windows Kit signtool crashes with GCP's plugin ${script:SignTool}="C:\Program Files (x86)\Windows Kits\8.1\bin\x64\signtool.exe" + if ("${env:KEY_CONTAINER}") { + ${script:OLLAMA_CERT}=$(resolve-path "${script:SRC_DIR}\ollama_inc.crt") + } } function git_module_setup { @@ -102,7 +106,7 @@ function sign { if ("${env:KEY_CONTAINER}") { write-host "Signing ${script:buildDir}/lib/*.dll" foreach ($file in (get-childitem "${script:buildDir}/lib/*.dll")){ - & "${script:SignTool}" sign /v /fd sha256 /t http://timestamp.digicert.com /f "${env:OLLAMA_CERT}" ` + & "${script:SignTool}" sign /v /fd sha256 /t http://timestamp.digicert.com /f "${script:OLLAMA_CERT}" ` /csp "Google Cloud KMS Provider" /kc "${env:KEY_CONTAINER}" $file if ($LASTEXITCODE -ne 0) { exit($LASTEXITCODE)} } diff --git a/scripts/build_windows.ps1 b/scripts/build_windows.ps1 index 10052590..835ed774 100644 --- a/scripts/build_windows.ps1 +++ b/scripts/build_windows.ps1 @@ -38,7 +38,7 @@ function checkEnv() { # Check for signing key if ("${env:KEY_CONTAINER}") { - ${env:OLLAMA_CERT}=$(resolve-path "${script:SRC_DIR}\ollama_inc.crt") + ${script:OLLAMA_CERT}=$(resolve-path "${script:SRC_DIR}\ollama_inc.crt") Write-host "Code signing enabled" # Note: 10 Windows Kit signtool crashes with GCP's plugin ${script:SignTool}="C:\Program Files (x86)\Windows Kits\8.1\bin\x64\signtool.exe" @@ -56,7 +56,7 @@ function buildOllama() { & go build "-ldflags=-w -s ""-X=github.com/jmorganca/ollama/version.Version=$script:VERSION"" ""-X=github.com/jmorganca/ollama/server.mode=release""" . if ($LASTEXITCODE -ne 0) { exit($LASTEXITCODE)} if ("${env:KEY_CONTAINER}") { - & "${script:SignTool}" sign /v /fd sha256 /t http://timestamp.digicert.com /f "${env:OLLAMA_CERT}" ` + & "${script:SignTool}" sign /v /fd sha256 /t http://timestamp.digicert.com /f "${script:OLLAMA_CERT}" ` /csp "Google Cloud KMS Provider" /kc ${env:KEY_CONTAINER} ollama.exe if ($LASTEXITCODE -ne 0) { exit($LASTEXITCODE)} } @@ -70,7 +70,7 @@ function buildApp() { & go build "-ldflags=-H windowsgui -w -s ""-X=github.com/jmorganca/ollama/version.Version=$script:VERSION"" ""-X=github.com/jmorganca/ollama/server.mode=release""" . if ($LASTEXITCODE -ne 0) { exit($LASTEXITCODE)} if ("${env:KEY_CONTAINER}") { - & "${script:SignTool}" sign /v /fd sha256 /t http://timestamp.digicert.com /f "${env:OLLAMA_CERT}" ` + & "${script:SignTool}" sign /v /fd sha256 /t http://timestamp.digicert.com /f "${script:OLLAMA_CERT}" ` /csp "Google Cloud KMS Provider" /kc ${env:KEY_CONTAINER} app.exe if ($LASTEXITCODE -ne 0) { exit($LASTEXITCODE)} } @@ -97,7 +97,7 @@ function gatherDependencies() { write-host "about to sign" foreach ($file in (get-childitem "${script:DEPS_DIR}/cu*.dll") + @("${script:SRC_DIR}\dist\ollama_welcome.ps1")){ write-host "signing $file" - & "${script:SignTool}" sign /v /fd sha256 /t http://timestamp.digicert.com /f "${env:OLLAMA_CERT}" ` + & "${script:SignTool}" sign /v /fd sha256 /t http://timestamp.digicert.com /f "${script:OLLAMA_CERT}" ` /csp "Google Cloud KMS Provider" /kc ${env:KEY_CONTAINER} $file if ($LASTEXITCODE -ne 0) { exit($LASTEXITCODE)} } @@ -110,7 +110,7 @@ function buildInstaller() { cd "${script:SRC_DIR}\app" $env:PKG_VERSION=$script:PKG_VERSION if ("${env:KEY_CONTAINER}") { - & "${script:INNO_SETUP_DIR}\ISCC.exe" /SMySignTool="${script:SignTool} sign /fd sha256 /t http://timestamp.digicert.com /f ${env:OLLAMA_CERT} /csp `$qGoogle Cloud KMS Provider`$q /kc ${env:KEY_CONTAINER} `$f" .\ollama.iss + & "${script:INNO_SETUP_DIR}\ISCC.exe" /SMySignTool="${script:SignTool} sign /fd sha256 /t http://timestamp.digicert.com /f ${script:OLLAMA_CERT} /csp `$qGoogle Cloud KMS Provider`$q /kc ${env:KEY_CONTAINER} `$f" .\ollama.iss } else { & "${script:INNO_SETUP_DIR}\ISCC.exe" .\ollama.iss }