tools/mc2bq/main.go (154 lines of code) (raw):
// Copyright 2023 Google LLC All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// Package main implements the Migration Center Exporter tool
package main
import (
"encoding/json"
"flag"
"fmt"
"os"
"github.com/GoogleCloudPlatform/migrationcenter-utils/tools/mc2bq/pkg/export"
"github.com/GoogleCloudPlatform/migrationcenter-utils/tools/mc2bq/pkg/messages"
"github.com/GoogleCloudPlatform/migrationcenter-utils/tools/mc2bq/pkg/schema"
)
type cliAction string
const (
actionInvalid = ""
actionVersion = "version"
actionDumpSchema = "dump-schema"
actionExport = "export"
actionExitFailure = "exit"
)
func parseFlags(params *export.Params, argv []string) (cliAction, error) {
var schemaPath string
var fs flag.FlagSet
params.DatasetID = os.Getenv("MC2BQ_DATASET")
params.TablePrefix = os.Getenv("MC2BQ_TABLE_PREFIX")
// set default region
defaultRegion := "us-central1"
if gcloudRegion := os.Getenv("REGION"); gcloudRegion != "" {
defaultRegion = gcloudRegion
}
if gcloudRegion := os.Getenv("MC2BQ_REGION"); gcloudRegion != "" {
defaultRegion = gcloudRegion
}
// set default project from env
params.ProjectID = os.Getenv("PROJECT")
if projectFromEnv := os.Getenv("MC2BQ_PROJECT"); projectFromEnv != "" {
params.ProjectID = projectFromEnv
}
fs.Usage = func() {
fmt.Fprintf(os.Stderr, "Usage: %s [FLAGS...] <PROJECT> <DATASET> [TABLE-PREFIX]\n", os.Args[0])
fmt.Fprintln(os.Stderr, messages.ExportCmdDescription.String())
fmt.Fprintln(os.Stderr, "")
fs.PrintDefaults()
}
fs.StringVar(
¶ms.TargetProjectID,
"target-project",
"",
messages.ParamDescriptionTargetProject.String())
fs.StringVar(
¶ms.Region,
"region",
defaultRegion,
messages.ParamDescriptionRegion.String())
fs.BoolVar(
¶ms.Force,
"force",
false,
messages.ParamDescriptionForce.String(),
)
fs.StringVar(
&schemaPath,
"schema-path",
"",
messages.ParamDescriptionSchemaPath.String(),
)
var versionFlag bool
fs.BoolVar(&versionFlag, "version", false, messages.ParamDescriptionVersion.String())
var dumpEmbeddedSchemaFlag bool
fs.BoolVar(&dumpEmbeddedSchemaFlag, "dump-embedded-schema", false, messages.ParamDescriptionDumpSchema.String())
err := fs.Parse(argv)
if err != nil {
return actionInvalid, err
}
// Keep right after parse so we ignore all other validations
if versionFlag {
return actionVersion, nil
}
// Keep right after version flag check so we ignore all other validations
if dumpEmbeddedSchemaFlag {
return actionDumpSchema, nil
}
args := fs.Args()
if len(args) > 0 {
params.ProjectID = fs.Arg(0)
}
if len(args) > 1 {
params.DatasetID = fs.Arg(1)
}
if len(args) > 2 {
params.TablePrefix = fs.Arg(2)
}
params.Force = params.Force || os.Getenv("MC2BQ_FORCE") != ""
if params.ProjectID == "" || params.DatasetID == "" {
fs.Usage()
return actionExitFailure, nil
}
if params.TargetProjectID == "" {
params.TargetProjectID = os.Getenv("MC2BQ_TARGET_PROJECT")
}
if params.TargetProjectID == "" {
params.TargetProjectID = params.ProjectID
}
if schemaPath == "" {
schemaPath = os.Getenv("MC2BQ_SCHEMA_PATH")
}
params.Schema, err = loadSchemas(schemaPath)
if err != nil {
return actionInvalid, err
}
return actionExport, nil
}
func main() {
var params export.Params
action, err := parseFlags(¶ms, os.Args[1:])
if err != nil {
fmt.Fprintf(os.Stderr, "%v\n", messages.WrapError(messages.ErrorParsingFlags, err))
os.Exit(1)
}
switch action {
case actionVersion:
fmt.Printf("mc2bq %s\n", messages.Version)
case actionDumpSchema:
_ = dumpEmbeddedSchema()
case actionExport:
err = export.Export(¶ms)
if err != nil {
fmt.Fprintf(os.Stderr, "%v\n", messages.WrapError(messages.ErrorExportingData, err))
os.Exit(1)
}
case actionExitFailure:
os.Exit(1)
default:
os.Exit(1)
}
}
func loadSchemas(name string) (*schema.ExporterSchema, error) {
if name == "" {
// return defaults
return &schema.EmbeddedSchema, nil
}
rawData, err := os.ReadFile(name)
if err != nil {
return nil, messages.WrapError(messages.ErrorLoadingSchema, err)
}
var schemas schema.ExporterSchema
err = json.Unmarshal(rawData, &schemas)
if err != nil {
return nil, messages.WrapError(messages.ErrorLoadingSchema, err)
}
return &schemas, err
}
func dumpEmbeddedSchema() error {
out, err := json.MarshalIndent(&schema.EmbeddedSchema, "", " ")
if err != nil {
return err
}
os.Stdout.Write(out)
os.Stdout.Write([]byte{'\n'})
return nil
}