github.com/freiheit-com/kuberpult@v1.24.2-0.20240328135542-315d5630abe6/services/cd-service/pkg/event/writer.go (about)

     1  /*This file is part of kuberpult.
     2  
     3  Kuberpult is free software: you can redistribute it and/or modify
     4  it under the terms of the Expat(MIT) License as published by
     5  the Free Software Foundation.
     6  
     7  Kuberpult is distributed in the hope that it will be useful,
     8  but WITHOUT ANY WARRANTY; without even the implied warranty of
     9  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    10  MIT License for more details.
    11  
    12  You should have received a copy of the MIT License
    13  along with kuberpult. If not, see <https://directory.fsf.org/wiki/License:Expat>.
    14  
    15  Copyright 2023 freiheit.com*/
    16  
    17  package event
    18  
    19  import (
    20  	"fmt"
    21  	"reflect"
    22  	"strings"
    23  
    24  	"github.com/go-git/go-billy/v5"
    25  	"github.com/go-git/go-billy/v5/util"
    26  )
    27  
    28  func write(
    29  	filesystem billy.Filesystem,
    30  	dir string,
    31  	val any,
    32  ) error {
    33  	return writeFile(filesystem, dir, reflect.ValueOf(val), encodingDefault)
    34  }
    35  
    36  func writeFile(
    37  	fs billy.Filesystem,
    38  	file string,
    39  	value reflect.Value,
    40  	encoding encoding,
    41  ) error {
    42  	tp := value.Type()
    43  	switch tp.Kind() {
    44  	case reflect.Pointer:
    45  		if value.IsNil() {
    46  			return nil
    47  		}
    48  		return writeFile(fs, file, value.Elem(), encoding)
    49  	case reflect.String:
    50  		val := value.Interface().(string)
    51  		return util.WriteFile(fs, file, []byte(val), 0666)
    52  	case reflect.Struct:
    53  		if err := fs.MkdirAll(file, 0777); err != nil {
    54  			return err
    55  		}
    56  		if tp.NumField() == 0 {
    57  			return util.WriteFile(fs, fs.Join(file, ".gitkeep"), []byte{}, 0666)
    58  		}
    59  		for i := 0; i < tp.NumField(); i++ {
    60  			f := tp.Field(i)
    61  			name, enc := parseTag(f.Tag.Get("fs"))
    62  			if name == "" {
    63  				name = f.Name
    64  			}
    65  			if err := writeFile(fs,
    66  				fs.Join(file, name),
    67  				value.Field(i),
    68  				enc,
    69  			); err != nil {
    70  				return err
    71  			}
    72  		}
    73  		return nil
    74  	case reflect.Map:
    75  		if tp.Key().Kind() != reflect.String {
    76  			return fmt.Errorf("can only use maps with strings as keys")
    77  		}
    78  		if err := fs.MkdirAll(file, 0777); err != nil {
    79  			return err
    80  		}
    81  		if value.Len() == 0 {
    82  			return util.WriteFile(fs, fs.Join(file, ".gitkeep"), []byte{}, 0666)
    83  		}
    84  		iter := value.MapRange()
    85  		for iter.Next() {
    86  			fileName := iter.Key().Interface().(string)
    87  			if err := writeFile(fs,
    88  				fs.Join(file, fileName),
    89  				iter.Value(),
    90  				encodingDefault,
    91  			); err != nil {
    92  				return err
    93  			}
    94  		}
    95  		return nil
    96  	case reflect.Slice:
    97  		if err := fs.MkdirAll(file, 0777); err != nil {
    98  			return err
    99  		}
   100  		if value.Len() == 0 {
   101  			return util.WriteFile(fs, fs.Join(file, ".gitkeep"), []byte{}, 0666)
   102  		}
   103  		for i := 0; i < value.Len(); i++ {
   104  			if err := writeFile(fs,
   105  				fs.Join(file, fmt.Sprintf("%d", i)),
   106  				value.Index(i),
   107  				encodingDefault,
   108  			); err != nil {
   109  				return err
   110  			}
   111  		}
   112  		return nil
   113  	default:
   114  		return fmt.Errorf("cannot write type %v", tp)
   115  	}
   116  }
   117  
   118  type encoding int
   119  
   120  const (
   121  	encodingDefault encoding = iota
   122  )
   123  
   124  func parseTag(tag string) (name string, encoding encoding) {
   125  	elems := strings.Split(tag, ",")
   126  	if len(elems) == 0 {
   127  		return "", encodingDefault
   128  	}
   129  	name = elems[0]
   130  	if len(elems) == 1 {
   131  		return name, encodingDefault
   132  	}
   133  	switch elems[1] {
   134  	case "default", "":
   135  		encoding = encodingDefault
   136  	default:
   137  		panic(fmt.Sprintf("unknown encoding: %q", elems[1]))
   138  	}
   139  	return name, encoding
   140  }