1package executehelpers 2 3import ( 4 "errors" 5 "fmt" 6 "os" 7 "path/filepath" 8 "sync" 9 10 "github.com/concourse/concourse/atc" 11 "github.com/concourse/concourse/fly/commands/internal/flaghelpers" 12 "github.com/concourse/concourse/fly/ui/progress" 13 "github.com/concourse/concourse/go-concourse/concourse" 14 "github.com/vbauerster/mpb/v4" 15) 16 17type Input struct { 18 Name string 19 Path string 20 21 Plan atc.Plan 22} 23 24func DetermineInputs( 25 fact atc.PlanFactory, 26 team concourse.Team, 27 taskInputs []atc.TaskInputConfig, 28 localInputMappings []flaghelpers.InputPairFlag, 29 userInputMappings []flaghelpers.InputMappingPairFlag, 30 jobInputImage string, 31 inputsFrom flaghelpers.JobFlag, 32 includeIgnored bool, 33 platform string, 34 tags []string, 35) ([]Input, map[string]string, *atc.ImageResource, atc.VersionedResourceTypes, error) { 36 inputMappings := ConvertInputMappings(userInputMappings) 37 38 err := CheckForUnknownInputMappings(localInputMappings, taskInputs) 39 if err != nil { 40 return nil, nil, nil, nil, err 41 } 42 43 err = CheckForInputType(localInputMappings) 44 if err != nil { 45 return nil, nil, nil, nil, err 46 } 47 48 if inputsFrom.PipelineName == "" && inputsFrom.JobName == "" { 49 wd, err := os.Getwd() 50 if err != nil { 51 return nil, nil, nil, nil, err 52 } 53 54 required := false 55 for _, input := range taskInputs { 56 if input.Name == filepath.Base(wd) { 57 required = true 58 break 59 } 60 } 61 62 provided := false 63 for _, input := range localInputMappings { 64 if input.Name == filepath.Base(wd) { 65 provided = true 66 break 67 } 68 } 69 70 if required && !provided { 71 localInputMappings = append(localInputMappings, flaghelpers.InputPairFlag{ 72 Name: filepath.Base(wd), 73 Path: ".", 74 }) 75 } 76 } 77 78 inputsFromLocal, err := GenerateLocalInputs(fact, team, localInputMappings, includeIgnored, platform, tags) 79 if err != nil { 80 return nil, nil, nil, nil, err 81 } 82 83 inputsFromJob, imageResourceFromJob, resourceTypes, err := FetchInputsFromJob(fact, team, inputsFrom, jobInputImage) 84 if err != nil { 85 return nil, nil, nil, nil, err 86 } 87 88 inputs := []Input{} 89 for _, taskInput := range taskInputs { 90 input, found := inputsFromLocal[taskInput.Name] 91 if !found { 92 93 jobInputName := taskInput.Name 94 if name, ok := inputMappings[taskInput.Name]; ok { 95 jobInputName = name 96 } 97 98 input, found = inputsFromJob[jobInputName] 99 if !found { 100 if taskInput.Optional { 101 continue 102 } else { 103 return nil, nil, nil, nil, fmt.Errorf("missing required input `%s`", taskInput.Name) 104 } 105 } 106 } 107 108 inputs = append(inputs, input) 109 } 110 111 return inputs, inputMappings, imageResourceFromJob, resourceTypes, nil 112} 113 114func ConvertInputMappings(variables []flaghelpers.InputMappingPairFlag) map[string]string { 115 inputMappings := map[string]string{} 116 for _, flag := range variables { 117 inputMappings[flag.Name] = flag.Value 118 } 119 return inputMappings 120} 121 122func CheckForInputType(inputMaps []flaghelpers.InputPairFlag) error { 123 for _, i := range inputMaps { 124 if i.Path != "" { 125 fi, err := os.Stat(i.Path) 126 if err != nil { 127 return err 128 } 129 switch mode := fi.Mode(); { 130 case mode.IsRegular(): 131 return errors.New(i.Path + " not a folder") 132 } 133 } 134 } 135 return nil 136} 137 138func CheckForUnknownInputMappings(inputMappings []flaghelpers.InputPairFlag, validInputs []atc.TaskInputConfig) error { 139 for _, inputMapping := range inputMappings { 140 if !TaskInputsContainsName(validInputs, inputMapping.Name) { 141 return fmt.Errorf("unknown input `%s`", inputMapping.Name) 142 } 143 } 144 return nil 145} 146 147func TaskInputsContainsName(inputs []atc.TaskInputConfig, name string) bool { 148 for _, input := range inputs { 149 if input.Name == name { 150 return true 151 } 152 } 153 return false 154} 155 156func GenerateLocalInputs( 157 fact atc.PlanFactory, 158 team concourse.Team, 159 inputMappings []flaghelpers.InputPairFlag, 160 includeIgnored bool, 161 platform string, 162 tags []string, 163) (map[string]Input, error) { 164 inputs := map[string]Input{} 165 166 artifacts := new(sync.Map) 167 168 prog := progress.New() 169 170 for _, mapping := range inputMappings { 171 name := mapping.Name 172 path := mapping.Path 173 174 prog.Go("uploading "+name, func(bar *mpb.Bar) error { 175 artifact, err := Upload(bar, team, path, includeIgnored, platform, tags) 176 if err != nil { 177 return err 178 } 179 180 artifacts.Store(name, artifact) 181 182 return nil 183 }) 184 } 185 186 err := prog.Wait() 187 if err != nil { 188 return nil, err 189 } 190 191 for _, mapping := range inputMappings { 192 val, _ := artifacts.Load(mapping.Name) 193 194 inputs[mapping.Name] = Input{ 195 Name: mapping.Name, 196 Path: mapping.Path, 197 Plan: fact.NewPlan(atc.ArtifactInputPlan{ 198 ArtifactID: val.(atc.WorkerArtifact).ID, 199 Name: mapping.Name, 200 }), 201 } 202 } 203 204 return inputs, nil 205} 206 207func FetchInputsFromJob(fact atc.PlanFactory, team concourse.Team, inputsFrom flaghelpers.JobFlag, imageName string) (map[string]Input, *atc.ImageResource, atc.VersionedResourceTypes, error) { 208 kvMap := map[string]Input{} 209 210 if inputsFrom.PipelineName == "" && inputsFrom.JobName == "" { 211 return kvMap, nil, nil, nil 212 } 213 214 buildInputs, found, err := team.BuildInputsForJob(inputsFrom.PipelineName, inputsFrom.JobName) 215 if err != nil { 216 return nil, nil, nil, err 217 } 218 219 if !found { 220 return nil, nil, nil, fmt.Errorf("build inputs for %s/%s not found", inputsFrom.PipelineName, inputsFrom.JobName) 221 } 222 223 versionedResourceTypes, found, err := team.VersionedResourceTypes(inputsFrom.PipelineName) 224 if err != nil { 225 return nil, nil, nil, err 226 } 227 228 if !found { 229 return nil, nil, nil, fmt.Errorf("versioned resource types of %s not found", inputsFrom.PipelineName) 230 } 231 232 var imageResource *atc.ImageResource 233 if imageName != "" { 234 imageResource, found, err = FetchImageResourceFromJobInputs(buildInputs, imageName) 235 if err != nil { 236 return nil, nil, nil, err 237 } 238 239 if !found { 240 return nil, nil, nil, fmt.Errorf("image resource %s not found", imageName) 241 } 242 } 243 244 for _, buildInput := range buildInputs { 245 version := buildInput.Version 246 247 kvMap[buildInput.Name] = Input{ 248 Name: buildInput.Name, 249 250 Plan: fact.NewPlan(atc.GetPlan{ 251 Name: buildInput.Name, 252 Type: buildInput.Type, 253 Source: buildInput.Source, 254 Version: &version, 255 Params: buildInput.Params, 256 Tags: buildInput.Tags, 257 VersionedResourceTypes: versionedResourceTypes, 258 }), 259 } 260 } 261 262 return kvMap, imageResource, versionedResourceTypes, nil 263} 264 265func FetchImageResourceFromJobInputs(inputs []atc.BuildInput, imageName string) (*atc.ImageResource, bool, error) { 266 267 for _, input := range inputs { 268 if input.Name == imageName { 269 version := input.Version 270 imageResource := atc.ImageResource{ 271 Type: input.Type, 272 Source: input.Source, 273 Version: version, 274 Params: input.Params, 275 } 276 return &imageResource, true, nil 277 } 278 } 279 280 return nil, false, nil 281} 282