Files
MosisService/portal/cmd/mosis/cmd/validate.go

202 lines
4.5 KiB
Go

package cmd
import (
"fmt"
"image"
_ "image/png"
"os"
"path/filepath"
"strings"
"github.com/spf13/cobra"
"github.com/omixlab/mosis-portal/pkg/mospkg"
)
// ValidateCmd returns the validate command
func ValidateCmd() *cobra.Command {
return &cobra.Command{
Use: "validate [directory]",
Short: "Validate project manifest and assets",
Long: "Validate a Mosis project without building. Checks manifest.json, assets, and icons.",
Args: cobra.MaximumNArgs(1),
RunE: runValidate,
}
}
func runValidate(cmd *cobra.Command, args []string) error {
dir := "."
if len(args) > 0 {
dir = args[0]
}
hasErrors := false
// Validate manifest
fmt.Println("Validating manifest.json...")
manifest, errs := validateManifest(dir)
if len(errs) > 0 {
hasErrors = true
for _, e := range errs {
fmt.Printf("✗ %s\n", e)
}
} else {
fmt.Println("✓ Required fields present")
fmt.Println("✓ Package ID format valid")
fmt.Println("✓ Version format valid")
}
if manifest == nil {
return fmt.Errorf("\nValidation failed.")
}
// Validate assets
fmt.Println("\nValidating assets...")
assetErrs := validateAssets(dir, manifest)
if len(assetErrs) > 0 {
hasErrors = true
for _, e := range assetErrs {
fmt.Printf("✗ %s\n", e)
}
} else {
fmt.Printf("✓ Entry point exists: %s\n", manifest.Entry)
// Count files by type
rmlCount, rcssCount, luaCount := countAssetFiles(dir)
if rmlCount > 0 {
fmt.Printf("✓ Found %d RML files\n", rmlCount)
}
if rcssCount > 0 {
fmt.Printf("✓ Found %d RCSS files\n", rcssCount)
}
if luaCount > 0 {
fmt.Printf("✓ Found %d Lua files\n", luaCount)
}
}
// Validate icons
fmt.Println("\nValidating icons...")
iconErrs := validateIcons(dir, manifest)
if len(iconErrs) > 0 {
hasErrors = true
for _, e := range iconErrs {
fmt.Printf("✗ %s\n", e)
}
} else {
if manifest.Icons.Size32 != "" {
fmt.Printf("✓ icon-32.png\n")
}
if manifest.Icons.Size64 != "" {
fmt.Printf("✓ icon-64.png\n")
}
if manifest.Icons.Size128 != "" {
fmt.Printf("✓ icon-128.png\n")
}
}
// Check permissions
fmt.Println("\nChecking permissions...")
if len(manifest.Permissions) == 0 {
fmt.Println("✓ No permissions declared")
} else {
fmt.Printf("✓ Permissions declared: %s\n", strings.Join(manifest.Permissions, ", "))
}
if hasErrors {
return fmt.Errorf("\nValidation failed with errors.")
}
fmt.Println("\nAll validations passed!")
return nil
}
func validateManifest(dir string) (*mospkg.Manifest, []string) {
manifestPath := filepath.Join(dir, "manifest.json")
data, err := os.ReadFile(manifestPath)
if err != nil {
return nil, []string{"manifest.json not found"}
}
manifest, err := mospkg.ParseManifest(data)
if err != nil {
return nil, []string{fmt.Sprintf("Invalid manifest.json: %v", err)}
}
validationErrs := manifest.Validate()
var errs []string
for _, e := range validationErrs {
errs = append(errs, e.Message)
}
if len(errs) > 0 {
return manifest, errs
}
return manifest, nil
}
func validateAssets(dir string, manifest *mospkg.Manifest) []string {
var errs []string
// Check entry point exists
entryPath := filepath.Join(dir, manifest.Entry)
if _, err := os.Stat(entryPath); os.IsNotExist(err) {
errs = append(errs, fmt.Sprintf("Entry point not found: %s", manifest.Entry))
}
return errs
}
func countAssetFiles(dir string) (rml, rcss, lua int) {
assetsDir := filepath.Join(dir, "assets")
filepath.Walk(assetsDir, func(path string, info os.FileInfo, err error) error {
if err != nil || info.IsDir() {
return nil
}
switch strings.ToLower(filepath.Ext(path)) {
case ".rml":
rml++
case ".rcss":
rcss++
case ".lua":
lua++
}
return nil
})
return
}
func validateIcons(dir string, manifest *mospkg.Manifest) []string {
var errs []string
checkIcon := func(path string, expectedSize int) {
if path == "" {
return
}
fullPath := filepath.Join(dir, path)
f, err := os.Open(fullPath)
if err != nil {
errs = append(errs, fmt.Sprintf("Icon not found: %s", path))
return
}
defer f.Close()
img, _, err := image.DecodeConfig(f)
if err != nil {
errs = append(errs, fmt.Sprintf("Invalid icon format: %s", path))
return
}
if img.Width != expectedSize || img.Height != expectedSize {
errs = append(errs, fmt.Sprintf("Icon %s should be %dx%d, got %dx%d",
path, expectedSize, expectedSize, img.Width, img.Height))
}
}
checkIcon(manifest.Icons.Size32, 32)
checkIcon(manifest.Icons.Size64, 64)
checkIcon(manifest.Icons.Size128, 128)
return errs
}