// Copyright (C) The Arvados Authors. All rights reserved. // // SPDX-License-Identifier: AGPL-3.0 package main import ( "context" "flag" "fmt" "io" "os" "path/filepath" "strings" "git.arvados.org/arvados.git/lib/cmd" "git.arvados.org/arvados.git/lib/install" "git.arvados.org/arvados.git/sdk/go/ctxlog" ) var ( handler = cmd.Multi(map[string]cmd.Handler{ "version": cmd.Version, "-version": cmd.Version, "--version": cmd.Version, "build": cmdFunc(build), "testinstall": cmdFunc(testinstall), "_fpm": cmdFunc(fpm), // internal use "_install": install.Command, // internal use }) ) func main() { if len(os.Args) < 2 || strings.HasPrefix(os.Args[1], "-") { parseFlags(os.Args[0], []string{"-help"}, os.Stderr) os.Exit(2) } os.Exit(handler.RunCommand(os.Args[0], os.Args[1:], os.Stdin, os.Stdout, os.Stderr)) } type cmdFunc func(ctx context.Context, opts opts, stdin io.Reader, stdout, stderr io.Writer) error func (cf cmdFunc) RunCommand(prog string, args []string, stdin io.Reader, stdout, stderr io.Writer) int { logger := ctxlog.New(stderr, "text", "info") ctx := ctxlog.Context(context.Background(), logger) opts, ok, code := parseFlags(prog, args, stderr) if !ok { return code } err := cf(ctx, opts, stdin, stdout, stderr) if err != nil { logger.WithError(err).Error("failed") return 1 } return 0 } type opts struct { PackageVersion string PackageDir string PackageChown string RebuildImage bool SourceDir string TargetOS string Maintainer string Vendor string Live string } func parseFlags(prog string, args []string, stderr io.Writer) (_ opts, ok bool, exitCode int) { opts := opts{ SourceDir: ".", TargetOS: "debian:10", Maintainer: "Arvados Package Maintainers ", Vendor: "The Arvados Project", } flags := flag.NewFlagSet("", flag.ContinueOnError) flags.StringVar(&opts.PackageVersion, "package-version", opts.PackageVersion, "package version to build/test, like \"1.2.3\"") flags.StringVar(&opts.SourceDir, "source", opts.SourceDir, "arvados source tree `directory`") flags.StringVar(&opts.PackageDir, "package-dir", opts.PackageDir, "destination `directory` for new package (default is cwd)") flags.StringVar(&opts.PackageChown, "package-chown", opts.PackageChown, "desired `uid:gid` for new package (default is current user:group)") flags.StringVar(&opts.TargetOS, "target-os", opts.TargetOS, "target operating system vendor:version") flags.StringVar(&opts.Maintainer, "package-maintainer", opts.Maintainer, "maintainer to be listed in package metadata") flags.StringVar(&opts.Vendor, "package-vendor", opts.Vendor, "vendor to be listed in package metadata") flags.StringVar(&opts.Live, "live", opts.Live, "(for testinstall) advertise external URLs like https://`example.com`:44xx, use the host's /var/lib/acme/live certificates, listen on the host's external interfaces, and wait for ^C before shutting down") flags.BoolVar(&opts.RebuildImage, "rebuild-image", opts.RebuildImage, "rebuild docker image(s) instead of using existing") flags.Usage = func() { fmt.Fprint(flags.Output(), `Usage: arvados-package [options] Subcommands: build use a docker container to build a package from a checked out version of the arvados source tree testinstall use a docker container to install a package and confirm the resulting installation is functional; optionally, expose the test cluster's services using the host's interfaces and ACME certificates, and leave it up to facilitate interactive testing (see -live option below) version show program version Internally used subcommands: _fpm build a package _install equivalent to "arvados-server install" Automation/integration notes: The first time a given machine runs "build" or "testinstall" (and any time the -rebuild-image is used), new docker images are built, which is quite slow. If you use on-demand VMs to run automated builds, run "build" and "testinstall" once when setting up your initial VM image, and be prepared to rebuild that VM image when package-building slows down (this will happen when new dependencies are introduced). The "build" subcommand, if successful, also runs dpkg-scanpackages to create/replace Packages.gz in the package dir. This enables the "testinstall" subcommand to list the package dir as a source in /etc/apt/sources.*. Options: `) flags.PrintDefaults() } if ok, code := cmd.ParseFlags(flags, prog, args, "", stderr); !ok { return opts, false, code } if opts.SourceDir == "" { d, err := os.Getwd() if err != nil { fmt.Fprintf(stderr, "error getting current working directory: %s\n", err) return opts, false, 1 } opts.SourceDir = d } opts.PackageDir = filepath.Clean(opts.PackageDir) abs, err := filepath.Abs(opts.SourceDir) if err != nil { fmt.Fprintf(stderr, "error resolving source dir %q: %s\n", opts.SourceDir, err) return opts, false, 1 } opts.SourceDir = abs return opts, true, 0 }