github.com/aacfactory/fns@v1.2.86-0.20240310083819-80d667fc0a17/cmd/generates/sources/workfiles.go (about) 1 /* 2 * Copyright 2023 Wang Min Xiang 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 * 16 */ 17 18 package sources 19 20 import ( 21 "fmt" 22 "github.com/aacfactory/errors" 23 "github.com/aacfactory/fns/cmd/generates/files" 24 "golang.org/x/mod/modfile" 25 "os" 26 "path/filepath" 27 "sync" 28 ) 29 30 type Work struct { 31 Dir string 32 Filename string 33 Uses []*Module 34 Replaces []*Module 35 parsed bool 36 } 37 38 func (work *Work) Use(path string) (v *Module, used bool) { 39 for _, use := range work.Uses { 40 if use.Path == path { 41 v = use 42 used = true 43 break 44 } 45 } 46 return 47 } 48 49 func (work *Work) Parse() (err error) { 50 if work.parsed { 51 return 52 } 53 path := work.Filename 54 if !filepath.IsAbs(path) { 55 absolute, absoluteErr := filepath.Abs(path) 56 if absoluteErr != nil { 57 err = errors.Warning("sources: parse work failed"). 58 WithCause(errors.Warning("sources: get absolute representation of work file failed").WithCause(absoluteErr).WithMeta("work", path)) 59 return 60 } 61 path = absolute 62 } 63 if !files.ExistFile(path) { 64 err = errors.Warning("sources: parse work failed"). 65 WithCause(errors.Warning("sources: file was not found").WithMeta("work", path)) 66 return 67 } 68 dir := filepath.Dir(path) 69 path = filepath.ToSlash(path) 70 data, readErr := os.ReadFile(path) 71 if readErr != nil { 72 err = errors.Warning("sources: parse work failed").WithMeta("work", path).WithCause(readErr) 73 return 74 } 75 file, parseErr := modfile.ParseWork(path, data, nil) 76 if parseErr != nil { 77 err = errors.Warning("sources: parse work failed").WithMeta("work", path).WithCause(parseErr) 78 return 79 } 80 work.Filename = path 81 work.Uses = make([]*Module, 0, 1) 82 work.Replaces = make([]*Module, 0, 1) 83 if file.Use != nil && len(file.Use) > 0 { 84 for _, use := range file.Use { 85 usePath := use.Path 86 if filepath.IsAbs(usePath) { 87 usePath = filepath.ToSlash(usePath) 88 } else { 89 usePath = filepath.ToSlash(filepath.Join(dir, usePath)) 90 } 91 moduleFile := filepath.ToSlash(filepath.Join(usePath, "go.mod")) 92 if !files.ExistFile(moduleFile) { 93 err = errors.Warning("sources: parse work failed").WithMeta("work", path). 94 WithCause(errors.Warning("sources: mod file was not found"). 95 WithMeta("mod", moduleFile)) 96 return 97 } 98 modData, readModErr := os.ReadFile(moduleFile) 99 if readModErr != nil { 100 err = errors.Warning("sources: parse work failed").WithMeta("work", path). 101 WithCause(errors.Warning("sources: read mod file failed").WithCause(readModErr).WithMeta("mod", moduleFile)) 102 return 103 } 104 mf, parseModErr := modfile.Parse(moduleFile, modData, nil) 105 if parseModErr != nil { 106 err = errors.Warning("sources: parse work failed").WithMeta("work", path). 107 WithCause(errors.Warning("sources: parse mod file failed").WithCause(parseModErr).WithMeta("mod", moduleFile)) 108 return 109 } 110 mod := &Module{ 111 Dir: usePath, 112 Path: mf.Module.Mod.Path, 113 Version: "", 114 Requires: nil, 115 Work: work, 116 Replace: nil, 117 locker: &sync.Mutex{}, 118 parsed: false, 119 sources: nil, 120 builtinTypes: nil, 121 types: nil, 122 } 123 registerBuiltinTypes(mod) 124 work.Uses = append(work.Uses, mod) 125 } 126 } 127 if file.Replace != nil && len(file.Replace) > 0 { 128 for _, replace := range file.Replace { 129 replaceDir := "" 130 if replace.New.Version != "" { 131 replaceDir = filepath.Join(PKG(), fmt.Sprintf("%s@%s", replace.New.Path, replace.New.Version)) 132 } else { 133 if filepath.IsAbs(replace.New.Path) { 134 replaceDir = replace.New.Path 135 } else { 136 replaceDir = filepath.Join(work.Dir, replace.New.Path) 137 } 138 } 139 replaceDir = filepath.ToSlash(replaceDir) 140 if !files.ExistFile(replaceDir) { 141 err = errors.Warning("sources: parse work failed").WithMeta("work", path). 142 WithCause(errors.Warning("sources: replace dir was not found").WithMeta("replace", replaceDir)) 143 return 144 } 145 moduleFile := filepath.ToSlash(filepath.Join(replaceDir, "go.mod")) 146 if !files.ExistFile(moduleFile) { 147 err = errors.Warning("sources: parse work failed").WithMeta("work", path). 148 WithCause(errors.Warning("sources: replace mod file was not found"). 149 WithMeta("mod", moduleFile)) 150 return 151 } 152 modData, readModErr := os.ReadFile(moduleFile) 153 if readModErr != nil { 154 err = errors.Warning("sources: parse work failed").WithMeta("work", path). 155 WithCause(errors.Warning("sources: read replace mod file failed").WithCause(readModErr).WithMeta("mod", moduleFile)) 156 return 157 } 158 mf, parseModErr := modfile.Parse(moduleFile, modData, nil) 159 if parseModErr != nil { 160 err = errors.Warning("sources: parse work failed").WithMeta("work", path). 161 WithCause(errors.Warning("sources: parse replace mod file failed").WithCause(parseModErr).WithMeta("mod", moduleFile)) 162 return 163 } 164 work.Replaces = append(work.Replaces, &Module{ 165 Dir: "", 166 Path: replace.Old.Path, 167 Version: replace.Old.Version, 168 Requires: nil, 169 Work: nil, 170 Replace: &Module{ 171 Dir: replaceDir, 172 Path: mf.Module.Mod.Path, 173 Version: mf.Module.Mod.Version, 174 Requires: nil, 175 Work: nil, 176 Replace: nil, 177 locker: &sync.Mutex{}, 178 parsed: false, 179 types: nil, 180 }, 181 locker: &sync.Mutex{}, 182 parsed: false, 183 sources: nil, 184 builtinTypes: map[string]*Type{}, 185 types: nil, 186 }) 187 } 188 } 189 work.parsed = true 190 return 191 }