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 }