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  }