code.gitea.io/gitea@v1.19.3/modules/options/base.go (about)

     1  // Copyright 2022 The Gitea Authors. All rights reserved.
     2  // SPDX-License-Identifier: MIT
     3  
     4  package options
     5  
     6  import (
     7  	"fmt"
     8  	"io/fs"
     9  	"os"
    10  	"path/filepath"
    11  
    12  	"code.gitea.io/gitea/modules/log"
    13  	"code.gitea.io/gitea/modules/setting"
    14  	"code.gitea.io/gitea/modules/util"
    15  )
    16  
    17  var directories = make(directorySet)
    18  
    19  // Locale reads the content of a specific locale from static/bindata or custom path.
    20  func Locale(name string) ([]byte, error) {
    21  	return fileFromOptionsDir("locale", name)
    22  }
    23  
    24  // Readme reads the content of a specific readme from static/bindata or custom path.
    25  func Readme(name string) ([]byte, error) {
    26  	return fileFromOptionsDir("readme", name)
    27  }
    28  
    29  // Gitignore reads the content of a gitignore locale from static/bindata or custom path.
    30  func Gitignore(name string) ([]byte, error) {
    31  	return fileFromOptionsDir("gitignore", name)
    32  }
    33  
    34  // License reads the content of a specific license from static/bindata or custom path.
    35  func License(name string) ([]byte, error) {
    36  	return fileFromOptionsDir("license", name)
    37  }
    38  
    39  // Labels reads the content of a specific labels from static/bindata or custom path.
    40  func Labels(name string) ([]byte, error) {
    41  	return fileFromOptionsDir("label", name)
    42  }
    43  
    44  // WalkLocales reads the content of a specific locale
    45  func WalkLocales(callback func(path, name string, d fs.DirEntry, err error) error) error {
    46  	if IsDynamic() {
    47  		if err := walkAssetDir(filepath.Join(setting.StaticRootPath, "options", "locale"), callback); err != nil && !os.IsNotExist(err) {
    48  			return fmt.Errorf("failed to walk locales. Error: %w", err)
    49  		}
    50  	}
    51  
    52  	if err := walkAssetDir(filepath.Join(setting.CustomPath, "options", "locale"), callback); err != nil && !os.IsNotExist(err) {
    53  		return fmt.Errorf("failed to walk locales. Error: %w", err)
    54  	}
    55  	return nil
    56  }
    57  
    58  func walkAssetDir(root string, callback func(path, name string, d fs.DirEntry, err error) error) error {
    59  	if err := filepath.WalkDir(root, func(path string, d fs.DirEntry, err error) error {
    60  		// name is the path relative to the root
    61  		name := path[len(root):]
    62  		if len(name) > 0 && name[0] == '/' {
    63  			name = name[1:]
    64  		}
    65  		if err != nil {
    66  			if os.IsNotExist(err) {
    67  				return callback(path, name, d, err)
    68  			}
    69  			return err
    70  		}
    71  		if util.CommonSkip(d.Name()) {
    72  			if d.IsDir() {
    73  				return fs.SkipDir
    74  			}
    75  			return nil
    76  		}
    77  		return callback(path, name, d, err)
    78  	}); err != nil && !os.IsNotExist(err) {
    79  		return fmt.Errorf("unable to get files for assets in %s: %w", root, err)
    80  	}
    81  	return nil
    82  }
    83  
    84  // mustLocalPathAbs coverts a path to absolute path
    85  // FIXME: the old behavior (StaticRootPath might not be absolute), not ideal, just keep the same as before
    86  func mustLocalPathAbs(s string) string {
    87  	abs, err := filepath.Abs(s)
    88  	if err != nil {
    89  		// This should never happen in a real system. If it happens, the user must have already been in trouble: the system is not able to resolve its own paths.
    90  		log.Fatal("Unable to get absolute path for %q: %v", s, err)
    91  	}
    92  	return abs
    93  }
    94  
    95  func joinLocalPaths(baseDirs []string, subDir string, elems ...string) (paths []string) {
    96  	abs := make([]string, len(elems)+2)
    97  	abs[1] = subDir
    98  	copy(abs[2:], elems)
    99  	for _, baseDir := range baseDirs {
   100  		abs[0] = mustLocalPathAbs(baseDir)
   101  		paths = append(paths, util.FilePathJoinAbs(abs...))
   102  	}
   103  	return paths
   104  }
   105  
   106  func listLocalDirIfExist(baseDirs []string, subDir string, elems ...string) (files []string, err error) {
   107  	for _, localPath := range joinLocalPaths(baseDirs, subDir, elems...) {
   108  		isDir, err := util.IsDir(localPath)
   109  		if err != nil {
   110  			return nil, fmt.Errorf("unable to check if path %q is a directory. %w", localPath, err)
   111  		} else if !isDir {
   112  			continue
   113  		}
   114  
   115  		dirFiles, err := util.StatDir(localPath, true)
   116  		if err != nil {
   117  			return nil, fmt.Errorf("unable to read directory %q. %w", localPath, err)
   118  		}
   119  		files = append(files, dirFiles...)
   120  	}
   121  	return files, nil
   122  }
   123  
   124  func readLocalFile(baseDirs []string, subDir string, elems ...string) ([]byte, error) {
   125  	for _, localPath := range joinLocalPaths(baseDirs, subDir, elems...) {
   126  		data, err := os.ReadFile(localPath)
   127  		if err == nil {
   128  			return data, nil
   129  		} else if !os.IsNotExist(err) {
   130  			log.Error("Unable to read file %q. Error: %v", localPath, err)
   131  		}
   132  	}
   133  	return nil, os.ErrNotExist
   134  }