github.com/pf-qiu/concourse/v6@v6.7.3-0.20201207032516-1f455d73275f/fly/commands/internal/executehelpers/inputs.go (about)

     1  package executehelpers
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"os"
     7  	"path/filepath"
     8  	"sync"
     9  
    10  	"github.com/pf-qiu/concourse/v6/atc"
    11  	"github.com/pf-qiu/concourse/v6/fly/commands/internal/flaghelpers"
    12  	"github.com/pf-qiu/concourse/v6/fly/ui/progress"
    13  	"github.com/pf-qiu/concourse/v6/go-concourse/concourse"
    14  	"github.com/vbauerster/mpb/v4"
    15  )
    16  
    17  type Input struct {
    18  	Name string
    19  	Path string
    20  
    21  	Plan atc.Plan
    22  }
    23  
    24  func 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.PipelineRef.Name == "" && 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  
   114  func 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  
   122  func 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  
   138  func 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  
   147  func 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  
   156  func 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  
   207  func 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.PipelineRef.Name == "" && inputsFrom.JobName == "" {
   211  		return kvMap, nil, nil, nil
   212  	}
   213  
   214  	buildInputs, found, err := team.BuildInputsForJob(inputsFrom.PipelineRef, 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.PipelineRef.String(), inputsFrom.JobName)
   221  	}
   222  
   223  	versionedResourceTypes, found, err := team.VersionedResourceTypes(inputsFrom.PipelineRef)
   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.PipelineRef.String())
   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  
   265  func 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  }