mirror of
				https://github.com/go-gitea/gitea
				synced 2025-11-03 21:08:25 +00:00 
			
		
		
		
	I don't see why we have to use two versions of yaml. The difference between the two versions has nothing to do with our usage.
		
			
				
	
	
		
			112 lines
		
	
	
		
			2.3 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			112 lines
		
	
	
		
			2.3 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
// Copyright 2022 The Gitea Authors. All rights reserved.
 | 
						|
// Use of this source code is governed by a MIT-style
 | 
						|
// license that can be found in the LICENSE file.
 | 
						|
 | 
						|
package migration
 | 
						|
 | 
						|
import (
 | 
						|
	"fmt"
 | 
						|
	"os"
 | 
						|
	"strings"
 | 
						|
	"time"
 | 
						|
 | 
						|
	"code.gitea.io/gitea/modules/json"
 | 
						|
	"code.gitea.io/gitea/modules/log"
 | 
						|
 | 
						|
	"github.com/santhosh-tekuri/jsonschema/v5"
 | 
						|
	"gopkg.in/yaml.v3"
 | 
						|
)
 | 
						|
 | 
						|
// Load project data from file, with optional validation
 | 
						|
func Load(filename string, data interface{}, validation bool) error {
 | 
						|
	isJSON := strings.HasSuffix(filename, ".json")
 | 
						|
 | 
						|
	bs, err := os.ReadFile(filename)
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
 | 
						|
	if validation {
 | 
						|
		err := validate(bs, data, isJSON)
 | 
						|
		if err != nil {
 | 
						|
			return err
 | 
						|
		}
 | 
						|
	}
 | 
						|
	return unmarshal(bs, data, isJSON)
 | 
						|
}
 | 
						|
 | 
						|
func unmarshal(bs []byte, data interface{}, isJSON bool) error {
 | 
						|
	if isJSON {
 | 
						|
		return json.Unmarshal(bs, data)
 | 
						|
	}
 | 
						|
	return yaml.Unmarshal(bs, data)
 | 
						|
}
 | 
						|
 | 
						|
func getSchema(filename string) (*jsonschema.Schema, error) {
 | 
						|
	c := jsonschema.NewCompiler()
 | 
						|
	c.LoadURL = openSchema
 | 
						|
	return c.Compile(filename)
 | 
						|
}
 | 
						|
 | 
						|
func validate(bs []byte, datatype interface{}, isJSON bool) error {
 | 
						|
	var v interface{}
 | 
						|
	err := unmarshal(bs, &v, isJSON)
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
	if !isJSON {
 | 
						|
		v, err = toStringKeys(v)
 | 
						|
		if err != nil {
 | 
						|
			return err
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	var schemaFilename string
 | 
						|
	switch datatype := datatype.(type) {
 | 
						|
	case *[]*Issue:
 | 
						|
		schemaFilename = "issue.json"
 | 
						|
	case *[]*Milestone:
 | 
						|
		schemaFilename = "milestone.json"
 | 
						|
	default:
 | 
						|
		return fmt.Errorf("file_format:validate: %T has not a validation implemented", datatype)
 | 
						|
	}
 | 
						|
 | 
						|
	sch, err := getSchema(schemaFilename)
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
	err = sch.Validate(v)
 | 
						|
	if err != nil {
 | 
						|
		log.Error("migration validation with %s failed for\n%s", schemaFilename, string(bs))
 | 
						|
	}
 | 
						|
	return err
 | 
						|
}
 | 
						|
 | 
						|
func toStringKeys(val interface{}) (interface{}, error) {
 | 
						|
	var err error
 | 
						|
	switch val := val.(type) {
 | 
						|
	case map[string]interface{}:
 | 
						|
		m := make(map[string]interface{})
 | 
						|
		for k, v := range val {
 | 
						|
			m[k], err = toStringKeys(v)
 | 
						|
			if err != nil {
 | 
						|
				return nil, err
 | 
						|
			}
 | 
						|
		}
 | 
						|
		return m, nil
 | 
						|
	case []interface{}:
 | 
						|
		l := make([]interface{}, len(val))
 | 
						|
		for i, v := range val {
 | 
						|
			l[i], err = toStringKeys(v)
 | 
						|
			if err != nil {
 | 
						|
				return nil, err
 | 
						|
			}
 | 
						|
		}
 | 
						|
		return l, nil
 | 
						|
	case time.Time:
 | 
						|
		return val.Format(time.RFC3339), nil
 | 
						|
	default:
 | 
						|
		return val, nil
 | 
						|
	}
 | 
						|
}
 |