github.com/hattya/nazuna@v0.7.1-0.20240331055452-55e14c275c1c/layer.go (about) 1 // 2 // nazuna :: layer.go 3 // 4 // Copyright (c) 2013-2020 Akinori Hattori <hattya@gmail.com> 5 // 6 // SPDX-License-Identifier: MIT 7 // 8 9 package nazuna 10 11 import ( 12 "fmt" 13 "path/filepath" 14 "sort" 15 ) 16 17 type Layer struct { 18 Name string `json:"name"` 19 Layers []*Layer `json:"layers,omitempty"` 20 Aliases map[string]string `json:"aliases,omitempty"` 21 Links map[string][]*Link `json:"links,omitempty"` 22 Subrepos map[string][]*Subrepo `json:"subrepos,omitempty"` 23 24 repo *Repository 25 abst *Layer 26 } 27 28 func (l *Layer) Path() string { 29 if l.abst != nil { 30 return l.abst.Name + "/" + l.Name 31 } 32 return l.Name 33 } 34 35 func (l *Layer) NewAlias(src, dst string) error { 36 s := filepath.ToSlash(filepath.Clean(src)) 37 d := filepath.ToSlash(filepath.Clean(dst)) 38 if s == d { 39 return fmt.Errorf("'%v' and '%v' are the same path", src, dst) 40 } 41 if err := l.check(dst, true); err != nil { 42 return err 43 } 44 45 if l.Aliases == nil { 46 l.Aliases = make(map[string]string) 47 } 48 l.Aliases[s] = d 49 return nil 50 } 51 52 func (l *Layer) NewLink(path []string, src, dst string) (*Link, error) { 53 if err := l.check(dst, false); err != nil { 54 return nil, err 55 } 56 57 for i, p := range path { 58 path[i] = filepath.ToSlash(filepath.Clean(p)) 59 } 60 src = filepath.ToSlash(filepath.Clean(src)) 61 dir, dst := SplitPath(filepath.ToSlash(filepath.Clean(dst))) 62 lnk := &Link{ 63 Path: path, 64 Src: src, 65 Dst: dst, 66 } 67 if l.Links == nil { 68 l.Links = make(map[string][]*Link) 69 } 70 l.Links[dir] = append(l.Links[dir], lnk) 71 sort.Slice(l.Links[dir], func(i, j int) bool { return l.Links[dir][i].Dst < l.Links[dir][j].Dst }) 72 return lnk, nil 73 } 74 75 func (l *Layer) NewSubrepo(src, dst string) (*Subrepo, error) { 76 if err := l.check(dst, false); err != nil { 77 return nil, err 78 } 79 80 dir, name := SplitPath(filepath.ToSlash(filepath.Clean(dst))) 81 if name == filepath.Base(src) { 82 name = "" 83 } 84 sub := &Subrepo{ 85 Src: src, 86 Name: name, 87 } 88 if l.Subrepos == nil { 89 l.Subrepos = make(map[string][]*Subrepo) 90 } 91 l.Subrepos[dir] = append(l.Subrepos[dir], sub) 92 sort.Slice(l.Subrepos[dir], func(i, j int) bool { return l.Subrepos[dir][i].Src < l.Subrepos[dir][j].Src }) 93 return sub, nil 94 } 95 96 func (l *Layer) check(path string, dir bool) error { 97 if len(l.Layers) != 0 { 98 return fmt.Errorf("layer '%v' is abstract", l.Path()) 99 } 100 switch typ := l.repo.Find(l, path); typ { 101 case "": 102 case "file", "dir": 103 if dir && typ == "dir" { 104 break 105 } 106 return fmt.Errorf("'%v' already exists!", path) 107 default: 108 return fmt.Errorf("%v '%v' already exists!", typ, path) 109 } 110 return nil 111 } 112 113 type Link struct { 114 Path []string `json:"path,omitempty"` 115 Src string `json:"src"` 116 Dst string `json:"dst"` 117 } 118 119 type Subrepo struct { 120 Src string `json:"src"` 121 Name string `json:"name,omitempty"` 122 }