返回 DeepSeek-Reasonix
coordinator_windows.go
根目录 / internal / desktoplauncher / coordinator_windows.go
1 //go:build windows
2
3 package desktoplauncher
4
5 import (
6 "fmt"
7 "io"
8 "os"
9 "os/exec"
10 "path/filepath"
11
12 "reasonix/internal/config"
13 "reasonix/internal/desktopinstance"
14 "reasonix/internal/installlayout"
15 "reasonix/internal/proc"
16 )
17
18 func coordinatedLaunch(root string, args []string) (bool, int) {
19 interactive := os.Getenv("REASONIX_NONINTERACTIVE") != "1"
20 return coordinatedLaunchWith(root, args, interactive, coordinatedLaunchDependencies{
21 classifyLocation: classifyLaunchLocation,
22 launchAndVerify: desktopinstance.LaunchAndVerify,
23 notify: desktopinstance.Notify,
24 logRejected: desktopinstance.LogPortableLocationRejected,
25 stderr: os.Stderr,
26 })
27 }
28
29 type coordinatedLaunchDependencies struct {
30 classifyLocation func(string) (launchLocation, error)
31 launchAndVerify func(string, string, bool, func() error, ...string) error
32 notify func(error)
33 logRejected func(string, string, bool)
34 stderr io.Writer
35 }
36
37 func coordinatedLaunchWith(root string, args []string, interactive bool, deps coordinatedLaunchDependencies) (bool, int) {
38 // Shell-less versioned layouts (pre-shell releases, partial rollbacks)
39 // carry no shell lifecycle to coordinate or verify; launch directly.
40 if !installlayout.HasCurrent(root) || !installlayout.HasActiveShell(root) {
41 return false, 0
42 }
43 home := config.ReasonixHomeDir()
44 if isPortableRoot(root) {
45 location, err := deps.classifyLocation(root)
46 if err != nil {
47 return coordinatedLaunchError(err, interactive, deps)
48 }
49 if location == launchLocationUNC || location == launchLocationRemoteDrive {
50 err := desktopinstance.NewUnsupportedPortableLocationError(string(location))
51 deps.logRejected(home, string(location), interactive)
52 return coordinatedLaunchError(err, interactive, deps)
53 }
54 }
55 err := deps.launchAndVerify(root, home, interactive, func() error {
56 path, err := ResolveDesktopPath(root)
57 if err != nil {
58 return err
59 }
60 cmd := exec.Command(path, StripLegacyLaunchArgs(args)...)
61 proc.HideConsole(cmd)
62 cmd.Dir = root
63 cmd.Stdin, cmd.Stdout, cmd.Stderr = os.Stdin, os.Stdout, os.Stderr
64 if err := cmd.Start(); err != nil {
65 return err
66 }
67 go func() { _ = cmd.Wait() }()
68 return nil
69 }, StripLegacyLaunchArgs(args)...)
70 if err != nil {
71 return coordinatedLaunchError(err, interactive, deps)
72 }
73 return true, 0
74 }
75
76 func coordinatedLaunchError(err error, interactive bool, deps coordinatedLaunchDependencies) (bool, int) {
77 fmt.Fprintln(deps.stderr, err)
78 if interactive {
79 deps.notify(err)
80 }
81 return true, desktopinstance.ExitCode(err)
82 }
83
84 func isPortableRoot(root string) bool {
85 info, err := os.Lstat(filepath.Join(root, installlayout.PortableAliasName()))
86 if err != nil || !info.Mode().IsRegular() || info.Mode()&os.ModeSymlink != 0 {
87 return false
88 }
89 _, err = os.Lstat(filepath.Join(root, "uninstall.exe"))
90 return os.IsNotExist(err)
91 }
92
92 lines GO