Merge pull request #7 from voidvon/master

Support macOS core bundle paths and add Darwin packaging files
This commit is contained in:
AntBlack
2026-04-23 21:56:19 +08:00
committed by GitHub
6 changed files with 205 additions and 0 deletions
+63
View File
@@ -31,6 +31,12 @@ func FindCoreExecutable(baseDir string) (string, string, bool) {
if baseDir == "" {
return "", "", false
}
if directPath, directCandidate, ok := findDirectCoreExecutable(baseDir); ok {
return directPath, directCandidate, true
}
if bundlePath, bundleCandidate, ok := findAppBundleExecutable(baseDir); ok {
return bundlePath, bundleCandidate, true
}
for _, candidate := range CoreExecutableCandidates() {
p := filepath.Join(baseDir, filepath.FromSlash(candidate))
if _, err := os.Stat(p); err == nil {
@@ -39,3 +45,60 @@ func FindCoreExecutable(baseDir string) (string, string, bool) {
}
return "", "", false
}
func findDirectCoreExecutable(path string) (string, string, bool) {
info, err := os.Stat(path)
if err != nil || info.IsDir() {
return "", "", false
}
normalized := filepath.ToSlash(filepath.Clean(path))
for _, candidate := range CoreExecutableCandidates() {
candidatePath := filepath.ToSlash(candidate)
if strings.HasSuffix(normalized, candidatePath) || filepath.Base(normalized) == filepath.Base(candidatePath) {
return path, candidate, true
}
}
return "", "", false
}
func findAppBundleExecutable(path string) (string, string, bool) {
if goruntime.GOOS != "darwin" {
return "", "", false
}
info, err := os.Stat(path)
if err != nil || !info.IsDir() {
return "", "", false
}
normalized := filepath.ToSlash(filepath.Clean(path))
if !strings.HasSuffix(strings.ToLower(normalized), ".app") {
return "", "", false
}
for _, candidate := range CoreExecutableCandidates() {
candidatePath := filepath.ToSlash(candidate)
appMarker := ".app/"
index := strings.Index(strings.ToLower(candidatePath), appMarker)
if index < 0 {
continue
}
if !strings.EqualFold(filepath.Base(normalized), filepath.Base(candidatePath[:index+len(".app")])) {
continue
}
relativeExecutable := candidatePath[index+len(appMarker):]
if relativeExecutable == "" {
continue
}
p := filepath.Join(path, filepath.FromSlash(relativeExecutable))
if _, err := os.Stat(p); err == nil {
return p, candidate, true
}
}
return "", "", false
}
+79
View File
@@ -4,6 +4,7 @@ import (
"ant-chrome/backend/internal/config"
"os"
"path/filepath"
"runtime"
"testing"
)
@@ -103,6 +104,84 @@ func TestResolveChromeBinaryNormalizesWindowsStyleRelativeCorePath(t *testing.T)
}
}
func TestResolveChromeBinaryAcceptsDirectExecutablePath(t *testing.T) {
t.Parallel()
root := t.TempDir()
coreDir := filepath.Join(root, "chrome-direct")
if err := os.MkdirAll(coreDir, 0o755); err != nil {
t.Fatalf("创建内核目录失败: %v", err)
}
exePath := filepath.Join(coreDir, filepath.FromSlash(CoreExecutableCandidates()[0]))
if err := os.MkdirAll(filepath.Dir(exePath), 0o755); err != nil {
t.Fatalf("创建可执行文件目录失败: %v", err)
}
if err := os.WriteFile(exePath, []byte("stub"), 0o755); err != nil {
t.Fatalf("写入可执行文件失败: %v", err)
}
cfg := config.DefaultConfig()
mgr := NewManager(cfg, root)
mgr.CoreDAO = &coreDAOStub{
list: []Core{
{
CoreId: "core-direct",
CoreName: "Chrome Direct",
CorePath: exePath,
IsDefault: true,
},
},
}
got, err := mgr.ResolveChromeBinary(&Profile{})
if err != nil {
t.Fatalf("ResolveChromeBinary 返回错误: %v", err)
}
if got != exePath {
t.Fatalf("ResolveChromeBinary 路径错误: got=%q want=%q", got, exePath)
}
}
func TestResolveChromeBinaryAcceptsDarwinAppBundlePath(t *testing.T) {
t.Parallel()
if runtime.GOOS != "darwin" {
t.Skip("仅验证 darwin .app 路径解析")
}
root := t.TempDir()
appDir := filepath.Join(root, "Chromium.app")
exePath := filepath.Join(appDir, "Contents", "MacOS", "Chromium")
if err := os.MkdirAll(filepath.Dir(exePath), 0o755); err != nil {
t.Fatalf("创建可执行文件目录失败: %v", err)
}
if err := os.WriteFile(exePath, []byte("stub"), 0o755); err != nil {
t.Fatalf("写入可执行文件失败: %v", err)
}
cfg := config.DefaultConfig()
mgr := NewManager(cfg, root)
mgr.CoreDAO = &coreDAOStub{
list: []Core{
{
CoreId: "core-app",
CoreName: "Chromium App",
CorePath: appDir,
IsDefault: true,
},
},
}
got, err := mgr.ResolveChromeBinary(&Profile{})
if err != nil {
t.Fatalf("ResolveChromeBinary 返回错误: %v", err)
}
if got != exePath {
t.Fatalf("ResolveChromeBinary 路径错误: got=%q want=%q", got, exePath)
}
}
func TestCountInstancesByCoreTreatsLegacyDefaultReferenceAsDefault(t *testing.T) {
t.Parallel()
+63
View File
@@ -0,0 +1,63 @@
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleName</key>
<string>{{.Info.ProductName}}</string>
<key>CFBundleExecutable</key>
<string>{{.OutputFilename}}</string>
<key>CFBundleIdentifier</key>
<string>com.wails.{{.Name}}</string>
<key>CFBundleVersion</key>
<string>{{.Info.ProductVersion}}</string>
<key>CFBundleGetInfoString</key>
<string>{{.Info.Comments}}</string>
<key>CFBundleShortVersionString</key>
<string>{{.Info.ProductVersion}}</string>
<key>CFBundleIconFile</key>
<string>iconfile</string>
<key>LSMinimumSystemVersion</key>
<string>10.13.0</string>
<key>NSHighResolutionCapable</key>
<string>true</string>
<key>NSHumanReadableCopyright</key>
<string>{{.Info.Copyright}}</string>
{{if .Info.FileAssociations}}
<key>CFBundleDocumentTypes</key>
<array>
{{range .Info.FileAssociations}}
<dict>
<key>CFBundleTypeExtensions</key>
<array>
<string>{{.Ext}}</string>
</array>
<key>CFBundleTypeName</key>
<string>{{.Name}}</string>
<key>CFBundleTypeRole</key>
<string>{{.Role}}</string>
<key>CFBundleTypeIconFile</key>
<string>{{.IconName}}</string>
</dict>
{{end}}
</array>
{{end}}
{{if .Info.Protocols}}
<key>CFBundleURLTypes</key>
<array>
{{range .Info.Protocols}}
<dict>
<key>CFBundleURLName</key>
<string>com.wails.{{.Scheme}}</string>
<key>CFBundleURLSchemes</key>
<array>
<string>{{.Scheme}}</string>
</array>
<key>CFBundleTypeRole</key>
<string>{{.Role}}</string>
</dict>
{{end}}
</array>
{{end}}
</dict>
</plist>
Vendored Regular → Executable
View File
View File
View File