github.com/release-engineering/exodus-rsync@v1.11.2/internal/cmd/cmd.go (about)

     1  package cmd
     2  
     3  import (
     4  	"context"
     5  
     6  	"github.com/release-engineering/exodus-rsync/internal/args"
     7  	"github.com/release-engineering/exodus-rsync/internal/conf"
     8  	"github.com/release-engineering/exodus-rsync/internal/diag"
     9  	"github.com/release-engineering/exodus-rsync/internal/gw"
    10  	"github.com/release-engineering/exodus-rsync/internal/log"
    11  	"github.com/release-engineering/exodus-rsync/internal/rsync"
    12  )
    13  
    14  var ext = struct {
    15  	conf  conf.Interface
    16  	rsync rsync.Interface
    17  	gw    gw.Interface
    18  	log   log.Interface
    19  	diag  diag.Interface
    20  }{
    21  	conf.Package,
    22  	rsync.Package,
    23  	gw.Package,
    24  	log.Package,
    25  	diag.Package,
    26  }
    27  
    28  // This version should be written at build time, see Makefile.
    29  var version string = "(unknown version)"
    30  
    31  type mainFunc func(context.Context, conf.Config, args.Config) int
    32  
    33  func invalidMain(ctx context.Context, cfg conf.Config, _ args.Config) int {
    34  	logger := log.FromContext(ctx)
    35  
    36  	logger.F("rsyncmode", cfg.RsyncMode()).Error("Invalid 'rsyncmode' in configuration")
    37  	return 95
    38  }
    39  
    40  // Main is the top-level entry point to the exodus-rsync command.
    41  func Main(rawArgs []string) int {
    42  	ctx, cancel := context.WithCancel(context.Background())
    43  	defer cancel()
    44  
    45  	// Before anything else, check for --server or --sender, which
    46  	// indicate rsync itself is trying to do something.
    47  	// If either are provided, pass through to real rsync.
    48  	for _, arg := range rawArgs {
    49  		if arg == "--server" || arg == "--sender" {
    50  			logger := ext.log.NewLogger(args.Config{})
    51  			ctx = log.NewContext(ctx, logger)
    52  			return rsyncRaw(ctx, rawArgs)
    53  		}
    54  	}
    55  
    56  	parsedArgs := args.Parse(rawArgs, version, nil)
    57  
    58  	logger := ext.log.NewLogger(parsedArgs)
    59  
    60  	err := parsedArgs.ValidateConfig()
    61  	if err != nil {
    62  		logger.WithField("error", err).Error("argument validation failed")
    63  		return 23
    64  	}
    65  
    66  	ctx = log.NewContext(ctx, logger)
    67  
    68  	cfg, err := ext.conf.Load(ctx, parsedArgs)
    69  	if err != nil {
    70  		if _, ok := err.(*conf.MissingConfigFile); ok {
    71  			// Failed to find any config files, fallback to rsync
    72  			logger.WithField("error", err).Debug("setting rsyncmode to 'rsync'")
    73  			return rsyncMain(ctx, nil, parsedArgs)
    74  		}
    75  		logger.WithField("error", err).Error("can't load config")
    76  		return 23
    77  	}
    78  
    79  	var env conf.Config = cfg.EnvironmentForDest(ctx, parsedArgs.Dest)
    80  	var main mainFunc = invalidMain
    81  
    82  	if env == nil || env.RsyncMode() == "rsync" {
    83  		main = rsyncMain
    84  	} else if env.RsyncMode() == "exodus" {
    85  		main = exodusMain
    86  	} else if env.RsyncMode() == "mixed" {
    87  		main = mixedMain
    88  	}
    89  
    90  	if env == nil {
    91  		env = cfg
    92  	}
    93  
    94  	logger.StartPlatformLogger(env)
    95  
    96  	// We've now decided more or less what we're going to do.
    97  	// In diagnostic mode, before proceeding we will *also* dump
    98  	// a wealth of information about the current environment,
    99  	// configuration and command, then proceed with publish
   100  	// afterward.
   101  	if env.Diag() {
   102  		ext.diag.Run(ctx, env, parsedArgs)
   103  	}
   104  
   105  	return main(ctx, env, parsedArgs)
   106  }