github.com/pf-qiu/concourse/v6@v6.7.3-0.20201207032516-1f455d73275f/atc/builds/planner.go (about)

     1  package builds
     2  
     3  import (
     4  	"github.com/pf-qiu/concourse/v6/atc"
     5  	"github.com/pf-qiu/concourse/v6/atc/db"
     6  )
     7  
     8  type Planner struct {
     9  	planFactory atc.PlanFactory
    10  }
    11  
    12  func NewPlanner(planFactory atc.PlanFactory) Planner {
    13  	return Planner{
    14  		planFactory: planFactory,
    15  	}
    16  }
    17  
    18  func (planner Planner) Create(
    19  	planConfig atc.StepConfig,
    20  	resources db.SchedulerResources,
    21  	resourceTypes atc.VersionedResourceTypes,
    22  	inputs []db.BuildInput,
    23  ) (atc.Plan, error) {
    24  	visitor := &planVisitor{
    25  		planFactory: planner.planFactory,
    26  
    27  		resources:     resources,
    28  		resourceTypes: resourceTypes,
    29  		inputs:        inputs,
    30  	}
    31  
    32  	err := planConfig.Visit(visitor)
    33  	if err != nil {
    34  		return atc.Plan{}, err
    35  	}
    36  
    37  	return visitor.plan, nil
    38  }
    39  
    40  type planVisitor struct {
    41  	planFactory atc.PlanFactory
    42  
    43  	resources     db.SchedulerResources
    44  	resourceTypes atc.VersionedResourceTypes
    45  	inputs        []db.BuildInput
    46  
    47  	plan atc.Plan
    48  }
    49  
    50  func (visitor *planVisitor) VisitTask(step *atc.TaskStep) error {
    51  	visitor.plan = visitor.planFactory.NewPlan(atc.TaskPlan{
    52  		Name:              step.Name,
    53  		Privileged:        step.Privileged,
    54  		Config:            step.Config,
    55  		ConfigPath:        step.ConfigPath,
    56  		Vars:              step.Vars,
    57  		Tags:              step.Tags,
    58  		Params:            step.Params,
    59  		InputMapping:      step.InputMapping,
    60  		OutputMapping:     step.OutputMapping,
    61  		ImageArtifactName: step.ImageArtifactName,
    62  
    63  		VersionedResourceTypes: visitor.resourceTypes,
    64  	})
    65  
    66  	return nil
    67  }
    68  
    69  func (visitor *planVisitor) VisitGet(step *atc.GetStep) error {
    70  	resourceName := step.Resource
    71  	if resourceName == "" {
    72  		resourceName = step.Name
    73  	}
    74  
    75  	resource, found := visitor.resources.Lookup(resourceName)
    76  	if !found {
    77  		return UnknownResourceError{resourceName}
    78  	}
    79  
    80  	var version atc.Version
    81  	for _, input := range visitor.inputs {
    82  		if input.Name == step.Name {
    83  			version = atc.Version(input.Version)
    84  			break
    85  		}
    86  	}
    87  
    88  	if version == nil {
    89  		return VersionNotProvidedError{step.Name}
    90  	}
    91  
    92  	resource.ApplySourceDefaults(visitor.resourceTypes)
    93  
    94  	visitor.plan = visitor.planFactory.NewPlan(atc.GetPlan{
    95  		Name: step.Name,
    96  
    97  		Type:     resource.Type,
    98  		Resource: resourceName,
    99  		Source:   resource.Source,
   100  		Params:   step.Params,
   101  		Version:  &version,
   102  		Tags:     step.Tags,
   103  
   104  		VersionedResourceTypes: visitor.resourceTypes,
   105  	})
   106  
   107  	return nil
   108  }
   109  
   110  func (visitor *planVisitor) VisitPut(step *atc.PutStep) error {
   111  	logicalName := step.Name
   112  
   113  	resourceName := step.Resource
   114  	if resourceName == "" {
   115  		resourceName = logicalName
   116  	}
   117  
   118  	resource, found := visitor.resources.Lookup(resourceName)
   119  	if !found {
   120  		return UnknownResourceError{resourceName}
   121  	}
   122  
   123  	resource.ApplySourceDefaults(visitor.resourceTypes)
   124  
   125  	atcPutPlan := atc.PutPlan{
   126  		Type:     resource.Type,
   127  		Name:     logicalName,
   128  		Resource: resourceName,
   129  		Source:   resource.Source,
   130  		Params:   step.Params,
   131  		Tags:     step.Tags,
   132  		Inputs:   step.Inputs,
   133  
   134  		VersionedResourceTypes: visitor.resourceTypes,
   135  	}
   136  
   137  	putPlan := visitor.planFactory.NewPlan(atcPutPlan)
   138  
   139  	dependentGetPlan := visitor.planFactory.NewPlan(atc.GetPlan{
   140  		Type:        resource.Type,
   141  		Name:        logicalName,
   142  		Resource:    resourceName,
   143  		VersionFrom: &putPlan.ID,
   144  
   145  		Params: step.GetParams,
   146  		Tags:   step.Tags,
   147  		Source: resource.Source,
   148  
   149  		VersionedResourceTypes: visitor.resourceTypes,
   150  	})
   151  
   152  	visitor.plan = visitor.planFactory.NewPlan(atc.OnSuccessPlan{
   153  		Step: putPlan,
   154  		Next: dependentGetPlan,
   155  	})
   156  
   157  	return nil
   158  }
   159  
   160  func (visitor *planVisitor) VisitDo(step *atc.DoStep) error {
   161  	do := atc.DoPlan{}
   162  
   163  	for _, step := range step.Steps {
   164  		err := step.Config.Visit(visitor)
   165  		if err != nil {
   166  			return err
   167  		}
   168  
   169  		do = append(do, visitor.plan)
   170  	}
   171  
   172  	visitor.plan = visitor.planFactory.NewPlan(do)
   173  
   174  	return nil
   175  }
   176  
   177  func (visitor *planVisitor) VisitAggregate(step *atc.AggregateStep) error {
   178  	do := atc.AggregatePlan{}
   179  
   180  	for _, sub := range step.Steps {
   181  		err := sub.Config.Visit(visitor)
   182  		if err != nil {
   183  			return err
   184  		}
   185  
   186  		do = append(do, visitor.plan)
   187  	}
   188  
   189  	visitor.plan = visitor.planFactory.NewPlan(do)
   190  
   191  	return nil
   192  }
   193  
   194  func (visitor *planVisitor) VisitInParallel(step *atc.InParallelStep) error {
   195  	var steps []atc.Plan
   196  
   197  	for _, sub := range step.Config.Steps {
   198  		err := sub.Config.Visit(visitor)
   199  		if err != nil {
   200  			return err
   201  		}
   202  
   203  		steps = append(steps, visitor.plan)
   204  	}
   205  
   206  	visitor.plan = visitor.planFactory.NewPlan(atc.InParallelPlan{
   207  		Steps:    steps,
   208  		Limit:    step.Config.Limit,
   209  		FailFast: step.Config.FailFast,
   210  	})
   211  
   212  	return nil
   213  }
   214  
   215  func (visitor *planVisitor) VisitAcross(step *atc.AcrossStep) error {
   216  	vars := make([]atc.AcrossVar, len(step.Vars))
   217  	for i, v := range step.Vars {
   218  		vars[i] = atc.AcrossVar{
   219  			Var:         v.Var,
   220  			Values:      v.Values,
   221  			MaxInFlight: v.MaxInFlight,
   222  		}
   223  	}
   224  
   225  	acrossPlan := atc.AcrossPlan{
   226  		Vars:     vars,
   227  		Steps:    []atc.VarScopedPlan{},
   228  		FailFast: step.FailFast,
   229  	}
   230  	for _, vals := range cartesianProduct(step.Vars) {
   231  		err := step.Step.Visit(visitor)
   232  		if err != nil {
   233  			return err
   234  		}
   235  		acrossPlan.Steps = append(acrossPlan.Steps, atc.VarScopedPlan{
   236  			Step:   visitor.plan,
   237  			Values: vals,
   238  		})
   239  	}
   240  
   241  	visitor.plan = visitor.planFactory.NewPlan(acrossPlan)
   242  
   243  	return nil
   244  }
   245  
   246  func cartesianProduct(vars []atc.AcrossVarConfig) [][]interface{} {
   247  	if len(vars) == 0 {
   248  		return make([][]interface{}, 1)
   249  	}
   250  	var product [][]interface{}
   251  	subProduct := cartesianProduct(vars[:len(vars)-1])
   252  	for _, vec := range subProduct {
   253  		for _, val := range vars[len(vars)-1].Values {
   254  			product = append(product, append(vec, val))
   255  		}
   256  	}
   257  	return product
   258  }
   259  
   260  func (visitor *planVisitor) VisitSetPipeline(step *atc.SetPipelineStep) error {
   261  	visitor.plan = visitor.planFactory.NewPlan(atc.SetPipelinePlan{
   262  		Name:         step.Name,
   263  		File:         step.File,
   264  		Team:         step.Team,
   265  		Vars:         step.Vars,
   266  		VarFiles:     step.VarFiles,
   267  		InstanceVars: step.InstanceVars,
   268  	})
   269  
   270  	return nil
   271  }
   272  
   273  func (visitor *planVisitor) VisitLoadVar(step *atc.LoadVarStep) error {
   274  	visitor.plan = visitor.planFactory.NewPlan(atc.LoadVarPlan{
   275  		Name:   step.Name,
   276  		File:   step.File,
   277  		Format: step.Format,
   278  		Reveal: step.Reveal,
   279  	})
   280  
   281  	return nil
   282  }
   283  
   284  func (visitor *planVisitor) VisitTry(step *atc.TryStep) error {
   285  	err := step.Step.Config.Visit(visitor)
   286  	if err != nil {
   287  		return err
   288  	}
   289  
   290  	visitor.plan = visitor.planFactory.NewPlan(atc.TryPlan{
   291  		Step: visitor.plan,
   292  	})
   293  
   294  	return nil
   295  }
   296  
   297  func (visitor *planVisitor) VisitTimeout(step *atc.TimeoutStep) error {
   298  	err := step.Step.Visit(visitor)
   299  	if err != nil {
   300  		return err
   301  	}
   302  
   303  	visitor.plan = visitor.planFactory.NewPlan(atc.TimeoutPlan{
   304  		Duration: step.Duration,
   305  		Step:     visitor.plan,
   306  	})
   307  
   308  	return nil
   309  }
   310  
   311  func (visitor *planVisitor) VisitRetry(step *atc.RetryStep) error {
   312  	retryStep := make(atc.RetryPlan, step.Attempts)
   313  
   314  	for i := 0; i < step.Attempts; i++ {
   315  		err := step.Step.Visit(visitor)
   316  		if err != nil {
   317  			return err
   318  		}
   319  
   320  		retryStep[i] = visitor.plan
   321  	}
   322  
   323  	visitor.plan = visitor.planFactory.NewPlan(retryStep)
   324  
   325  	return nil
   326  }
   327  
   328  func (visitor *planVisitor) VisitOnSuccess(step *atc.OnSuccessStep) error {
   329  	plan := atc.OnSuccessPlan{}
   330  
   331  	err := step.Step.Visit(visitor)
   332  	if err != nil {
   333  		return err
   334  	}
   335  
   336  	plan.Step = visitor.plan
   337  
   338  	err = step.Hook.Config.Visit(visitor)
   339  	if err != nil {
   340  		return err
   341  	}
   342  
   343  	plan.Next = visitor.plan
   344  
   345  	visitor.plan = visitor.planFactory.NewPlan(plan)
   346  
   347  	return nil
   348  }
   349  
   350  func (visitor *planVisitor) VisitOnFailure(step *atc.OnFailureStep) error {
   351  	plan := atc.OnFailurePlan{}
   352  
   353  	err := step.Step.Visit(visitor)
   354  	if err != nil {
   355  		return err
   356  	}
   357  
   358  	plan.Step = visitor.plan
   359  
   360  	err = step.Hook.Config.Visit(visitor)
   361  	if err != nil {
   362  		return err
   363  	}
   364  
   365  	plan.Next = visitor.plan
   366  
   367  	visitor.plan = visitor.planFactory.NewPlan(plan)
   368  
   369  	return nil
   370  }
   371  
   372  func (visitor *planVisitor) VisitOnAbort(step *atc.OnAbortStep) error {
   373  	plan := atc.OnAbortPlan{}
   374  
   375  	err := step.Step.Visit(visitor)
   376  	if err != nil {
   377  		return err
   378  	}
   379  
   380  	plan.Step = visitor.plan
   381  
   382  	err = step.Hook.Config.Visit(visitor)
   383  	if err != nil {
   384  		return err
   385  	}
   386  
   387  	plan.Next = visitor.plan
   388  
   389  	visitor.plan = visitor.planFactory.NewPlan(plan)
   390  
   391  	return nil
   392  }
   393  
   394  func (visitor *planVisitor) VisitOnError(step *atc.OnErrorStep) error {
   395  	plan := atc.OnErrorPlan{}
   396  
   397  	err := step.Step.Visit(visitor)
   398  	if err != nil {
   399  		return err
   400  	}
   401  
   402  	plan.Step = visitor.plan
   403  
   404  	err = step.Hook.Config.Visit(visitor)
   405  	if err != nil {
   406  		return err
   407  	}
   408  
   409  	plan.Next = visitor.plan
   410  
   411  	visitor.plan = visitor.planFactory.NewPlan(plan)
   412  
   413  	return nil
   414  }
   415  func (visitor *planVisitor) VisitEnsure(step *atc.EnsureStep) error {
   416  	plan := atc.EnsurePlan{}
   417  
   418  	err := step.Step.Visit(visitor)
   419  	if err != nil {
   420  		return err
   421  	}
   422  
   423  	plan.Step = visitor.plan
   424  
   425  	err = step.Hook.Config.Visit(visitor)
   426  	if err != nil {
   427  		return err
   428  	}
   429  
   430  	plan.Next = visitor.plan
   431  
   432  	visitor.plan = visitor.planFactory.NewPlan(plan)
   433  
   434  	return nil
   435  }