~techalchemy/mojo/python3-fixes

« back to all changes in this revision

Viewing changes to mojo/cli.py

  • Committer: Dan Ryan
  • Date: 2020-02-20 14:55:13 UTC
  • Revision ID: dan.ryan@canonical.com-20200220145513-41lqpneq56x26vex
- Move `get_prog` to argument parser `__init__` method
- Add comments arround error handling in CLI
- Undo accidental formatting changes

Show diffs side-by-side

added added

removed removed

Lines of Context:
359
359
    ie. --foo_bar is converted to --foo-bar. Non-option arguments
360
360
    are left untouched.
361
361
    """
 
362
 
 
363
    @staticmethod
 
364
    def get_prog():
 
365
        prog = "mojo"
 
366
        try:
 
367
            prog_name = os.path.basename(sys.argv[0])
 
368
            if prog_name in ("__main__.py", "-c"):
 
369
                prog = "{0} -m mojo".format(sys.executable)
 
370
            else:
 
371
                prog = prog_name
 
372
        except (AttributeError, TypeError, IndexError):
 
373
            pass
 
374
        return prog
 
375
 
 
376
    def __init__(self, *args, **kwargs):
 
377
        if "prog" not in kwargs or kwargs["prog"] is None:
 
378
            kwargs["prog"] = self.get_prog()
 
379
        super(MojoArgumentParser, self).__init__(*args, **kwargs)
 
380
 
362
381
    def add_argument(self, *args, **kwargs):
363
382
        # Replace _ with - to create a consistent cli, no matter
364
383
        # what the callsite chose. We don't need to worry about
384
403
                                                                namespace)
385
404
 
386
405
 
387
 
def get_prog():
388
 
    prog = "mojo"
389
 
    try:
390
 
        prog_name = os.path.basename(sys.argv[0])
391
 
        if prog_name in ("__main__.py", "-c"):
392
 
            prog = "{0} -m mojo".format(sys.executable)
393
 
        else:
394
 
            prog = prog_name
395
 
    except (AttributeError, TypeError, IndexError):
396
 
        pass
397
 
    return prog
398
 
 
399
 
 
400
406
def create_arg_parser():
401
407
    # main program parser
402
 
    ap = MojoArgumentParser(prog=get_prog())
 
408
    ap = MojoArgumentParser()
403
409
    ap.add_argument("--blunt", action="store_true",
404
410
                    help="Handle fewer exceptions")
405
411
    ap.add_argument("--break_everything", action="store_true",
408
414
                    help="Log level. Checks $MOJO_LOGLEVEL, defaults to INFO")
409
415
    ap.add_argument("--logfile", "-L", default=os.environ.get('MOJO_LOGFILE'),
410
416
                    help="File to log to in addition to stdout. Overrides environment "
411
 
                            "variable MOJO_LOGFILE. Defaults to MOJO_WORKSPACE/log/mojo.log")
 
417
                         "variable MOJO_LOGFILE. Defaults to MOJO_WORKSPACE/log/mojo.log")
412
418
    ap.add_argument("-r", "--mojo_root", default=os.environ.get('MOJO_ROOT'),
413
419
                    help="Root directory that mojo works out of Overrides the MOJO_ROOT environment variable. "
414
 
                            "Defaults to /srv/mojo for projects using 'lxc' containers and to "
415
 
                            " ~/.local/share/mojo for 'lxd' and 'containerless' projects.")
416
 
    ap.add_argument('--version', action='version',
417
 
                    version=mojo.__version__)
 
420
                         "Defaults to /srv/mojo for projects using 'lxc' containers and to "
 
421
                         " ~/.local/share/mojo for 'lxd' and 'containerless' projects.")
 
422
    ap.add_argument('--version', action='version', version=mojo.__version__)
418
423
 
419
424
    # subcommand parser
420
425
    sp = ap.add_subparsers(title="subcommands", dest="subparser_name")
424
429
    project_kwargs = {'help': "Project name. Overrides the MOJO_PROJECT environment variable."}
425
430
    series_args = ("-s", "--series")
426
431
    series_kwargs = {'default': os.environ.get('MOJO_SERIES'),
427
 
                        'help': "Distro series. Overrides the MOJO_SERIES environment variable."}
 
432
                     'help': "Distro series. Overrides the MOJO_SERIES environment variable."}
428
433
    stage_args = ("--stage", )
429
434
    stage_kwargs = {'default': os.environ.get('MOJO_STAGE', 'devel'),
430
435
                    'help': "Deployment stage. Overrides MOJO_STAGE environment variable (default: devel)"}
444
449
    phaseopts.add_argument(*series_args, **series_kwargs)
445
450
    phaseopts.add_argument("--spec-url", default=None,
446
451
                            help='Location of the Mojo spec. Overrides the '
447
 
                                'MOJO_SPEC environment variable. If MOJO_SPEC '
448
 
                                'is unset, defaults to ".".')
 
452
                                 'MOJO_SPEC environment variable. If MOJO_SPEC '
 
453
                                 'is unset, defaults to ".".')
449
454
 
450
455
    # project-new subcommand - creates a new mojo project
451
456
    prjnewcmd = sp.add_parser("project-new",
452
 
                                description="Create a new Mojo project and container")
 
457
                              description="Create a new Mojo project and container")
453
458
    prjnewcmd.add_argument(*series_args, required=False, **series_kwargs)
454
459
    prjnewcmd.add_argument("name", nargs='?', default=os.environ.get('MOJO_PROJECT'),
455
 
                            help="Base name of the project ([a-zA-Z0-9._]*)")
 
460
                           help="Base name of the project ([a-zA-Z0-9._]*)")
456
461
    prjnewcmd.add_argument('-c', "--container", default=os.environ.get('MOJO_CONTAINER', 'lxc'),
457
 
                            choices=['lxc', 'lxd', 'containerless'],
458
 
                            help="Container. Options 'lxc', 'lxd' or 'containerless'. "
459
 
                                "Defaults to 'lxc'")
 
462
                           choices=['lxc', 'lxd', 'containerless'],
 
463
                           help="Container. Options 'lxc', 'lxd' or 'containerless'. "
 
464
                                 "Defaults to 'lxc'")
460
465
    prjnewcmd.set_defaults(func=call_project_new)
461
466
 
462
467
    # project-destroy subcommand - deletes a mojo project
463
468
    prjdelcmd = sp.add_parser("project-destroy",
464
469
                                description="Destroy a Mojo project and container")
465
470
    prjdelcmd.add_argument("name", default=os.environ.get('MOJO_PROJECT'),
466
 
                            help="Base name of the project ([a-zA-Z0-9._]*)")
 
471
                           help="Base name of the project ([a-zA-Z0-9._]*)")
467
472
    prjdelcmd.add_argument(*series_args, **series_kwargs)
468
473
    prjdelcmd.set_defaults(func=call_project_destroy)
469
474
 
470
475
    # project-list
471
476
    prjlistcmd = sp.add_parser("project-list",
472
 
                                description="List existing projects, found at the mojo root")
 
477
                               description="List existing projects, found at the mojo root")
473
478
    prjlistcmd.add_argument("-n", "--names", action="store_true",
474
479
                            help="List only project names, without series")
475
480
    prjlistcmd.set_defaults(func=list_projects)
477
482
    # workspace-new subcommand - creates a new workspace for a specific spec
478
483
    # revision
479
484
    wsnewcmd = sp.add_parser("workspace-new",
480
 
                                description="Initialize a mojo workspace")
 
485
                             description="Initialize a mojo workspace")
481
486
    wsnewcmd.add_argument("spec_url", nargs='?', default=None,
482
487
                            help='Location of the Mojo spec. Overrides the '
483
 
                                'MOJO_SPEC environment variable. If MOJO_SPEC '
484
 
                                'is unset, defaults to ".".')
 
488
                                 'MOJO_SPEC environment variable. If MOJO_SPEC '
 
489
                                 'is unset, defaults to ".".')
485
490
    wsnewcmd.add_argument("workspace", nargs='?', default=None, help=workspace_kwargs['help'])
486
491
    wsnewcmd.add_argument(*project_args, **project_kwargs)
487
492
    wsnewcmd.add_argument(*series_args, **series_kwargs)
490
495
 
491
496
    # workspace-destroy subcommand - deletes a mojo project
492
497
    wsdelcmd = sp.add_parser("workspace-destroy",
493
 
                                description="Destroy a mojo workspace")
 
498
                             description="Destroy a mojo workspace")
494
499
    wsdelcmd.add_argument(*project_args, **project_kwargs)
495
500
    wsdelcmd.add_argument(*series_args, **series_kwargs)
496
501
    wsdelcmd.add_argument(*workspace_args, **workspace_kwargs)
498
503
 
499
504
    # workspace-list subcommand
500
505
    wslistcmd = sp.add_parser("workspace-list",
501
 
                                description="List workspaces for a project")
 
506
                              description="List workspaces for a project")
502
507
    wslistcmd.add_argument(*project_args, **project_kwargs)
503
508
    wslistcmd.add_argument(*series_args, **series_kwargs)
504
509
    wslistcmd.set_defaults(func=list_workspaces)
516
521
 
517
522
    # charm-audit subcommand - runs a charm audit
518
523
    charmauditcmd = sp.add_parser("charm-audit",
519
 
                                    description="Run a charm audit",
520
 
                                    parents=[phaseopts])
 
524
                                  description="Run a charm audit",
 
525
                                  parents=[phaseopts])
521
526
    charmauditcmd.set_defaults(func=run_phase)
522
527
 
523
528
    # build subcommand - run project build script inside container
524
529
    buildcmd = sp.add_parser("build",
525
 
                                description="Execute project build script",
526
 
                                parents=[phaseopts])
 
530
                             description="Execute project build script",
 
531
                             parents=[phaseopts])
527
532
    buildcmd.set_defaults(func=run_phase)
528
533
 
529
534
    # repo subcommand - assembles charms into a repository
533
538
 
534
539
    # sleep subcommand - sleeps for n seconds
535
540
    sleepcmd = sp.add_parser("sleep", description="Sleep for time in seconds",
536
 
                                parents=[phaseopts])
 
541
                             parents=[phaseopts])
537
542
    sleepcmd.set_defaults(func=run_phase)
538
543
 
539
544
    # secrets subcommand - secretss for n seconds
540
545
    secretscmd = sp.add_parser("secrets",
541
 
                                description="Copy secrets from staged "
542
 
                                "location to workspace local",
543
 
                                parents=[phaseopts])
 
546
                               description="Copy secrets from staged "
 
547
                               "location to workspace local",
 
548
                               parents=[phaseopts])
544
549
    secretscmd.set_defaults(func=run_phase)
545
550
 
546
551
    # script subcommand - run an arbitrary script inside container
547
552
    scriptcmd = sp.add_parser("script", description="Execute a project script",
548
 
                                parents=[phaseopts])
 
553
                              parents=[phaseopts])
549
554
    scriptcmd.set_defaults(func=run_phase)
550
555
 
551
556
    # bundle subcommand - run a juju deploy using bundles
552
557
    bundlecmd = sp.add_parser("bundle",
553
 
                                description="Deploy applications and relations using juju bundles",
554
 
                                parents=[phaseopts])
 
558
                              description="Deploy applications and relations using juju bundles",
 
559
                              parents=[phaseopts])
555
560
    bundlecmd.set_defaults(func=run_phase)
556
561
 
557
562
    # deploy subcommand - run a juju-deployer session
558
563
    deploycmd = sp.add_parser("deploy",
559
 
                                description="Deploy services and/or create "
560
 
                                "relations",
561
 
                                parents=[phaseopts])
 
564
                              description="Deploy services and/or create "
 
565
                              "relations",
 
566
                              parents=[phaseopts])
562
567
    deploycmd.add_argument("--ignore", action="store_true", default=False,
563
568
                            help="Exit 0 even if service deployment fails")
564
569
    deploycmd.set_defaults(func=run_phase)
565
570
 
566
571
    # deploy-show subcommand
567
572
    deployshowcmd = sp.add_parser("deploy-show",
568
 
                                    description="Show rendered juju-deployer "
569
 
                                                "configuration",
570
 
                                    parents=[phaseopts])
 
573
                                  description="Show rendered juju-deployer "
 
574
                                              "configuration",
 
575
                                  parents=[phaseopts])
571
576
    deployshowcmd.set_defaults(func=show_deploy)
572
577
 
573
578
    # deploy-diff subcommand
574
579
    deploydiffcmd = sp.add_parser("deploy-diff",
575
 
                                    description="Show juju-deployer diff. "
576
 
                                                "Generate a delta between a "
577
 
                                                "configured deployment and a "
578
 
                                                "running environment.",
579
 
                                    parents=[phaseopts])
 
580
                                  description="Show juju-deployer diff. "
 
581
                                              "Generate a delta between a "
 
582
                                              "configured deployment and a "
 
583
                                              "running environment.",
 
584
                                  parents=[phaseopts])
580
585
 
581
586
    configapplicationgroup = deploydiffcmd.add_mutually_exclusive_group()
582
587
    configapplicationgroup.add_argument(
592
597
 
593
598
    # volumes subcommand - mount volumes
594
599
    volcmd = sp.add_parser("volumes", description="Mount volumes",
595
 
                            parents=[phaseopts])
 
600
                           parents=[phaseopts])
596
601
    volcmd.set_defaults(func=run_phase)
597
602
 
598
603
    # verify subcommand - verify that a deployment was successful
599
604
    verifycmd = sp.add_parser("verify",
600
 
                                description="Verify that the deployment is "
601
 
                                "working",
602
 
                                parents=[phaseopts])
 
605
                              description="Verify that the deployment is "
 
606
                              "working",
 
607
                              parents=[phaseopts])
603
608
    verifycmd.set_defaults(func=run_phase)
604
609
 
605
610
    # juju-check-wait subcommand - wait until juju environment reaches steady state
606
611
    jujucheckwaitcmd = sp.add_parser("juju-check-wait",
607
 
                                        description="Wait until juju environment "
608
 
                                                    "reaches steady state.",
609
 
                                        parents=[phaseopts])
 
612
                                     description="Wait until juju environment "
 
613
                                                 "reaches steady state.",
 
614
                                     parents=[phaseopts])
610
615
    jujucheckwaitcmd.set_defaults(func=run_phase)
611
616
 
612
617
    # nagios-check subcommand - run all nagios checks in an environment
613
618
    nagioscheckcmd = sp.add_parser("nagios-check",
614
 
                                    description="Run all nagios checks in the environment",
615
 
                                    parents=[phaseopts])
 
619
                                   description="Run all nagios checks in the environment",
 
620
                                   parents=[phaseopts])
616
621
    nagioscheckcmd.set_defaults(func=run_phase)
617
622
 
618
623
    # run subcommand - run an entire spec per its manifest
619
624
    runcmd = sp.add_parser("run",
620
 
                            description="Run an entire deployment from start "
621
 
                            "to finish")
 
625
                           description="Run an entire deployment from start "
 
626
                           "to finish")
622
627
    runcmd.add_argument("spec_url", nargs='?', default=None,
623
628
                        help='Location of the Mojo spec. Overrides the '
624
 
                                'MOJO_SPEC environment variable. If MOJO_SPEC '
625
 
                                'is unset, defaults to ".".')
 
629
                              'MOJO_SPEC environment variable. If MOJO_SPEC '
 
630
                              'is unset, defaults to ".".')
626
631
    runcmd.add_argument("workspace", nargs='?', default=None, help=workspace_kwargs['help'])
627
632
    runcmd.add_argument("-i", "--interactive", action="store_true", default=False,
628
633
                        help="Run the manifest in interactive mode, prompting for each phase before running it")
641
646
    # help subcommand - get help for other subcommands
642
647
    helpcmd = sp.add_parser("help", description="Interactive help")
643
648
    helpcmd.add_argument("command", nargs='?', default=None,
644
 
                            help="Get help for this sub-command.")
 
649
                         help="Get help for this sub-command.")
645
650
    helpcmd.set_defaults(func=display_help, parser=ap)
646
651
 
647
652
    return ap
654
659
        mojo.CacheDisk.ttl(cache_ttl)
655
660
    try:
656
661
        args.func(args)
 
662
    # XXX: Handle attribute errors when calling bare 'mojo' command on
 
663
    # XXX: python 3 -- this prints usage and exits with an exit code 1
 
664
    # XXX: on python 2
657
665
    except AttributeError as e:
658
666
        if args.subparser_name is None and ap is not None:
659
667
            ap.print_usage()