// Copyright 2024 Matthew Rich . All rights reserved. package folio import ( "decl/internal/ext" "decl/internal/ds" "errors" "fmt" "log/slog" "path/filepath" "decl/internal/data" ) var ( ErrSearchPathNotExist error = errors.New("Search path does not exist.") ) // A search path should find a file in list of paths type SearchPath struct { paths *ds.OrderedSet[string] } func NewSearchPath(paths []string) (s *SearchPath) { s = &SearchPath{ paths: ds.NewOrderedSet[string]() } s.paths.AddItems(paths) return } func (s *SearchPath) AddPath(path string) error { if newPath := ext.FilePath(path).Abs(); newPath.Exists() { s.paths.Add(string(newPath)) } else { return fmt.Errorf("%w: %s", ErrSearchPathNotExist, path) } return nil } func (s *SearchPath) Find(relative string) string { pathValues := s.paths.Items() for i := len(pathValues) - 1; i >= 0; i-- { p := *pathValues[i] searchPath := ext.FilePath(p) searchPath.Add(relative) slog.Info("SearchPath.Find()", "searchpath", p, "file", relative, "target", searchPath) if searchPath.Exists() { return string(searchPath) } } return "" } func (s *SearchPath) FindParsedURI(uri data.URIParser) (result URI) { u := uri.URL() filePath := filepath.Join(u.Hostname(), u.Path) if absPath := s.Find(filePath); absPath != "" { result = URI(fmt.Sprintf("%s://%s", u.Scheme, string(absPath))) } return } func (s *SearchPath) FindURI(uri URI) (result URI) { return s.FindParsedURI(uri.Parse()) }