diff --git a/alpha/action/migrate.go b/alpha/action/migrate.go index 962cd6489..0a689108d 100644 --- a/alpha/action/migrate.go +++ b/alpha/action/migrate.go @@ -5,6 +5,7 @@ import ( "fmt" "os" + "github.com/operator-framework/operator-registry/alpha/action/migrations" "github.com/operator-framework/operator-registry/alpha/declcfg" "github.com/operator-framework/operator-registry/pkg/image" ) @@ -12,7 +13,7 @@ import ( type Migrate struct { CatalogRef string OutputDir string - Level string + Level migrations.MigrationToken WriteFunc declcfg.WriteFunc FileExt string diff --git a/alpha/action/migrations/migrations.go b/alpha/action/migrations/migrations.go index 6f4e3a3ed..143282132 100644 --- a/alpha/action/migrations/migrations.go +++ b/alpha/action/migrations/migrations.go @@ -9,20 +9,31 @@ import ( "github.com/operator-framework/operator-registry/alpha/declcfg" ) +type MigrationToken string + +const MigrationTokenInvalid MigrationToken = "" + type Migration interface { + Token() MigrationToken Name() string Help() string Migrate(*declcfg.DeclarativeConfig) error } func newMigration(name string, help string, fn func(config *declcfg.DeclarativeConfig) error) Migration { - return &simpleMigration{name: name, help: help, fn: fn} + s := strings.ReplaceAll(help, "`", "\"") + return &simpleMigration{token: MigrationToken(name), name: name, help: s, fn: fn} } type simpleMigration struct { - name string - help string - fn func(*declcfg.DeclarativeConfig) error + token MigrationToken + name string + help string + fn func(*declcfg.DeclarativeConfig) error +} + +func (s simpleMigration) Token() MigrationToken { + return s.token } func (s simpleMigration) Name() string { @@ -41,11 +52,20 @@ type Migrations struct { Migrations []Migration } -func GetLastMigrationName() string { +func GetLastMigration() MigrationToken { if len(allMigrations) == 0 { return "" } - return allMigrations[len(allMigrations)-1].Name() + return allMigrations[len(allMigrations)-1].Token() +} + +func ValidateName(name string) (MigrationToken, error) { + for _, migration := range allMigrations { + if migration.Name() == name { + return migration.Token(), nil + } + } + return MigrationTokenInvalid, fmt.Errorf("unknown migration level %q", name) } // allMigrations represents the migration catalog @@ -54,7 +74,7 @@ var allMigrations = []Migration{ bundleObjectToCSVMetadata, } -func NewMigrations(level string) (*Migrations, error) { +func NewMigrations(level MigrationToken) (*Migrations, error) { if level == "" { return &Migrations{}, nil } @@ -65,7 +85,7 @@ func NewMigrations(level string) (*Migrations, error) { keep := migrations[:0] for _, migration := range migrations { keep = append(keep, migration) - if migration.Name() == level { + if migration.Token() == level { found = true break } @@ -84,9 +104,9 @@ func HelpText() string { help.WriteString(" (no migrations available in this version)\n") } - tabber := tabwriter.NewWriter(&help, 20, 30, 1, '\t', tabwriter.AlignRight) + tabber := tabwriter.NewWriter(&help, 8, 8, 1, '\t', 0) for _, migration := range allMigrations { - fmt.Fprintf(tabber, " - %s\t%s\n", migration.Name(), migration.Help()) + fmt.Fprintf(tabber, " - %s\t%s\n", migration.Name(), migration.Help()) } tabber.Flush() return help.String() diff --git a/alpha/action/render.go b/alpha/action/render.go index 75ea58a07..cf7e1bb2f 100644 --- a/alpha/action/render.go +++ b/alpha/action/render.go @@ -54,7 +54,7 @@ type Render struct { Refs []string Registry image.Registry AllowedRefMask RefType - MigrationLevel string + MigrationLevel migrations.MigrationToken ImageRefTemplate *template.Template skipSqliteDeprecationLog bool @@ -414,7 +414,7 @@ func moveBundleObjectsToEndOfPropertySlices(cfg *declcfg.DeclarativeConfig) { } } -func migrate(cfg *declcfg.DeclarativeConfig, migrateLevel string) error { +func migrate(cfg *declcfg.DeclarativeConfig, migrateLevel migrations.MigrationToken) error { mobj, err := migrations.NewMigrations(migrateLevel) if err != nil { return err diff --git a/alpha/template/basic/basic.go b/alpha/template/basic/basic.go index fc467162e..d270560ba 100644 --- a/alpha/template/basic/basic.go +++ b/alpha/template/basic/basic.go @@ -9,6 +9,7 @@ import ( "k8s.io/apimachinery/pkg/util/yaml" "github.com/operator-framework/operator-registry/alpha/action" + "github.com/operator-framework/operator-registry/alpha/action/migrations" "github.com/operator-framework/operator-registry/alpha/declcfg" "github.com/operator-framework/operator-registry/pkg/image" ) @@ -17,7 +18,7 @@ const schema string = "olm.template.basic" type Template struct { Registry image.Registry - MigrationLevel string + MigrationLevel migrations.MigrationToken } type BasicTemplate struct { diff --git a/alpha/template/semver/types.go b/alpha/template/semver/types.go index 458252321..8dc777ec9 100644 --- a/alpha/template/semver/types.go +++ b/alpha/template/semver/types.go @@ -5,6 +5,7 @@ import ( "github.com/blang/semver/v4" + "github.com/operator-framework/operator-registry/alpha/action/migrations" "github.com/operator-framework/operator-registry/pkg/image" ) @@ -12,7 +13,7 @@ import ( type Template struct { Data io.Reader Registry image.Registry - MigrationLevel string + MigrationLevel migrations.MigrationToken } // IO structs -- BEGIN diff --git a/cmd/opm/alpha/template/basic.go b/cmd/opm/alpha/template/basic.go index 3729df960..f09f6498a 100644 --- a/cmd/opm/alpha/template/basic.go +++ b/cmd/opm/alpha/template/basic.go @@ -16,7 +16,8 @@ import ( func newBasicTemplateCmd() *cobra.Command { var ( - template basic.Template + template basic.Template + migrateLevel string ) cmd := &cobra.Command{ Use: "basic basic-template-file", @@ -63,6 +64,14 @@ When FILE is '-' or not provided, the template is read from standard input`, template.Registry = reg + if migrateLevel != "" { + token, err := migrations.ValidateName(migrateLevel) + if err != nil { + log.Fatal(err) + } + template.MigrationLevel = token + } + // only taking first file argument cfg, err := template.Render(cmd.Context(), data) if err != nil { @@ -75,7 +84,7 @@ When FILE is '-' or not provided, the template is read from standard input`, }, } - cmd.Flags().StringVar(&template.MigrationLevel, "migrate-level", "", "Name of the last migration to run (default: none)\n"+migrations.HelpText()) + cmd.Flags().StringVar(&migrateLevel, "migrate-level", "", "Name of the last migration to run (default: none)\n"+migrations.HelpText()) return cmd } diff --git a/cmd/opm/alpha/template/semver.go b/cmd/opm/alpha/template/semver.go index 7caf93036..a74b2975d 100644 --- a/cmd/opm/alpha/template/semver.go +++ b/cmd/opm/alpha/template/semver.go @@ -72,6 +72,13 @@ When FILE is '-' or not provided, the template is read from standard input`, Data: data, Registry: reg, } + if migrateLevel != "" { + token, err := migrations.ValidateName(migrateLevel) + if err != nil { + log.Fatal(err) + } + template.MigrationLevel = token + } out, err := template.Render(cmd.Context()) if err != nil { log.Fatalf("semver %q: %v", source, err) diff --git a/cmd/opm/migrate/cmd.go b/cmd/opm/migrate/cmd.go index 501763090..caf9b498d 100644 --- a/cmd/opm/migrate/cmd.go +++ b/cmd/opm/migrate/cmd.go @@ -14,8 +14,9 @@ import ( func NewCmd() *cobra.Command { var ( - migrate action.Migrate - output string + migrate action.Migrate + migrateLevel string + output string ) cmd := &cobra.Command{ Use: "migrate ", @@ -43,6 +44,14 @@ parsers that assume that a file contains exactly one valid JSON object. log.Fatalf("invalid --output value %q, expected (json|yaml)", output) } + if migrateLevel != "" { + level, err := migrations.ValidateName(migrateLevel) + if err != nil { + log.Fatal(err) + } + migrate.Level = level + } + logrus.Infof("rendering index %q as file-based catalog", migrate.CatalogRef) if err := migrate.Run(cmd.Context()); err != nil { logrus.New().Fatal(err) @@ -52,7 +61,7 @@ parsers that assume that a file contains exactly one valid JSON object. }, } cmd.Flags().StringVarP(&output, "output", "o", "json", "Output format (json|yaml)") - cmd.Flags().StringVar(&migrate.Level, "migrate-level", "", "Name of the last migration to run (default: none)\n"+migrations.HelpText()) + cmd.Flags().StringVar(&migrateLevel, "migrate-level", "", "Name of the last migration to run (default: none)\n"+migrations.HelpText()) return cmd } diff --git a/cmd/opm/render/cmd.go b/cmd/opm/render/cmd.go index ebc8bb69d..7c5b3edbc 100644 --- a/cmd/opm/render/cmd.go +++ b/cmd/opm/render/cmd.go @@ -23,6 +23,7 @@ func NewCmd(showAlphaHelp bool) *cobra.Command { imageRefTemplate string deprecatedMigrateFlag bool + migrateLevel string ) cmd := &cobra.Command{ Use: "render [catalog-image | catalog-directory | bundle-image | bundle-directory | sqlite-file]...", @@ -68,7 +69,13 @@ database files. // if the deprecated flag was used, set the level explicitly to the last migration to perform all migrations if deprecatedMigrateFlag { - render.MigrationLevel = migrations.GetLastMigrationName() + render.MigrationLevel = migrations.GetLastMigration() + } else if migrateLevel != "" { + level, err := migrations.ValidateName(migrateLevel) + if err != nil { + log.Fatal(err) + } + render.MigrationLevel = level } cfg, err := render.Run(cmd.Context()) @@ -83,7 +90,7 @@ database files. } cmd.Flags().StringVarP(&output, "output", "o", "json", "Output format of the streamed file-based catalog objects (json|yaml)") - cmd.Flags().StringVar(&render.MigrationLevel, "migrate-level", "", "Name of the last migration to run (default: none)\n"+migrations.HelpText()) + cmd.Flags().StringVar(&migrateLevel, "migrate-level", "", "Name of the last migration to run (default: none)\n"+migrations.HelpText()) cmd.Flags().BoolVar(&deprecatedMigrateFlag, "migrate", false, "Perform migrations on the rendered FBC") cmd.Flags().MarkDeprecated("migrate", "use --migrate-level instead") cmd.MarkFlagsMutuallyExclusive("migrate", "migrate-level")