func()

in registry/datastore/importer.go [1063:1192]


func (imp *Importer) doImport(ctx context.Context, required step, steps ...step) error {
	var (
		tx                Transactor
		err               error
		pre, repos, blobs bool
	)

	// Assign each valid step to a boolean value. This ensures that we only run a
	// particular step once and in the correct order.
	steps = append(steps, required)
	for _, s := range steps {
		switch s {
		case preImport:
			pre = true
		case repoImport:
			repos = true
		case commonBlobs:
			blobs = true
		default:
			return fmt.Errorf("unknown import step: %v", s)
		}
	}

	var f *os.File
	bar := progressbar.NewOptions(-1,
		progressbar.OptionShowElapsedTimeOnFinish(),
		progressbar.OptionShowDescriptionAtLineEnd(),
		progressbar.OptionSetVisibility(imp.showProgressBar),
	)
	defer bar.Close()

	commonBarOptions = append(commonBarOptions, progressbar.OptionSetVisibility(imp.showProgressBar))

	if imp.showProgressBar {
		fn := fmt.Sprintf("%s-registry-import.log", time.Now().Format(time.RFC3339))
		// nolint: gosec // G304
		f, err = os.OpenFile(fn, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0o600)
		if err != nil {
			return fmt.Errorf("opening log file: %w", err)
		}

		wd, err := os.Getwd()
		if err != nil {
			return fmt.Errorf("getting working directory: %w", err)
		}

		// A little hacky, but we can use a progress bar to show the overall import
		// progress by printing the bar with different descriptions. Otherwise, the
		// progress bars and a regular logger would step over one another.
		_ = bar.Add(1) // Give the bar some state so we can print it.
		imp.printBar(bar, fmt.Sprintf("registry import starting, detailed log written to: %s", filepath.Join(wd, fn)))
	} else {
		f = os.Stdout
	}

	l := log.GetLogger(log.WithContext(ctx), log.WithWriter(f)).WithFields(log.Fields{
		"pre_import":        pre,
		"repository_import": repos,
		"common_blobs":      blobs,
		"dry_run":           imp.dryRun,
	})

	ctx = log.WithLogger(ctx, l)

	// Create a single transaction and roll it back at the end for dry runs.
	if imp.dryRun {
		tx, err = imp.beginTx(ctx)
		if err != nil {
			return fmt.Errorf("beginning dry run transaction: %w", err)
		}
		defer tx.Rollback()
	}

	start := time.Now()
	l.Info("starting metadata import")

	if pre {
		start := time.Now()
		imp.printBar(bar, "step one: import manifests")

		if err := imp.preImportAllRepositories(ctx); err != nil {
			return fmt.Errorf("pre importing all repositories: %w", err)
		}

		imp.printBar(bar, fmt.Sprintf("step one completed in %s", time.Since(start).Round(time.Second)))
	}

	if repos {
		start := time.Now()
		imp.printBar(bar, "step two: import tags")

		if err := imp.importAllRepositoriesImpl(ctx); err != nil {
			return fmt.Errorf("importing all repositories: %w", err)
		}

		imp.printBar(bar, fmt.Sprintf("step two completed in %s", time.Since(start).Round(time.Second)))
	}

	if blobs {
		start := time.Now()
		imp.printBar(bar, "step three: import blobs")

		if err := imp.importBlobsImpl(ctx); err != nil {
			return fmt.Errorf("importing blobs: %w", err)
		}

		imp.printBar(bar, fmt.Sprintf("step three completed in %s", time.Since(start).Round(time.Second)))
	}

	bar.Describe("registry import complete")

	t := time.Since(start).Seconds()

	if imp.rowCount {
		counters, err := imp.countRows(ctx)
		if err != nil {
			l.WithError(err).Error("counting table rows")
		}

		logCounters := make(map[string]any, len(counters))
		for t, n := range counters {
			logCounters[t] = n
		}
		l = l.WithFields(logCounters)
	}

	l.WithFields(log.Fields{"duration_s": t}).Info("metadata import complete")

	return err
}