You are an expert in writing code in many different languages. Your goal is to perform code completion for the following code, keeping in mind the rest of the code and the file meta data.
    Metadata details:
    filename: pipeline_importer.go
    path of file: ./repos/cds/engine/api/pipeline
    
    the code of the file until where you have to start completion: package pipeline

import (
	"context"
	"time"

	"github.com/go-gorp/gorp"
	"github.com/rockbears/log"

	"github.com/ovh/cds/engine/api/action"
	"github.com/ovh/cds/engine/api/ascode"
	"github.com/ovh/cds/engine/api/group"
	"github.com/ovh/cds/engine/cache"
	"github.com/ovh/cds/sdk"
)

//ImportUpdate import and update the pipeline in the project
func ImportUpdate(ctx context.Context, db gorp.SqlExecutor, proj sdk.Project, pip *sdk.Pipeline, msgChan chan<- sdk.Message, opts ImportOptions) error {
	t := time.Now()
	log.Debug(ctx, "ImportUpdate> Begin")
	defer log.Debug(ctx, "ImportUpdate> End (%d ns)", time.Since(t).Nanoseconds())

	oldPipeline, err := LoadPipeline(ctx, db,
		proj.Key,
		pip.Name, true)
	if err != nil {
		return sdk.WrapError(err, "Unable to load pipeline %s %s", proj.Key, pip.Name)
	}

	if opts.Force && opts.FromRepository == "" {
		if oldPipeline.FromRepository != "" {
			if err := ascode.DeleteEventsPipelineOnlyFromRepoName(ctx, db, oldPipeline.FromRepository, oldPipeline.ID, oldPipeline.Name); err != nil {
				return sdk.WrapError(err, "unable to delete as_code_event for %s on repo %s", pip.Name, pip.FromRepository)
			}
			msgChan <- sdk.NewMessage(sdk.MsgPipelineDetached, pip.Name, oldPipeline.FromRepository)
		}
		log.Debug(ctx, "ImportUpdate>> Force import pipeline %s in project %s without fromRepository", pip.Name, proj
    
func ImportUpdate(ctx context.Context, db gorp.SqlExecutor, proj sdk.Project, pip *sdk.Pipeline, msgChan chan<- sdk.Message, opts ImportOptions) error {
	t := time.Now()
	log.Debug(ctx, "ImportUpdate> Begin")
	defer log.Debug(ctx, "ImportUpdate> End (%d ns)", time.Since(t).Nanoseconds())

	oldPipeline, err := LoadPipeline(ctx, db,
		proj.Key,
		pip.Name, true)
	if err != nil {
		return sdk.WrapError(err, "Unable to load pipeline %s %s", proj.Key, pip.Name)
	}

	if opts.Force && opts.FromRepository == "" {
		if oldPipeline.FromRepository != "" {
			if err := ascode.DeleteEventsPipelineOnlyFromRepoName(ctx, db, oldPipeline.FromRepository, oldPipeline.ID, oldPipeline.Name); err != nil {
				return sdk.WrapError(err, "unable to delete as_code_event for %s on repo %s", pip.Name, pip.FromRepository)
			}
			msgChan <- sdk.NewMessage(sdk.MsgPipelineDetached, pip.Name, oldPipeline.FromRepository)
		}
		log.Debug(ctx, "ImportUpdate>> Force import pipeline %s in project %s without fromRepository", pip.Name, proj.Key)
	} else if oldPipeline.FromRepository != "" && pip.FromRepository != oldPipeline.FromRepository {
		return sdk.WrapError(sdk.ErrPipelineAsCodeOverride, "unable to update as code pipeline %q old repo:%s to:%s.", pip.Name, oldPipeline.FromRepository, pip.FromRepository)
	}

	// check that action used by job can be used by pipeline's project
	groupIDs := make([]int64, 0, len(proj.ProjectGroups)+1)
	groupIDs = append(groupIDs, group.SharedInfraGroup.ID)
	for i := range proj.ProjectGroups {
		groupIDs = append(groupIDs, proj.ProjectGroups[i].Group.ID)
	}

	rx := sdk.NamePatternSpaceRegex
	pip.ID = oldPipeline.ID

	// Delete old stages
	for _, s := range oldPipeline.Stages {
		if err := DeleteStageByID(ctx, db, &s); err != nil {
			return sdk.WrapError(err, "unable to delete stage %d", s.ID)
		}
	}

	// delete old parameters
	if err := DeleteAllParameterFromPipeline(db, oldPipeline.ID); err != nil {
		return sdk.WrapError(err, "unable to delete pipeline parameters for pipeline %d", oldPipeline.ID)
	}

	// Insert new stages
	for i := range pip.Stages {
		s := &pip.Stages[i]
		// stage name mandatory if there are many stages
		if len(pip.Stages) > 1 && !rx.MatchString(s.Name) {
			return sdk.NewErrorFrom(sdk.ErrInvalidName, "stage name '%s' should match pattern %s", s.Name, sdk.NamePatternSpace)
		}

		//Insert stage
		log.Debug(ctx, "Inserting stage %s", s.Name)
		s.PipelineID = pip.ID
		if err := InsertStage(db, s); err != nil {
			return sdk.WrapError(err, "Unable to insert stage %s in %s", s.Name, pip.Name)
		}
		//Insert stage's Jobs
		for x := range s.Jobs {
			jobAction := &s.Jobs[x]
			if errs := CheckJob(ctx, db, jobAction); errs != nil {
				log.Debug(ctx, "CheckJob > %s", errs)
				return errs
			}
			if err := action.CheckChildrenForGroupIDs(ctx, db, &jobAction.Action, groupIDs); err != nil {
				return err
			}
			jobAction.PipelineStageID = s.ID
			jobAction.Action.Type = sdk.JoinedAction
			log.Debug(ctx, "Creating job %s on stage %s on pipeline %s", jobAction.Action.Name, s.Name, pip.Name)
			if err := InsertJob(db, jobAction, s.ID, pip); err != nil {
				return sdk.WrapError(err, "Unable to insert job %s in %s", jobAction.Action.Name, pip.Name)
			}
			if msgChan != nil {
				msgChan <- sdk.NewMessage(sdk.MsgPipelineJobAdded, jobAction.Action.Name, s.Name)
			}
		}
		if msgChan != nil {
			msgChan <- sdk.NewMessage(sdk.MsgPipelineStageAdded, s.Name)
		}

	}

	// Insert new parameters
	for _, param := range pip.Parameter {
		if err := InsertParameterInPipeline(db, pip.ID, &param); err != nil {
			return sdk.WrapError(err, "cannot insert parameter %s", param.Name)
		}
	}

	errU := UpdatePipeline(db, pip)

	return sdk.WrapError(errU, "ImportUpdate> cannot update pipeline")
}