mirror of
https://github.com/jmorganca/ollama
synced 2025-10-06 00:32:49 +02:00
113 lines
2.8 KiB
Go
113 lines
2.8 KiB
Go
package cmd
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"fmt"
|
|
"log/slog"
|
|
"os"
|
|
"os/exec"
|
|
"path"
|
|
"path/filepath"
|
|
"strings"
|
|
"syscall"
|
|
"unsafe"
|
|
|
|
"github.com/ollama/ollama/api"
|
|
"golang.org/x/sys/windows"
|
|
)
|
|
|
|
const (
|
|
Installer = "OllamaSetup.exe"
|
|
)
|
|
|
|
func startApp(ctx context.Context, client *api.Client) error {
|
|
if len(isProcRunning(Installer)) > 0 {
|
|
return fmt.Errorf("upgrade in progress...")
|
|
}
|
|
AppName := "ollama app.exe"
|
|
exe, err := os.Executable()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
appExe := filepath.Join(filepath.Dir(exe), AppName)
|
|
_, err = os.Stat(appExe)
|
|
if errors.Is(err, os.ErrNotExist) {
|
|
// Try the standard install location
|
|
localAppData := os.Getenv("LOCALAPPDATA")
|
|
appExe = filepath.Join(localAppData, "Ollama", AppName)
|
|
_, err := os.Stat(appExe)
|
|
if errors.Is(err, os.ErrNotExist) {
|
|
// Finally look in the path
|
|
appExe, err = exec.LookPath(AppName)
|
|
if err != nil {
|
|
return errors.New("could not locate ollama app")
|
|
}
|
|
}
|
|
}
|
|
|
|
cmd_path := "c:\\Windows\\system32\\cmd.exe"
|
|
cmd := exec.Command(cmd_path, "/c", appExe, "--hide", "--fast-startup")
|
|
cmd.SysProcAttr = &syscall.SysProcAttr{CreationFlags: 0x08000000, HideWindow: true}
|
|
|
|
cmd.Stdin = strings.NewReader("")
|
|
cmd.Stdout = os.Stdout
|
|
cmd.Stderr = os.Stderr
|
|
|
|
if err := cmd.Start(); err != nil {
|
|
return fmt.Errorf("unable to start ollama app %w", err)
|
|
}
|
|
|
|
if cmd.Process != nil {
|
|
defer cmd.Process.Release() //nolint:errcheck
|
|
}
|
|
return waitForServer(ctx, client)
|
|
}
|
|
|
|
func isProcRunning(procName string) []uint32 {
|
|
pids := make([]uint32, 2048)
|
|
var ret uint32
|
|
if err := windows.EnumProcesses(pids, &ret); err != nil || ret == 0 {
|
|
slog.Debug("failed to check for running installers", "error", err)
|
|
return nil
|
|
}
|
|
if ret > uint32(len(pids)) {
|
|
pids = make([]uint32, ret+10)
|
|
if err := windows.EnumProcesses(pids, &ret); err != nil || ret == 0 {
|
|
slog.Debug("failed to check for running installers", "error", err)
|
|
return nil
|
|
}
|
|
}
|
|
if ret < uint32(len(pids)) {
|
|
pids = pids[:ret]
|
|
}
|
|
var matches []uint32
|
|
for _, pid := range pids {
|
|
if pid == 0 {
|
|
continue
|
|
}
|
|
hProcess, err := windows.OpenProcess(windows.PROCESS_QUERY_INFORMATION|windows.PROCESS_VM_READ, false, pid)
|
|
if err != nil {
|
|
continue
|
|
}
|
|
defer windows.CloseHandle(hProcess)
|
|
var module windows.Handle
|
|
var cbNeeded uint32
|
|
cb := (uint32)(unsafe.Sizeof(module))
|
|
if err := windows.EnumProcessModules(hProcess, &module, cb, &cbNeeded); err != nil {
|
|
continue
|
|
}
|
|
var sz uint32 = 1024 * 8
|
|
moduleName := make([]uint16, sz)
|
|
cb = uint32(len(moduleName)) * (uint32)(unsafe.Sizeof(uint16(0)))
|
|
if err := windows.GetModuleBaseName(hProcess, module, &moduleName[0], cb); err != nil && err != syscall.ERROR_INSUFFICIENT_BUFFER {
|
|
continue
|
|
}
|
|
exeFile := path.Base(strings.ToLower(syscall.UTF16ToString(moduleName)))
|
|
if strings.EqualFold(exeFile, procName) {
|
|
matches = append(matches, pid)
|
|
}
|
|
}
|
|
return matches
|
|
}
|