362 lines
9.9 KiB
Go
362 lines
9.9 KiB
Go
package main
|
|
|
|
import (
|
|
"encoding/json"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
)
|
|
|
|
// PackSuggestItem 推荐的一条打包命令。
|
|
type PackSuggestItem struct {
|
|
Name string `json:"name"`
|
|
Cmd string `json:"cmd"`
|
|
}
|
|
|
|
// PackSuggest 根据目录识别出的项目类型与推荐命令。
|
|
type PackSuggest struct {
|
|
Kind string `json:"kind"`
|
|
Label string `json:"label"`
|
|
Items []PackSuggestItem `json:"items"`
|
|
}
|
|
|
|
// SuggestPackCommands 分析项目目录,给出打包/构建推荐命令(本地,不同步)。
|
|
func (a *App) SuggestPackCommands(dir string) PackSuggest {
|
|
return detectPackSuggestions(strings.TrimSpace(dir))
|
|
}
|
|
|
|
func detectPackSuggestions(dir string) PackSuggest {
|
|
out := PackSuggest{Kind: "other", Label: "通用", Items: nil}
|
|
if dir == "" {
|
|
return out
|
|
}
|
|
if st, e := os.Stat(dir); e != nil || !st.IsDir() {
|
|
return out
|
|
}
|
|
|
|
// —— 最具体优先 ——
|
|
if isWails3Project(dir) {
|
|
out.Kind, out.Label = "wails3", "Wails 3"
|
|
out.Items = []PackSuggestItem{
|
|
{Name: "开发热更", Cmd: "wails3 task dev"},
|
|
{Name: "Windows 构建", Cmd: "wails3 task windows:build"},
|
|
{Name: "完整安装包", Cmd: "wails3 task package"},
|
|
{Name: "仅打包后端", Cmd: "wails3 task api:package"},
|
|
}
|
|
return out
|
|
}
|
|
if fileExists(dir, "wails.json") || hasWailsV2Mod(dir) {
|
|
out.Kind, out.Label = "wails", "Wails 2"
|
|
out.Items = []PackSuggestItem{
|
|
{Name: "开发", Cmd: "wails dev"},
|
|
{Name: "生产构建", Cmd: "wails build"},
|
|
{Name: "生产构建(压缩)", Cmd: "wails build -clean -upx"},
|
|
}
|
|
return out
|
|
}
|
|
|
|
if fileExists(dir, "package.json") {
|
|
pm := npmPM(dir)
|
|
pkg := readNPMPackage(dir)
|
|
run := func(script string) string {
|
|
switch pm {
|
|
case "pnpm":
|
|
return "pnpm " + script
|
|
case "yarn":
|
|
return "yarn " + script
|
|
case "bun":
|
|
return "bun run " + script
|
|
default:
|
|
return "npm run " + script
|
|
}
|
|
}
|
|
|
|
if isVbenProject(dir, pkg) {
|
|
out.Kind, out.Label = "vben", "Vben Admin"
|
|
items := []PackSuggestItem{}
|
|
for _, s := range []struct{ name, key string }{
|
|
{"构建", "build"},
|
|
{"构建 Antd", "build:antd"},
|
|
{"构建 Ant Design Vue", "build:ant"},
|
|
{"构建 Element", "build:ele"},
|
|
{"构建 Naive", "build:naive"},
|
|
{"预览", "preview"},
|
|
{"类型检查", "typecheck"},
|
|
} {
|
|
if pkgHasScript(pkg, s.key) {
|
|
items = append(items, PackSuggestItem{Name: s.name, Cmd: run(s.key)})
|
|
}
|
|
}
|
|
if len(items) == 0 {
|
|
items = append(items, PackSuggestItem{Name: "构建", Cmd: run("build")})
|
|
}
|
|
out.Items = items
|
|
return out
|
|
}
|
|
|
|
if isNextProject(dir) {
|
|
out.Kind, out.Label = "next", "Next.js"
|
|
out.Items = packScriptsOr(pkg, run, []string{"build", "export", "start"}, []PackSuggestItem{
|
|
{Name: "生产构建", Cmd: run("build")},
|
|
})
|
|
return out
|
|
}
|
|
if isNuxtProject(dir) {
|
|
out.Kind, out.Label = "nuxt", "Nuxt"
|
|
out.Items = packScriptsOr(pkg, run, []string{"build", "generate", "preview"}, []PackSuggestItem{
|
|
{Name: "生产构建", Cmd: run("build")},
|
|
{Name: "静态生成", Cmd: run("generate")},
|
|
})
|
|
return out
|
|
}
|
|
if isElectronProject(pkg) {
|
|
out.Kind, out.Label = "electron", "Electron"
|
|
out.Items = packScriptsOr(pkg, run, []string{"build", "dist", "package", "make", "pack"}, []PackSuggestItem{
|
|
{Name: "打包", Cmd: run("build")},
|
|
})
|
|
return out
|
|
}
|
|
if isVueProject(dir, pkg) {
|
|
out.Kind, out.Label = "vue", "Vue"
|
|
out.Items = packScriptsOr(pkg, run, []string{"build", "build:prod", "build:pro", "preview"}, []PackSuggestItem{
|
|
{Name: "生产构建", Cmd: run("build")},
|
|
})
|
|
return out
|
|
}
|
|
if isReactProject(pkg) {
|
|
out.Kind, out.Label = "react", "React"
|
|
out.Items = packScriptsOr(pkg, run, []string{"build", "build:prod", "preview"}, []PackSuggestItem{
|
|
{Name: "生产构建", Cmd: run("build")},
|
|
})
|
|
return out
|
|
}
|
|
|
|
out.Kind, out.Label = "node", "Node.js"
|
|
out.Items = collectNPMBuildScripts(pkg, run)
|
|
if len(out.Items) == 0 {
|
|
out.Items = []PackSuggestItem{{Name: "构建", Cmd: run("build")}}
|
|
}
|
|
return out
|
|
}
|
|
|
|
if fileExists(dir, "go.mod") {
|
|
out.Kind, out.Label = "go", "Go"
|
|
name := filepath.Base(dir)
|
|
out.Items = []PackSuggestItem{
|
|
{Name: "编译当前平台", Cmd: "go build -o bin/" + name + " ."},
|
|
{Name: "Linux amd64", Cmd: "set GOOS=linux&& set GOARCH=amd64&& go build -o bin/" + name + " ."},
|
|
{Name: "测试", Cmd: "go test ./..."},
|
|
{Name: "整理依赖", Cmd: "go mod tidy"},
|
|
}
|
|
if fileExists(dir, "Makefile") || fileExists(dir, "makefile") {
|
|
out.Items = append([]PackSuggestItem{
|
|
{Name: "make build", Cmd: "make build"},
|
|
{Name: "make package", Cmd: "make package"},
|
|
}, out.Items...)
|
|
}
|
|
return out
|
|
}
|
|
|
|
if fileExists(dir, "Cargo.toml") {
|
|
out.Kind, out.Label = "rust", "Rust"
|
|
out.Items = []PackSuggestItem{
|
|
{Name: "Release 构建", Cmd: "cargo build --release"},
|
|
{Name: "检查", Cmd: "cargo check"},
|
|
{Name: "测试", Cmd: "cargo test"},
|
|
}
|
|
return out
|
|
}
|
|
|
|
if fileExists(dir, "pom.xml") {
|
|
out.Kind, out.Label = "java", "Java / Maven"
|
|
out.Items = []PackSuggestItem{
|
|
{Name: "打包", Cmd: "mvn -DskipTests package"},
|
|
{Name: "清理打包", Cmd: "mvn clean package -DskipTests"},
|
|
}
|
|
return out
|
|
}
|
|
if fileExists(dir, "build.gradle") || fileExists(dir, "build.gradle.kts") {
|
|
out.Kind, out.Label = "java", "Java / Gradle"
|
|
out.Items = []PackSuggestItem{
|
|
{Name: "构建", Cmd: "gradle build -x test"},
|
|
{Name: "bootJar", Cmd: "gradle bootJar"},
|
|
}
|
|
return out
|
|
}
|
|
|
|
if hasExtInDir(dir, ".csproj") || hasExtInDir(dir, ".sln") {
|
|
out.Kind, out.Label = "dotnet", ".NET"
|
|
out.Items = []PackSuggestItem{
|
|
{Name: "发布", Cmd: "dotnet publish -c Release"},
|
|
{Name: "构建", Cmd: "dotnet build -c Release"},
|
|
}
|
|
return out
|
|
}
|
|
|
|
if fileExists(dir, "composer.json") {
|
|
out.Kind, out.Label = "php", "PHP"
|
|
out.Items = []PackSuggestItem{
|
|
{Name: "安装生产依赖", Cmd: "composer install --no-dev -o"},
|
|
{Name: "优化自动加载", Cmd: "composer dump-autoload -o"},
|
|
}
|
|
return out
|
|
}
|
|
|
|
return out
|
|
}
|
|
|
|
func npmPM(dir string) string {
|
|
if fileExists(dir, "bun.lockb") || fileExists(dir, "bun.lock") {
|
|
return "bun"
|
|
}
|
|
if fileExists(dir, "pnpm-lock.yaml") {
|
|
return "pnpm"
|
|
}
|
|
if fileExists(dir, "yarn.lock") {
|
|
return "yarn"
|
|
}
|
|
return "npm"
|
|
}
|
|
|
|
type npmPkgFull struct {
|
|
Name string `json:"name"`
|
|
Scripts map[string]string `json:"scripts"`
|
|
Dependencies map[string]string `json:"dependencies"`
|
|
DevDependencies map[string]string `json:"devDependencies"`
|
|
}
|
|
|
|
func readNPMPackage(dir string) npmPkgFull {
|
|
var pkg npmPkgFull
|
|
raw, e := os.ReadFile(filepath.Join(dir, "package.json"))
|
|
if e == nil {
|
|
_ = json.Unmarshal(raw, &pkg)
|
|
}
|
|
return pkg
|
|
}
|
|
|
|
func pkgHasScript(pkg npmPkgFull, key string) bool {
|
|
if pkg.Scripts == nil {
|
|
return false
|
|
}
|
|
_, ok := pkg.Scripts[key]
|
|
return ok
|
|
}
|
|
|
|
func pkgHasDep(pkg npmPkgFull, names ...string) bool {
|
|
check := func(m map[string]string) bool {
|
|
for k := range m {
|
|
lk := strings.ToLower(k)
|
|
for _, n := range names {
|
|
if lk == n || strings.Contains(lk, n) {
|
|
return true
|
|
}
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
return check(pkg.Dependencies) || check(pkg.DevDependencies)
|
|
}
|
|
|
|
func isWails3Project(dir string) bool {
|
|
if fileExists(dir, "build/config.yml") && (fileExists(dir, "Taskfile.yml") || fileExists(dir, "Taskfile.yaml")) {
|
|
return true
|
|
}
|
|
if b, e := os.ReadFile(filepath.Join(dir, "go.mod")); e == nil {
|
|
s := string(b)
|
|
if strings.Contains(s, "github.com/wailsapp/wails/v3") {
|
|
return true
|
|
}
|
|
}
|
|
for _, name := range []string{"Taskfile.yml", "Taskfile.yaml"} {
|
|
if b, e := os.ReadFile(filepath.Join(dir, name)); e == nil && strings.Contains(string(b), "wails3") {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
func hasWailsV2Mod(dir string) bool {
|
|
b, e := os.ReadFile(filepath.Join(dir, "go.mod"))
|
|
if e != nil {
|
|
return false
|
|
}
|
|
s := string(b)
|
|
return strings.Contains(s, "github.com/wailsapp/wails/v2")
|
|
}
|
|
|
|
func isVbenProject(dir string, pkg npmPkgFull) bool {
|
|
n := strings.ToLower(pkg.Name)
|
|
if strings.Contains(n, "vben") {
|
|
return true
|
|
}
|
|
if pkgHasDep(pkg, "@vben/", "vben") {
|
|
return true
|
|
}
|
|
if dirExists(dir, "apps/web-antd") || dirExists(dir, "apps/web-ele") || dirExists(dir, "packages/effects") {
|
|
return true
|
|
}
|
|
return false
|
|
}
|
|
|
|
func isNextProject(dir string) bool {
|
|
return fileExists(dir, "next.config.js") || fileExists(dir, "next.config.mjs") || fileExists(dir, "next.config.ts") || dirExists(dir, ".next")
|
|
}
|
|
|
|
func isNuxtProject(dir string) bool {
|
|
return fileExists(dir, "nuxt.config.js") || fileExists(dir, "nuxt.config.ts") || fileExists(dir, "nuxt.config.mjs")
|
|
}
|
|
|
|
func isElectronProject(pkg npmPkgFull) bool {
|
|
return pkgHasDep(pkg, "electron", "electron-builder", "electron-vite")
|
|
}
|
|
|
|
func isVueProject(dir string, pkg npmPkgFull) bool {
|
|
return pkgHasDep(pkg, "vue", "@vitejs/plugin-vue")
|
|
}
|
|
|
|
func isReactProject(pkg npmPkgFull) bool {
|
|
return pkgHasDep(pkg, "react", "react-dom", "next")
|
|
}
|
|
|
|
func packScriptsOr(pkg npmPkgFull, run func(string) string, keys []string, fallback []PackSuggestItem) []PackSuggestItem {
|
|
items := []PackSuggestItem{}
|
|
for _, k := range keys {
|
|
if pkgHasScript(pkg, k) {
|
|
items = append(items, PackSuggestItem{Name: k, Cmd: run(k)})
|
|
}
|
|
}
|
|
if len(items) == 0 {
|
|
return fallback
|
|
}
|
|
return items
|
|
}
|
|
|
|
func collectNPMBuildScripts(pkg npmPkgFull, run func(string) string) []PackSuggestItem {
|
|
if pkg.Scripts == nil {
|
|
return nil
|
|
}
|
|
prefer := []string{"build", "build:prod", "build:pro", "build:release", "package", "dist", "release"}
|
|
var items []PackSuggestItem
|
|
seen := map[string]bool{}
|
|
for _, k := range prefer {
|
|
if pkgHasScript(pkg, k) && !seen[k] {
|
|
seen[k] = true
|
|
items = append(items, PackSuggestItem{Name: k, Cmd: run(k)})
|
|
}
|
|
}
|
|
for k := range pkg.Scripts {
|
|
lk := strings.ToLower(k)
|
|
if seen[k] {
|
|
continue
|
|
}
|
|
if strings.HasPrefix(lk, "build") || strings.HasPrefix(lk, "package") || strings.HasPrefix(lk, "dist") || strings.HasPrefix(lk, "release") {
|
|
seen[k] = true
|
|
items = append(items, PackSuggestItem{Name: k, Cmd: run(k)})
|
|
}
|
|
}
|
|
if len(items) > 10 {
|
|
items = items[:10]
|
|
}
|
|
return items
|
|
}
|