go.chromium.org/luci@v0.0.0-20240309015107-7cdc2e660f33/starlark/interpreter/loaders.go (about)

     1  // Copyright 2018 The LUCI Authors.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //      http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package interpreter
    16  
    17  import (
    18  	"os"
    19  	"path/filepath"
    20  	"strings"
    21  
    22  	"go.starlark.net/starlark"
    23  
    24  	"go.chromium.org/luci/common/errors"
    25  )
    26  
    27  // FileSystemLoader returns a loader that loads files from the file system.
    28  func FileSystemLoader(root string) Loader {
    29  	root, err := filepath.Abs(root)
    30  	if err != nil {
    31  		panic(err)
    32  	}
    33  	return func(path string) (_ starlark.StringDict, src string, err error) {
    34  		abs := filepath.Join(root, filepath.FromSlash(path))
    35  		rel, err := filepath.Rel(root, abs)
    36  		if err != nil {
    37  			return nil, "", errors.Annotate(err, "failed to calculate relative path").Err()
    38  		}
    39  		if strings.HasPrefix(rel, ".."+string(filepath.Separator)) {
    40  			return nil, "", errors.New("outside the package root")
    41  		}
    42  		body, err := os.ReadFile(abs)
    43  		if os.IsNotExist(err) {
    44  			return nil, "", ErrNoModule
    45  		}
    46  		return nil, string(body), err
    47  	}
    48  }
    49  
    50  // MemoryLoader returns a loader that loads files from the given map.
    51  //
    52  // Useful together with 'assets' package to embed Starlark code into the
    53  // interpreter binary.
    54  func MemoryLoader(files map[string]string) Loader {
    55  	return func(path string) (_ starlark.StringDict, src string, err error) {
    56  		body, ok := files[path]
    57  		if !ok {
    58  			return nil, "", ErrNoModule
    59  		}
    60  		return nil, body, nil
    61  	}
    62  }