mirror of
https://github.com/0xJacky/nginx-ui.git
synced 2026-06-19 07:36:59 +00:00
fix: improve error handling and path resolution in license generation
This commit is contained in:
Binary file not shown.
@@ -34,10 +34,16 @@ type ComponentInfo struct {
|
||||
func main() {
|
||||
log.Println("Generating license information...")
|
||||
|
||||
repoRoot, err := locateRepoRoot()
|
||||
if err != nil {
|
||||
log.Fatalf("Error locating repository root: %v", err)
|
||||
}
|
||||
log.Printf("INFO: Repository root resolved to %s", repoRoot)
|
||||
|
||||
var info ComponentInfo
|
||||
|
||||
// Generate backend licenses
|
||||
backendLicenses, err := generateBackendLicenses()
|
||||
backendLicenses, err := generateBackendLicenses(repoRoot)
|
||||
if err != nil {
|
||||
log.Printf("Error generating backend licenses: %v", err)
|
||||
} else {
|
||||
@@ -46,7 +52,7 @@ func main() {
|
||||
}
|
||||
|
||||
// Generate frontend licenses
|
||||
frontendLicenses, err := generateFrontendLicenses()
|
||||
frontendLicenses, err := generateFrontendLicenses(repoRoot)
|
||||
if err != nil {
|
||||
log.Printf("Error generating frontend licenses: %v", err)
|
||||
} else {
|
||||
@@ -83,7 +89,7 @@ func main() {
|
||||
compressed.Len(), float64(compressed.Len())/float64(len(jsonData))*100)
|
||||
|
||||
// Write compressed data to file
|
||||
outputPath := "internal/license/licenses.xz"
|
||||
outputPath := filepath.Join(repoRoot, "internal", "license", "licenses.xz")
|
||||
log.Printf("INFO: Writing compressed data to %s", outputPath)
|
||||
err = os.MkdirAll(filepath.Dir(outputPath), 0755)
|
||||
if err != nil {
|
||||
@@ -103,16 +109,19 @@ func main() {
|
||||
log.Printf(" - Output file: %s", outputPath)
|
||||
}
|
||||
|
||||
func generateBackendLicenses() ([]License, error) {
|
||||
func generateBackendLicenses(repoRoot string) ([]License, error) {
|
||||
var licenses []License
|
||||
|
||||
log.Println("INFO: Collecting backend Go modules...")
|
||||
|
||||
// Read go.mod file directly
|
||||
goModPath := "go.mod"
|
||||
goModPath := filepath.Join(repoRoot, "go.mod")
|
||||
if _, err := os.Stat(goModPath); err != nil {
|
||||
return nil, fmt.Errorf("failed to locate go.mod at %s: %v", goModPath, err)
|
||||
}
|
||||
|
||||
data, err := os.ReadFile(goModPath)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to read go.mod: %v", err)
|
||||
return nil, fmt.Errorf("failed to read go.mod at %s: %v", goModPath, err)
|
||||
}
|
||||
|
||||
// Parse go.mod content to extract dependencies
|
||||
@@ -303,13 +312,13 @@ func generateBackendLicenses() ([]License, error) {
|
||||
return licenses, nil
|
||||
}
|
||||
|
||||
func generateFrontendLicenses() ([]License, error) {
|
||||
func generateFrontendLicenses(repoRoot string) ([]License, error) {
|
||||
var licenses []License
|
||||
|
||||
log.Println("INFO: Collecting frontend npm packages...")
|
||||
|
||||
// Read package.json
|
||||
packagePath := "app/package.json"
|
||||
packagePath := filepath.Join(repoRoot, "app", "package.json")
|
||||
if _, err := os.Stat(packagePath); os.IsNotExist(err) {
|
||||
return nil, fmt.Errorf("package.json not found at %s", packagePath)
|
||||
}
|
||||
@@ -760,3 +769,48 @@ func getGoVersion() string {
|
||||
|
||||
return "Unknown"
|
||||
}
|
||||
|
||||
// locateRepoRoot returns the directory containing go.mod so relative paths stay stable.
|
||||
func locateRepoRoot() (string, error) {
|
||||
goModPath, err := locateGoModPath()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return filepath.Dir(goModPath), nil
|
||||
}
|
||||
|
||||
// locateGoModPath finds the module root so the tool works from any working directory.
|
||||
func locateGoModPath() (string, error) {
|
||||
// Prefer go env GOMOD which respects module-aware mode.
|
||||
cmd := exec.Command("go", "env", "GOMOD")
|
||||
output, err := cmd.Output()
|
||||
if err == nil {
|
||||
path := strings.TrimSpace(string(output))
|
||||
if path != "" {
|
||||
if _, statErr := os.Stat(path); statErr == nil {
|
||||
return path, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Fallback: walk upwards from the current working directory.
|
||||
dir, err := os.Getwd()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
for {
|
||||
candidate := filepath.Join(dir, "go.mod")
|
||||
if info, statErr := os.Stat(candidate); statErr == nil && !info.IsDir() {
|
||||
return candidate, nil
|
||||
}
|
||||
|
||||
parent := filepath.Dir(dir)
|
||||
if parent == dir {
|
||||
break
|
||||
}
|
||||
dir = parent
|
||||
}
|
||||
|
||||
return "", fmt.Errorf("go.mod not found from current directory or parents")
|
||||
}
|
||||
|
||||
@@ -0,0 +1,174 @@
|
||||
//go:generate go run .
|
||||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strings"
|
||||
"unicode"
|
||||
)
|
||||
|
||||
type fileReport struct {
|
||||
path string
|
||||
insertions int
|
||||
}
|
||||
|
||||
var (
|
||||
dryRun = flag.Bool("dry-run", false, "only report issues without modifying files")
|
||||
targetDir string
|
||||
rootDir string
|
||||
)
|
||||
|
||||
func main() {
|
||||
flag.Parse()
|
||||
log.SetFlags(0)
|
||||
|
||||
if err := resolvePaths(); err != nil {
|
||||
log.Fatalf("resolve paths: %v", err)
|
||||
}
|
||||
|
||||
reports, totalInsertions, err := processDirectory(*dryRun)
|
||||
if err != nil {
|
||||
log.Fatalf("scan failed: %v", err)
|
||||
}
|
||||
|
||||
if len(reports) == 0 {
|
||||
log.Println("No spacing issues detected.")
|
||||
return
|
||||
}
|
||||
|
||||
for _, r := range reports {
|
||||
relative := r.path
|
||||
if rel, err := filepath.Rel(rootDir, r.path); err == nil {
|
||||
relative = rel
|
||||
}
|
||||
fmt.Printf("%s: inserted %d space(s)\n", relative, r.insertions)
|
||||
}
|
||||
|
||||
if *dryRun {
|
||||
log.Printf("Dry run complete. %d potential insertion(s) across %d file(s).", totalInsertions, len(reports))
|
||||
return
|
||||
}
|
||||
|
||||
log.Printf("Completed fixes. Inserted %d space(s) across %d file(s).", totalInsertions, len(reports))
|
||||
}
|
||||
|
||||
func resolvePaths() error {
|
||||
_, file, _, ok := runtime.Caller(0)
|
||||
if !ok {
|
||||
return fmt.Errorf("unable to determine caller")
|
||||
}
|
||||
|
||||
rootDir = filepath.Clean(filepath.Join(filepath.Dir(file), "../.."))
|
||||
targetDir = filepath.Join(rootDir, "app/src/language")
|
||||
|
||||
info, err := os.Stat(targetDir)
|
||||
if err != nil {
|
||||
return fmt.Errorf("stat language directory: %w", err)
|
||||
}
|
||||
if !info.IsDir() {
|
||||
return fmt.Errorf("language path is not a directory: %s", targetDir)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func processDirectory(dryRun bool) ([]fileReport, int, error) {
|
||||
reports := make([]fileReport, 0)
|
||||
totalInsertions := 0
|
||||
|
||||
err := filepath.Walk(targetDir, func(path string, info os.FileInfo, err error) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if info.IsDir() {
|
||||
return nil
|
||||
}
|
||||
if !isSupportedFile(path) {
|
||||
return nil
|
||||
}
|
||||
|
||||
original, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
return fmt.Errorf("read %s: %w", path, err)
|
||||
}
|
||||
|
||||
fixed, insertions := fixContent(string(original))
|
||||
if insertions == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
if !dryRun {
|
||||
if err := os.WriteFile(path, []byte(fixed), info.Mode().Perm()); err != nil {
|
||||
return fmt.Errorf("write %s: %w", path, err)
|
||||
}
|
||||
}
|
||||
|
||||
reports = append(reports, fileReport{
|
||||
path: path,
|
||||
insertions: insertions,
|
||||
})
|
||||
totalInsertions += insertions
|
||||
return nil
|
||||
})
|
||||
|
||||
return reports, totalInsertions, err
|
||||
}
|
||||
|
||||
func isSupportedFile(path string) bool {
|
||||
switch strings.ToLower(filepath.Ext(path)) {
|
||||
case ".po", ".pot", ".ts":
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
func fixContent(text string) (string, int) {
|
||||
runes := []rune(text)
|
||||
if len(runes) == 0 {
|
||||
return text, 0
|
||||
}
|
||||
|
||||
var builder strings.Builder
|
||||
builder.Grow(len(runes) + 16)
|
||||
insertions := 0
|
||||
|
||||
for i := 0; i < len(runes); i++ {
|
||||
current := runes[i]
|
||||
builder.WriteRune(current)
|
||||
|
||||
if i == len(runes)-1 {
|
||||
break
|
||||
}
|
||||
|
||||
next := runes[i+1]
|
||||
if needsSpace(current, next) {
|
||||
builder.WriteRune(' ')
|
||||
insertions++
|
||||
}
|
||||
}
|
||||
|
||||
return builder.String(), insertions
|
||||
}
|
||||
|
||||
func needsSpace(left, right rune) bool {
|
||||
if isHan(left) && isASCIIAlphaNum(right) {
|
||||
return true
|
||||
}
|
||||
if isASCIIAlphaNum(left) && isHan(right) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func isHan(r rune) bool {
|
||||
return unicode.Is(unicode.Han, r)
|
||||
}
|
||||
|
||||
func isASCIIAlphaNum(r rune) bool {
|
||||
return r <= unicode.MaxASCII && ((r >= 'a' && r <= 'z') || (r >= 'A' && r <= 'Z') || (r >= '0' && r <= '9'))
|
||||
}
|
||||
Binary file not shown.
Reference in New Issue
Block a user