Example #1
0
def inspect(args=None):
    build = Builder()
    parser = argparse.ArgumentParser(
        description='inspect the layers of a built charm. This '
                    'renders a tree of the files in the color '
                    'of each layer. Each layers assigned color '
                    'is presented in a legend at the top of the '
                    'output.')
    parser.add_argument('-r', '--force-raw', action="store_true",
                        dest='force_color', help="Alias of --force-color")
    parser.add_argument('-c', '--force-color', action="store_true",
                        help="Force raw output (color)")
    parser.add_argument('-a', '--annotate', action="store_true",
                        help="Annotate each file with the layer name, "
                             "rather than just using colors "
                             "(this is enabled automatically enabled if "
                             "colors are unavailable)")
    parser.add_argument('-l', '--log-level', default=logging.INFO)
    parser.add_argument('charm', nargs="?", default=".", type=path)
    utils.add_plugin_description(parser)
    # Namespace will set the options as attrs of build
    parser.parse_args(args, namespace=build)
    configLogging(build)
    try:
        build.inspect()
    except BuildError as e:
        if e.args:
            log.error(*e.args)
        raise SystemExit(1)
Example #2
0
def inspect(args=None):
    build = Builder()
    parser = argparse.ArgumentParser(
        description='inspect the layers of a built charm. This '
        'renders a tree of the files in the color '
        'of each layer. Each layers assigned color '
        'is presented in a legend at the top of the '
        'output.')
    parser.add_argument('-r',
                        '--force-raw',
                        action="store_true",
                        dest='force_color',
                        help="Alias of --force-color")
    parser.add_argument('-c',
                        '--force-color',
                        action="store_true",
                        help="Force raw output (color)")
    parser.add_argument('-l', '--log-level', default=logging.INFO)
    parser.add_argument('charm', nargs="?", default=".", type=path)
    utils.add_plugin_description(parser)
    # Namespace will set the options as attrs of build
    parser.parse_args(args, namespace=build)
    configLogging(build)
    try:
        build.inspect()
    except BuildError as e:
        if e.args:
            log.error(*e.args)
        raise SystemExit(1)
Example #3
0
def setup_parser():
    parser = argparse.ArgumentParser(
        prog='charm pull-source',
        description=textwrap.dedent(__doc__),
        formatter_class=argparse.RawDescriptionHelpFormatter,
    )

    parser.add_argument(
        'item', help='Name of the charm, layer, or interface to download.')
    parser.add_argument(
        'dir',
        nargs='?',
        help='Directory in which to place the downloaded source.',
    )
    parser.add_argument(
        '-i',
        '--layer-index',
        help='One or more index URLs used to look up layers, '
        'separated by commas. Can include the token '
        'DEFAULT, which will be replaced by the default '
        'index{} ({}).  E.g.: https://my-site.com/index/,DEFAULT'.format(
            'es' if len(fetchers.LayerFetcher.LAYER_INDEXES) > 1 else '',
            ','.join(fetchers.LayerFetcher.LAYER_INDEXES)))
    parser.add_argument(
        '-v',
        '--verbose',
        help='Show verbose output',
        action='store_true',
        default=False,
    )
    utils.add_plugin_description(parser)

    return parser
Example #4
0
def setup_parser():
    parser = argparse.ArgumentParser(
        prog='charm pull-source',
        description=textwrap.dedent(__doc__),
        formatter_class=argparse.RawDescriptionHelpFormatter,
    )

    parser.add_argument(
        'item',
        help='Name of the charm, layer, or interface to download.'
    )
    parser.add_argument(
        'dir', nargs='?',
        help='Directory in which to place the downloaded source.',
    )
    parser.add_argument(
        '-i', '--layer-index',
        help='One or more index URLs used to look up layers, '
             'separated by commas. Can include the token '
             'DEFAULT, which will be replaced by the default '
             'index{} ({}).  E.g.: https://my-site.com/index/,DEFAULT'.format(
                 'es' if len(fetchers.LayerFetcher.LAYER_INDEXES) > 1 else '',
                 ','.join(fetchers.LayerFetcher.LAYER_INDEXES)))
    parser.add_argument(
        '-v', '--verbose',
        help='Show verbose output',
        action='store_true', default=False,
    )
    utils.add_plugin_description(parser)

    return parser
Example #5
0
def get_args(args=None):
    parser = argparse.ArgumentParser(
        description='display tooling version information')
    utils.add_plugin_description(parser)
    parser = parser_defaults(parser)
    args = parser.parse_args(args)

    return args
Example #6
0
def parser(args=None):
    parser = argparse.ArgumentParser(
        description='add icon, readme, or tests to a charm')
    parser.add_argument('subcommand', choices=['tests', 'readme', 'icon'],
                        help='Which type of generator to run')
    utils.add_plugin_description(parser)
    parser = parser_defaults(parser)
    return parser.parse_known_args(args)
Example #7
0
def main(args=None):
    build = Builder()
    parser = argparse.ArgumentParser(
        description="build a charm from layers and interfaces",
        formatter_class=argparse.RawDescriptionHelpFormatter,)
    parser.add_argument('-l', '--log-level', default=logging.INFO)
    parser.add_argument('-f', '--force', action="store_true")
    parser.add_argument('-o', '--output-dir', type=path)
    parser.add_argument('-s', '--series', default=None)
    parser.add_argument('--hide-metrics', dest="hide_metrics",
                        default=False, action="store_true")
    parser.add_argument('--interface-service',
                        default="http://interfaces.juju.solutions")
    parser.add_argument('--no-local-layers', action="store_true",
                        help="Don't use local layers when building. "
                        "Forces included layers to be downloaded "
                        "from the interface service.")
    parser.add_argument('-n', '--name',
                        help="Build a charm of 'name' from 'charm'")
    parser.add_argument('-r', '--report', action="store_true",
                        help="Show post-build report of changes")
    parser.add_argument('charm', nargs="?", default=".", type=path)
    utils.add_plugin_description(parser)
    # Namespace will set the options as attrs of build
    parser.parse_args(args, namespace=build)
    if build.charm == "help":
        parser.print_help()
        raise SystemExit(0)

    # Monkey patch in the domain for the interface webservice
    InterfaceFetcher.INTERFACE_DOMAIN = build.interface_service
    LayerFetcher.INTERFACE_DOMAIN = build.interface_service

    InterfaceFetcher.NO_LOCAL_LAYERS = build.no_local_layers

    configLogging(build)

    try:
        if not build.output_dir:
            build.normalize_outputdir()
        if not build.series:
            build.check_series()

        build()

        lint, exit_code = proof.proof(os.getcwd(), False, False)
        if lint:
            llog = logging.getLogger("proof")
            for line in lint:
                if line[0] == "I":
                    llog.info(line)
                elif line[0] == "W":
                    llog.warn(line)
                elif line[0] == "E":
                    llog.error(line)
    except (BuildError, FetchError) as e:
        log.error(*e.args)
        raise SystemExit(1)
Example #8
0
def get_args(args=None):
    parser = argparse.ArgumentParser(
        description='perform static analysis on a charm or bundle')
    parser.add_argument('charm_name', nargs='?', default=os.getcwd(),
                        help='path of charm dir to check. Defaults to PWD')
    utils.add_plugin_description(parser)
    parser = parser_defaults(parser)
    args = parser.parse_args(args)

    return args
Example #9
0
def inspect(args=None):
    build = Builder()
    parser = argparse.ArgumentParser(
        description='inspect the layers of a built charm')
    parser.add_argument('-r', '--force-raw', action="store_true",
                        help="Force raw output (color)")
    parser.add_argument('-l', '--log-level', default=logging.INFO)
    parser.add_argument('charm', nargs="?", default=".", type=path)
    utils.add_plugin_description(parser)
    # Namespace will set the options as attrs of build
    parser.parse_args(args, namespace=build)
    configLogging(build)
    build.inspect()
Example #10
0
def inspect(args=None):
    build = Builder()
    parser = argparse.ArgumentParser(
        description='inspect the layers of a built charm')
    parser.add_argument('-r', '--force-raw', action="store_true",
                        help="Force raw output (color)")
    parser.add_argument('-l', '--log-level', default=logging.INFO)
    parser.add_argument('charm', nargs="?", default=".", type=path)
    utils.add_plugin_description(parser)
    # Namespace will set the options as attrs of build
    parser.parse_args(args, namespace=build)
    configLogging(build)
    build.inspect()
Example #11
0
def get_args(args=None):
    parser = argparse.ArgumentParser(
        description='display tooling version information')
    parser.add_argument('--format',
                        choices=['long', 'short', 'default'],
                        default='default',
                        help="Version format. Long includes git revision "
                        "info. Default uses long if it's a pre-release.")
    utils.add_plugin_description(parser)
    parser = parser_defaults(parser)
    args = parser.parse_args(args)

    return args
Example #12
0
def get_args(args=None):
    parser = argparse.ArgumentParser(
        description='display tooling version information')
    parser.add_argument('--format',
                        choices=['long', 'short', 'default', 'json'],
                        default='default',
                        help="Version format. Long includes git revision "
                             "info. Default uses long if it's a pre-release.")
    utils.add_plugin_description(parser)
    parser = parser_defaults(parser)
    args = parser.parse_args(args)

    return args
Example #13
0
def inspect(args=None):
    build = Builder()
    parser = argparse.ArgumentParser(
        description='inspect the layers of a built charm. This '
                    'renders a tree of the files in the color '
                    'of each layer. Each layers assigned color '
                    'is presented in a legend at the top of the '
                    'output.')
    parser.add_argument('-r', '--force-raw', action="store_true",
                        help="Force raw output (color)")
    parser.add_argument('-l', '--log-level', default=logging.INFO)
    parser.add_argument('charm', nargs="?", default=".", type=path)
    utils.add_plugin_description(parser)
    # Namespace will set the options as attrs of build
    parser.parse_args(args, namespace=build)
    configLogging(build)
    try:
        build.inspect()
    except BuildError as e:
        if e.args:
            log.error(*e.args)
        raise SystemExit(1)
Example #14
0
def setup_parser():
    parser = argparse.ArgumentParser(
        prog='charm pull-source',
        description=textwrap.dedent(__doc__),
        formatter_class=argparse.RawDescriptionHelpFormatter,
    )

    parser.add_argument(
        'item',
        help='Name of the charm, layer, or interface to download.'
    )
    parser.add_argument(
        'dir', nargs='?',
        help='Directory in which to place the downloaded source.',
    )
    parser.add_argument(
        '-v', '--verbose',
        help='Show verbose output',
        action='store_true', default=False,
    )
    utils.add_plugin_description(parser)

    return parser
Example #15
0
def setup_parser():
    parser = argparse.ArgumentParser(
        prog='charm pull-source',
        description=textwrap.dedent(__doc__),
        formatter_class=argparse.RawDescriptionHelpFormatter,
    )

    parser.add_argument(
        'item', help='Name of the charm, layer, or interface to download.')
    parser.add_argument(
        'dir',
        nargs='?',
        help='Directory in which to place the downloaded source.',
    )
    parser.add_argument(
        '-v',
        '--verbose',
        help='Show verbose output',
        action='store_true',
        default=False,
    )
    utils.add_plugin_description(parser)

    return parser
Example #16
0
def main(args=None):
    build = Builder()
    parser = argparse.ArgumentParser(
        description="build a charm from layers and interfaces",
        formatter_class=argparse.RawDescriptionHelpFormatter,
    )
    parser.add_argument('-l', '--log-level', default=logging.INFO)
    parser.add_argument('-f', '--force', action="store_true")
    parser.add_argument('-o', '--output-dir', type=path)
    parser.add_argument('-s', '--series', default=None)
    parser.add_argument('--hide-metrics',
                        dest="hide_metrics",
                        default=False,
                        action="store_true")
    parser.add_argument('--interface-service',
                        help="Deprecated: use --layer-index")
    parser.add_argument('--layer-index',
                        default="https://juju.github.io/layer-index/")
    parser.add_argument('--no-local-layers',
                        action="store_true",
                        help="Don't use local layers when building. "
                        "Forces included layers to be downloaded "
                        "from the interface service.")
    parser.add_argument('-n',
                        '--name',
                        help="Build a charm of 'name' from 'charm'")
    parser.add_argument('-r',
                        '--report',
                        action="store_true",
                        help="Show post-build report of changes")
    parser.add_argument('-w',
                        '--wheelhouse-overrides',
                        type=path,
                        help="Provide a wheelhouse.txt file with overrides "
                        "for the built wheelhouse")
    parser.add_argument('-v',
                        '--verbose',
                        action='store_true',
                        default=False,
                        help="Increase output (same as -l DEBUG)")
    parser.add_argument('charm', nargs="?", default=".", type=path)
    utils.add_plugin_description(parser)
    # Namespace will set the options as attrs of build
    parser.parse_args(args, namespace=build)
    if build.charm == "help":
        parser.print_help()
        raise SystemExit(0)

    if build.verbose:
        build.log_level = logging.DEBUG

    # Monkey patch in the domain for the interface webservice
    layer_index = build.interface_service or build.layer_index
    InterfaceFetcher.INTERFACE_DOMAIN = layer_index
    LayerFetcher.INTERFACE_DOMAIN = layer_index

    InterfaceFetcher.NO_LOCAL_LAYERS = build.no_local_layers

    configLogging(build)

    try:
        if not build.output_dir:
            build.normalize_outputdir()
        build.check_paths()
        if not build.series:
            build.check_series()

        build()

        lint, exit_code = proof.proof(build.target_dir, False, False)
        llog = logging.getLogger("proof")

        if not lint:
            llog.info('OK!')

        for line in lint:
            if line[0] == "I":
                llog.info(line)
            elif line[0] == "W":
                llog.warn(line)
            elif line[0] == "E":
                llog.error(line)
    except (BuildError, FetchError) as e:
        log.debug(traceback.format_exc())
        if e.args:
            log.error(*e.args)
        raise SystemExit(1)
Example #17
0
def main(args=None):
    env_vars = (
        ("CHARM_LAYERS_DIR", "Directory containing local copies of base "
                             "layers"),
        ("CHARM_INTERFACES_DIR", "Directory containing local copies of "
                                 "interface layers"),
        ("CHARM_BUILD_DIR", "Build charms will be placed into "
                            "$CHARM_BUILD_DIR/{charm_name} "
                            "(defaults to current directory)"),
        ("JUJU_REPOSITORY", "Deprecated: If CHARM_BUILD_DIR is not set but "
                            "this is, built charms will be placed into "
                            "$JUJU_REPOSITORY/builds/{charm_name}"),
        ("LAYER_PATH", "Deprecated: Alias of CHARM_LAYERS_DIR"),
        ("INTERFACE_PATH", "Deprecated: Alias of CHARM_INTERFACES_DIR"),
    )
    build = Builder()
    parser = argparse.ArgumentParser(
        description="build a charm from layers and interfaces",
        epilog="The following environment variables will be honored:\n" +
               "\n" +
               "".join("  {:<20}  {}\n".format(name, desc)
                       for name, desc in env_vars),
        formatter_class=argparse.RawDescriptionHelpFormatter,)
    parser.add_argument('-l', '--log-level', default=logging.INFO)
    parser.add_argument('-f', '--force', action="store_true")
    parser.add_argument('-o', '--output-dir', type=path,
                        help='Alias for --build-dir')
    parser.add_argument('-d', '--build-dir', type=path,
                        help='Directory under which to place built charms; '
                             'overrides CHARM_BUILD_DIR env')
    parser.add_argument('-C', '--cache-dir', type=path,
                        help='Directory to cache build dependencies '
                        '(default: ~/.cache/charm; can also be set via '
                        'CHARM_CACHE_DIR env)')
    parser.add_argument('-s', '--series', default=None,
                        help='Deprecated: define series in metadata.yaml')
    parser.add_argument('--hide-metrics', dest="hide_metrics",
                        action="store_true")
    parser.add_argument('--interface-service',
                        help="Deprecated: use --layer-index")
    parser.add_argument('--layer-index',
                        default=LayerFetcher.LAYER_INDEX)
    parser.add_argument('--no-local-layers', action="store_true",
                        help="Don't use local layers when building. "
                        "Forces included layers to be downloaded "
                        "from the interface service.")
    parser.add_argument('-n', '--name',
                        help="Build a charm of 'name' from 'charm'")
    parser.add_argument('-r', '--report', action="store_true",
                        help="Show post-build report of changes")
    parser.add_argument('-w', '--wheelhouse-overrides', type=path,
                        help="Provide a wheelhouse.txt file with overrides "
                             "for the built wheelhouse")
    parser.add_argument('-v', '--verbose', action='store_true', default=False,
                        help="Increase output (same as -l DEBUG)")
    parser.add_argument('-c', '--force-color', action="store_true",
                        help="Force raw output (color)")
    parser.add_argument('charm', nargs="?", default=".", type=path,
                        help='Source directory for charm layer to build '
                             '(default: .)')
    utils.add_plugin_description(parser)
    # Namespace will set the options as attrs of build
    parser.parse_args(args, namespace=build)
    if build.charm == "help":
        parser.print_help()
        raise SystemExit(0)

    if build.verbose:
        build.log_level = logging.DEBUG

    # Monkey patch in the domain for the interface webservice
    layer_index = build.interface_service or build.layer_index
    LayerFetcher.LAYER_INDEX = layer_index

    LayerFetcher.NO_LOCAL_LAYERS = build.no_local_layers

    configLogging(build)

    try:
        build.check_series()
        build.normalize_build_dir()
        build.normalize_cache_dir()
        build.check_paths()

        build()

        lint, exit_code = proof.proof(build.target_dir, False, False)
        llog = logging.getLogger("proof")

        if not lint:
            llog.info('OK!')

        for line in lint:
            if line[0] == "I":
                llog.info(line)
            elif line[0] == "W":
                llog.warn(line)
            elif line[0] == "E":
                llog.error(line)

        if exit_code > 0:
            raise SystemExit(exit_code)

    except (BuildError, FetchError) as e:
        log.debug(traceback.format_exc())
        if e.args:
            log.error(*e.args)
        raise SystemExit(1)
Example #18
0
def main(args=None):
    env_vars = (
        ("CHARM_LAYERS_DIR", "Directory containing local copies of base "
         "layers"),
        ("CHARM_INTERFACES_DIR", "Directory containing local copies of "
         "interface layers"),
        ("CHARM_BUILD_DIR", "Build charms will be placed into "
         "$CHARM_BUILD_DIR/{charm_name} "
         "(defaults to current directory)"),
        ("JUJU_REPOSITORY", "Deprecated: If CHARM_BUILD_DIR is not set but "
         "this is, built charms will be placed into "
         "$JUJU_REPOSITORY/builds/{charm_name}"),
        ("LAYER_PATH", "Deprecated: Alias of CHARM_LAYERS_DIR"),
        ("INTERFACE_PATH", "Deprecated: Alias of CHARM_INTERFACES_DIR"),
    )
    build = Builder()
    parser = argparse.ArgumentParser(
        description="build a charm from layers and interfaces",
        epilog="The following environment variables will be honored:\n" +
        "\n" + "".join("  {:<20}  {}\n".format(name, desc)
                       for name, desc in env_vars),
        formatter_class=argparse.RawDescriptionHelpFormatter,
    )
    parser.add_argument('-l', '--log-level', default=logging.INFO)
    parser.add_argument('-f', '--force', action="store_true")
    parser.add_argument('-o',
                        '--output-dir',
                        type=path,
                        help='Alias for --build-dir')
    parser.add_argument('-d',
                        '--build-dir',
                        type=path,
                        help='Directory under which to place built charms; '
                        'overrides CHARM_BUILD_DIR env')
    parser.add_argument('-C',
                        '--cache-dir',
                        type=path,
                        help='Directory to cache build dependencies '
                        '(default: ~/.cache/charm; can also be set via '
                        'CHARM_CACHE_DIR env)')
    parser.add_argument('-s',
                        '--series',
                        default=None,
                        help='Deprecated: define series in metadata.yaml')
    parser.add_argument('--hide-metrics',
                        dest="hide_metrics",
                        action="store_true")
    parser.add_argument('--interface-service',
                        help="Deprecated: use --layer-index")
    parser.add_argument(
        '-i',
        '--layer-index',
        help='One or more index URLs used to look up layers, '
        'separated by commas. Can include the token '
        'DEFAULT, which will be replaced by the default '
        'index{} ({}).  E.g.: '
        'https://my-site.com/index/,DEFAULT'.format(
            'es' if len(LayerFetcher.LAYER_INDEXES) > 1 else '',
            ','.join(LayerFetcher.LAYER_INDEXES)))
    parser.add_argument('--no-local-layers',
                        action="store_true",
                        help="Don't use local layers when building. "
                        "Forces included layers to be downloaded "
                        "from the interface service.")
    parser.add_argument('-n',
                        '--name',
                        help="Build a charm of 'name' from 'charm'")
    parser.add_argument('-r',
                        '--report',
                        action="store_true",
                        help="Show post-build report of changes")
    parser.add_argument('-w',
                        '--wheelhouse-overrides',
                        type=path,
                        help="Provide a wheelhouse.txt file with overrides "
                        "for the built wheelhouse")
    parser.add_argument('-v',
                        '--verbose',
                        action='store_true',
                        default=False,
                        help="Increase output (same as -l DEBUG)")
    parser.add_argument('--debug',
                        action='store_true',
                        help='Same as --log-level=DEBUG')
    parser.add_argument('-c',
                        '--force-color',
                        action="store_true",
                        help="Force raw output (color)")
    parser.add_argument('charm',
                        nargs="?",
                        default=".",
                        type=path,
                        help='Source directory for charm layer to build '
                        '(default: .)')
    utils.add_plugin_description(parser)
    # Namespace will set the options as attrs of build
    parser.parse_args(args, namespace=build)
    if build.charm == "help":
        parser.print_help()
        raise SystemExit(0)

    if build.verbose or build.debug:
        build.log_level = logging.DEBUG

    LayerFetcher.set_layer_indexes(build.interface_service
                                   or build.layer_index)
    LayerFetcher.NO_LOCAL_LAYERS = build.no_local_layers

    configLogging(build)

    try:
        build.check_series()
        build.normalize_build_dir()
        build.normalize_cache_dir()
        build.check_paths()

        build()

        lint, exit_code = proof.proof(build.target_dir, False, False)
        llog = logging.getLogger("proof")

        if not lint:
            llog.info('OK!')

        for line in lint:
            if line[0] == "I":
                llog.info(line)
            elif line[0] == "W":
                llog.warn(line)
            elif line[0] == "E":
                llog.error(line)

        if exit_code > 0:
            raise SystemExit(exit_code)

    except (BuildError, FetchError) as e:
        log.debug(traceback.format_exc())
        if e.args:
            log.error(*e.args)
        raise SystemExit(1)
Example #19
0
def main(args=None):
    build = Builder()
    parser = argparse.ArgumentParser(
        description="build a charm from layers and interfaces",
        formatter_class=argparse.RawDescriptionHelpFormatter,
    )
    parser.add_argument('-l', '--log-level', default=logging.INFO)
    parser.add_argument('-f', '--force', action="store_true")
    parser.add_argument('-o', '--output-dir', type=path)
    parser.add_argument('-s', '--series', default=None)
    parser.add_argument('--hide-metrics',
                        dest="hide_metrics",
                        default=False,
                        action="store_true")
    parser.add_argument('--interface-service',
                        default="http://interfaces.juju.solutions")
    parser.add_argument('--no-local-layers',
                        action="store_true",
                        help="Don't use local layers when building. "
                        "Forces included layers to be downloaded "
                        "from the interface service.")
    parser.add_argument('-n',
                        '--name',
                        help="Build a charm of 'name' from 'charm'")
    parser.add_argument('-r',
                        '--report',
                        action="store_true",
                        help="Show post-build report of changes")
    parser.add_argument('charm', nargs="?", default=".", type=path)
    utils.add_plugin_description(parser)
    # Namespace will set the options as attrs of build
    parser.parse_args(args, namespace=build)
    if build.charm == "help":
        parser.print_help()
        raise SystemExit(0)

    # Monkey patch in the domain for the interface webservice
    InterfaceFetcher.INTERFACE_DOMAIN = build.interface_service
    LayerFetcher.INTERFACE_DOMAIN = build.interface_service

    InterfaceFetcher.NO_LOCAL_LAYERS = build.no_local_layers

    configLogging(build)

    try:
        if not build.output_dir:
            build.normalize_outputdir()
        if not build.series:
            build.check_series()

        build()

        lint, exit_code = proof.proof(os.getcwd(), False, False)
        if lint:
            llog = logging.getLogger("proof")
            for line in lint:
                if line[0] == "I":
                    llog.info(line)
                elif line[0] == "W":
                    llog.warn(line)
                elif line[0] == "E":
                    llog.error(line)
    except (BuildError, FetchError) as e:
        log.error(*e.args)
        raise SystemExit(1)
Example #20
0
def main(args=None):
    build = Builder()
    parser = argparse.ArgumentParser(
        description="build a charm from layers and interfaces",
        formatter_class=argparse.RawDescriptionHelpFormatter,)
    parser.add_argument('-l', '--log-level', default=logging.INFO)
    parser.add_argument('-f', '--force', action="store_true")
    parser.add_argument('-o', '--output-dir', type=path)
    parser.add_argument('-s', '--series', default=None)
    parser.add_argument('--hide-metrics', dest="hide_metrics",
                        default=False, action="store_true")
    parser.add_argument('--interface-service',
                        help="Deprecated: use --layer-index")
    parser.add_argument('--layer-index',
                        default="https://juju.github.io/layer-index/")
    parser.add_argument('--no-local-layers', action="store_true",
                        help="Don't use local layers when building. "
                        "Forces included layers to be downloaded "
                        "from the interface service.")
    parser.add_argument('-n', '--name',
                        help="Build a charm of 'name' from 'charm'")
    parser.add_argument('-r', '--report', action="store_true",
                        help="Show post-build report of changes")
    parser.add_argument('-w', '--wheelhouse-overrides', type=path,
                        help="Provide a wheelhouse.txt file with overrides "
                             "for the built wheelhouse")
    parser.add_argument('-v', '--verbose', action='store_true', default=False,
                        help="Increase output (same as -l DEBUG)")
    parser.add_argument('charm', nargs="?", default=".", type=path)
    utils.add_plugin_description(parser)
    # Namespace will set the options as attrs of build
    parser.parse_args(args, namespace=build)
    if build.charm == "help":
        parser.print_help()
        raise SystemExit(0)

    if build.verbose:
        build.log_level = logging.DEBUG

    # Monkey patch in the domain for the interface webservice
    layer_index = build.interface_service or build.layer_index
    InterfaceFetcher.INTERFACE_DOMAIN = layer_index
    LayerFetcher.INTERFACE_DOMAIN = layer_index

    InterfaceFetcher.NO_LOCAL_LAYERS = build.no_local_layers

    configLogging(build)

    try:
        if not build.output_dir:
            build.normalize_outputdir()
        build.check_paths()
        if not build.series:
            build.check_series()

        build()

        lint, exit_code = proof.proof(build.target_dir, False, False)
        llog = logging.getLogger("proof")

        if not lint:
            llog.info('OK!')

        for line in lint:
            if line[0] == "I":
                llog.info(line)
            elif line[0] == "W":
                llog.warn(line)
            elif line[0] == "E":
                llog.error(line)
    except (BuildError, FetchError) as e:
        log.debug(traceback.format_exc())
        if e.args:
            log.error(*e.args)
        raise SystemExit(1)