Esempio n. 1
0
    def Modify(self, client, resources, args, existing):
        replacement = encoding.CopyProtoMessage(existing)

        mask = None

        interface_name = args.interface_name

        if args.mask_length is not None:
            if args.mask_length < 0 or args.mask_length > 31:
                raise parser_errors.ArgumentException(
                    '--mask-length must be a non-negative integer less than 32'
                )

        if args.ip_address is not None:
            if args.mask_length is not None:
                mask = '{0}/{1}'.format(args.ip_address, args.mask_length)
            else:
                raise parser_errors.ArgumentException(
                    '--mask-length must be set if --ip-address is set')

        if not args.vpn_tunnel_region:
            args.vpn_tunnel_region = replacement.region
        vpn_ref = self.VPN_TUNNEL_ARG.ResolveAsResource(
            args,
            resources,
            scope_lister=compute_flags.GetDefaultScopeLister(client))

        interface = client.messages.RouterInterface(
            name=interface_name,
            linkedVpnTunnel=vpn_ref.SelfLink(),
            ipRange=mask)

        replacement.interfaces.append(interface)

        return replacement
  def Modify(self, client, resources, args, existing):
    replacement = encoding.CopyProtoMessage(existing)
    mask = None
    interface_name = args.interface_name

    if args.ip_address is not None:
      if args.subnetwork is None and args.mask_length is not None:
        mask = '{0}/{1}'.format(args.ip_address, args.mask_length)
      elif args.subnetwork is None:
        raise parser_errors.ArgumentException(
            '--mask-length must be set if --ip-address is set')
      elif args.mask_length is not None:
        raise parser_errors.ArgumentException(
            '--mask-length cannot be set if --subnetwork is set')

    if args.mask_length is not None:
      if args.mask_length < 0 or args.mask_length > 31:
        raise parser_errors.ArgumentException(
            '--mask-length must be a non-negative integer less than 32')

    if not args.vpn_tunnel_region:
      args.vpn_tunnel_region = replacement.region
    vpn_ref = None
    if args.vpn_tunnel is not None:
      vpn_ref = self.VPN_TUNNEL_ARG.ResolveAsResource(
          args,
          resources,
          scope_lister=compute_flags.GetDefaultScopeLister(client))

    if not args.interconnect_attachment_region:
      args.interconnect_attachment_region = replacement.region
    attachment_ref = None
    if args.interconnect_attachment is not None:
      attachment_ref = self.INTERCONNECT_ATTACHMENT_ARG.ResolveAsResource(
          args, resources)

    subnetwork_ref = None
    private_ip_address = None
    redundant_interface = None
    if args.subnetwork is not None:
      subnetwork_ref = self.SUBNETWORK_ARG.ResolveAsResource(args, resources)
      private_ip_address = args.ip_address
      redundant_interface = args.redundant_interface

    interface = client.messages.RouterInterface(
        name=interface_name,
        linkedVpnTunnel=(vpn_ref.SelfLink() if vpn_ref else None),
        linkedInterconnectAttachment=(attachment_ref.SelfLink()
                                      if attachment_ref else None),
        subnetwork=(subnetwork_ref.SelfLink() if subnetwork_ref else None),
        ipRange=mask,
        privateIpAddress=private_ip_address,
        redundantInterface=redundant_interface)

    replacement.interfaces.append(interface)

    return replacement
Esempio n. 3
0
  def _AcquireArgs(self):
    """Calls the functions to register the arguments for this module."""
    # A Command subclass can define a _Flags() method.
    self._common_type._Flags(self.ai)  # pylint: disable=protected-access
    # A command implementation can optionally define an Args() method.
    self._common_type.Args(self.ai)

    if self._parent_group:
      # Add parent arguments to the list of all arguments.
      for arg in self._parent_group.ai.arguments:
        self.ai.arguments.append(arg)
      # Add parent concepts to children, if they aren't represented already
      if self._parent_group.ai.concept_handler:
        if not self.ai.concept_handler:
          self.ai.add_concepts(handlers.RuntimeHandler())
        # pylint: disable=protected-access
        for concept_details in self._parent_group.ai.concept_handler._all_concepts:
          try:
            self.ai.concept_handler.AddConcept(**concept_details)
          except handlers.RepeatedConceptName:
            raise parser_errors.ArgumentException(
                'repeated concept in {command}: {concept_name}'.format(
                    command=self.dotted_name,
                    concept_name=concept_details['name']))
      # Add parent flags to children, if they aren't represented already
      for flag in self._parent_group.GetAllAvailableFlags():
        if flag.is_replicated:
          # Each command or group gets its own unique help flags.
          continue
        if flag.do_not_propagate:
          # Don't propagate down flags that only apply to the group but not to
          # subcommands.
          continue
        if flag.is_required:
          # It is not easy to replicate required flags to subgroups and
          # subcommands, since then there would be two+ identical required
          # flags, and we'd want only one of them to be necessary.
          continue
        try:
          self.ai.AddFlagActionFromAncestors(flag)
        except argparse.ArgumentError:
          raise parser_errors.ArgumentException(
              'repeated flag in {command}: {flag}'.format(
                  command=self.dotted_name,
                  flag=flag.option_strings))
      # Update parent display_info in children, children take precedence.
      self.ai.display_info.AddLowerDisplayInfo(
          self._parent_group.ai.display_info)
Esempio n. 4
0
    def Run(self, args):
        holder = base_classes.ComputeApiHolder(self.ReleaseTrack())
        attachment_ref = self.INTERCONNECT_ATTACHMENT_ARG.ResolveAsResource(
            args,
            holder.resources,
            scope_lister=compute_flags.GetDefaultScopeLister(holder.client))

        interconnect_attachment = client.InterconnectAttachment(
            attachment_ref, compute_client=holder.client)

        if args.router_region is None:
            args.router_region = attachment_ref.region

        if args.router_region != attachment_ref.region:
            raise parser_errors.ArgumentException(
                'router-region must be same as the attachment region.')

        router_ref = None
        if args.router is not None:
            router_ref = self.ROUTER_ARG.ResolveAsResource(
                args, holder.resources)

        admin_enabled = attachment_flags.GetAdminEnabledFlag(args)

        attachment = interconnect_attachment.CreateAlpha(
            description=args.description,
            router=router_ref,
            attachment_type='PARTNER',
            edge_availability_domain=args.edge_availability_domain,
            admin_enabled=admin_enabled,
            validate_only=getattr(args, 'dry_run', None),
            mtu=getattr(args, 'mtu', None))
        self._pairing_key = attachment.pairingKey
        return attachment
    def Modify(self, client, resources, args, existing):
        replacement = super(BetaUpdateInterface,
                            self).Modify(client, resources, args, existing)

        iface = None
        for i in replacement.interfaces:
            if i.name == args.interface_name:
                iface = i
                break

        if not args.interconnect_attachment_region:
            args.interconnect_attachment_region = replacement.region

        if args.interconnect_attachment is not None:
            attachment_ref = self.INTERCONNECT_ATTACHMENT_ARG.ResolveAsResource(
                args, resources)
            iface.linkedInterconnectAttachment = attachment_ref.SelfLink()

        if (iface.linkedVpnTunnel is not None
                and iface.linkedInterconnectAttachment is not None):
            raise parser_errors.ArgumentException(
                'cannot have both vpn-tunnel and interconnect-attachment for the '
                'interface.')

        return replacement
Esempio n. 6
0
    def Run(self, args):
        holder = base_classes.ComputeApiHolder(self.ReleaseTrack())
        attachment_ref = self.INTERCONNECT_ATTACHMENT_ARG.ResolveAsResource(
            args,
            holder.resources,
            scope_lister=compute_flags.GetDefaultScopeLister(holder.client))

        interconnect_attachment = client.InterconnectAttachment(
            attachment_ref, compute_client=holder.client)

        interconnect_ref = None
        if args.interconnect is not None:
            interconnect_ref = self.INTERCONNECT_ARG.ResolveAsResource(
                args, holder.resources)

        if args.router_region is None:
            args.router_region = attachment_ref.region

        if args.router_region != attachment_ref.region:
            raise parser_errors.ArgumentException(
                'router-region must be same as the attachment region.')

        router_ref = None
        if args.router is not None:
            router_ref = self.ROUTER_ARG.ResolveAsResource(
                args, holder.resources)

        return interconnect_attachment.Create(description=args.description,
                                              interconnect=interconnect_ref,
                                              router=router_ref)
Esempio n. 7
0
    def _AcquireArgs(self):
        """Calls the functions to register the arguments for this module."""
        # A Command subclass can define a _Flags() method.
        # Calliope sets up _Flags() and should not affect the legacy setting.
        legacy = self.ai.display_info.legacy
        self._common_type._Flags(self.ai)  # pylint: disable=protected-access
        self.ai.display_info.legacy = legacy
        # A command implementation can optionally define an Args() method.
        self._common_type.Args(self.ai)

        if self._parent_group:
            # Add parent flags to children, if they aren't represented already
            for flag in self._parent_group.GetAllAvailableFlags():
                if flag.is_replicated:
                    # Each command or group gets its own unique help flags.
                    continue
                if flag.do_not_propagate:
                    # Don't propagate down flags that only apply to the group but not to
                    # subcommands.
                    continue
                if flag.required:
                    # It is not easy to replicate required flags to subgroups and
                    # subcommands, since then there would be two+ identical required
                    # flags, and we'd want only one of them to be necessary.
                    continue
                try:
                    self.ai.AddFlagActionFromAncestors(flag)
                except argparse.ArgumentError:
                    raise parser_errors.ArgumentException(
                        'repeated flag in {command}: {flag}'.format(
                            command=self.dotted_name,
                            flag=flag.option_strings))
            # Update parent display_info in children, children take precedence.
            self.ai.display_info.AddLowerDisplayInfo(
                self._parent_group.ai.display_info)
Esempio n. 8
0
    def _AddRemoteCompleter(self, added_argument, completion_resource,
                            list_command_path, list_command_callback_fn):
        """Adds a remote completer to the given argument if necessary.

    Args:
      added_argument: The argparse argument that was previously created.
      completion_resource: str, The name of the resource that this argument
        corresponds to.
      list_command_path: str, The explicit calliope command to run to get the
        completions if you want to override the default for the given resource
        type. list_command_callback_fn takes precedence.
      list_command_callback_fn: function, Callback function to be called to get
        the list command. Takes precedence over list_command_path.
    """
        if not completion_resource:
            if list_command_path or list_command_callback_fn:
                raise parser_errors.ArgumentException(
                    'Command [{}] argument [{}] does not have completion_resource '
                    'set but has one or more of the deprecated list_command_path '
                    'and list_command_callback_fn attributes.'.format(
                        ' '.join(self.data.command_name), added_argument.dest))
            return
        # add a remote completer
        added_argument.completer = (
            remote_completion.RemoteCompletion.GetCompleterForResource(
                completion_resource,
                self.cli_generator.Generate,
                command_line=list_command_path,
                list_command_callback_fn=list_command_callback_fn))
        added_argument.completion_resource = completion_resource
Esempio n. 9
0
  def add_group(self, help=None, category=None, mutex=False, required=False,
                hidden=False, **kwargs):
    """Adds an argument group with mutex/required attributes to the parser.

    Args:
      help: str, The group help text description.
      category: str, The group flag category name, None for no category.
      mutex: bool, A mutually exclusive group if True.
      required: bool, A required group if True.
      hidden: bool, A hidden group if True.
      **kwargs: Passed verbatim to ArgumentInterceptor().

    Returns:
      The added argument object.
    """
    if 'description' in kwargs or 'title' in kwargs:
      raise parser_errors.ArgumentException(
          'parser.add_group(): description or title kwargs not supported '
          '-- use help=... instead.')
    new_parser = self.parser.add_argument_group()
    group = ArgumentInterceptor(parser=new_parser,
                                is_global=self.is_global,
                                cli_generator=self.cli_generator,
                                allow_positional=self.allow_positional,
                                data=self.data,
                                help=help,
                                category=category,
                                mutex=mutex,
                                required=required,
                                hidden=hidden,
                                **kwargs)
    self.arguments.append(group)
    return group
Esempio n. 10
0
  def Run(self, args):
    holder = base_classes.ComputeApiHolder(self.ReleaseTrack())
    attachment_ref = self.INTERCONNECT_ATTACHMENT_ARG.ResolveAsResource(
        args,
        holder.resources,
        scope_lister=compute_flags.GetDefaultScopeLister(holder.client))

    interconnect_attachment = client.InterconnectAttachment(
        attachment_ref, compute_client=holder.client)

    interconnect_ref = None
    if args.interconnect is not None:
      interconnect_ref = self.INTERCONNECT_ARG.ResolveAsResource(
          args, holder.resources)

    if args.router_region is None:
      args.router_region = attachment_ref.region

    if args.router_region != attachment_ref.region:
      raise parser_errors.ArgumentException(
          'router-region must be same as the attachment region.')

    router_ref = None
    if args.router is not None:
      router_ref = self.ROUTER_ARG.ResolveAsResource(args, holder.resources)

    return interconnect_attachment.CreateAlpha(
        description=args.description,
        interconnect=interconnect_ref,
        attachment_type='DEDICATED',
        router=router_ref,
        vlan_tag_802_1q=args.vlan,
        admin_enabled=args.admin_enabled,
        candidate_subnets=args.candidate_subnets,
        bandwidth=getattr(args, 'bandwidth', None))
Esempio n. 11
0
    def _Run(self, args):
        holder = base_classes.ComputeApiHolder(self.ReleaseTrack())
        attachment_ref = self.INTERCONNECT_ATTACHMENT_ARG.ResolveAsResource(
            args,
            holder.resources,
            scope_lister=compute_flags.GetDefaultScopeLister(holder.client))

        interconnect_attachment = client.InterconnectAttachment(
            attachment_ref, compute_client=holder.client)

        interconnect_ref = None
        if args.interconnect is not None:
            interconnect_ref = self.INTERCONNECT_ARG.ResolveAsResource(
                args, holder.resources)

        if args.router_region is None:
            args.router_region = attachment_ref.region

        if args.router_region != attachment_ref.region:
            raise parser_errors.ArgumentException(
                'router-region must be same as the attachment region.')

        router_ref = None
        if args.router is not None:
            router_ref = self.ROUTER_ARG.ResolveAsResource(
                args, holder.resources)

        admin_enabled = attachment_flags.GetAdminEnabledFlag(args)

        ipsec_internal_addresses_urls = None
        region = attachment_ref.region
        if args.ipsec_internal_addresses is not None:
            ipsec_internal_addresses_urls = [
                attachment_flags.GetAddressRef(
                    holder.resources, name, region,
                    attachment_ref.project).SelfLink()
                for name in args.ipsec_internal_addresses
            ]

        return interconnect_attachment.CreateAlpha(
            description=args.description,
            interconnect=interconnect_ref,
            attachment_type='DEDICATED',
            router=router_ref,
            vlan_tag_802_1q=args.vlan,
            admin_enabled=admin_enabled,
            candidate_subnets=args.candidate_subnets,
            bandwidth=getattr(args, 'bandwidth', None),
            validate_only=getattr(args, 'dry_run', None),
            mtu=getattr(args, 'mtu', None),
            encryption=getattr(args, 'encryption', None),
            ipsec_internal_addresses=ipsec_internal_addresses_urls,
            stack_type=getattr(args, 'stack_type', None),
            candidate_ipv6_subnets=args.candidate_ipv6_subnets,
            cloud_router_ipv6_interface_id=getattr(
                args, 'cloud_router_ipv6_interface_id', None),
            customer_router_ipv6_interface_id=getattr(
                args, 'customer_router_ipv6_interface_id', None))
Esempio n. 12
0
    def Modify(self, args, existing):
        replacement = copy.deepcopy(existing)
        mask = None
        interface_name = args.interface_name

        if args.mask_length is not None:
            if args.mask_length < 0 or args.mask_length > 31:
                raise parser_errors.ArgumentException(
                    '--mask-length must be a non-negative integer less than 32'
                )

        if args.ip_address is not None:
            if args.mask_length is not None:
                mask = '{0}/{1}'.format(args.ip_address, args.mask_length)
            else:
                raise parser_errors.ArgumentException(
                    '--mask-length must be set if --ip-address is set')

        if not args.vpn_tunnel_region:
            args.vpn_tunnel_region = replacement.region
        vpn_ref = None
        if args.vpn_tunnel is not None:
            vpn_ref = self.VPN_TUNNEL_ARG.ResolveAsResource(
                args,
                self.resources,
                scope_lister=compute_flags.GetDefaultScopeLister(
                    self.compute_client))

        if not args.interconnect_attachment_region:
            args.interconnect_attachment_region = replacement.region
        attachment_ref = None
        if args.interconnect_attachment is not None:
            attachment_ref = self.INTERCONNECT_ATTACHMENT_ARG.ResolveAsResource(
                args, self.resources)

        interface = self.messages.RouterInterface(
            name=interface_name,
            linkedVpnTunnel=(vpn_ref.SelfLink() if vpn_ref else None),
            linkedInterconnectAttachment=(attachment_ref.SelfLink()
                                          if attachment_ref else None),
            ipRange=mask)

        replacement.interfaces.append(interface)

        return replacement
    def ModifyToAddInterface(self, router_ref, args, existing):
        """Mutate the router to add an interface."""
        replacement = encoding.CopyProtoMessage(existing)
        new_interface = self._messages.Interface(name=args.interface_name)

        if args.interconnect_attachment is None and args.subnetwork is None:
            raise parser_errors.ArgumentException(
                'One of Subnet and Interconnect attachment must be set')

        if args.interconnect_attachment is not None and args.subnetwork is not None:
            raise parser_errors.ArgumentException(
                'Subnet and Interconnect attachment cannot coexist')

        if args.interconnect_attachment is not None:
            attachment_ref = self._resource_parser.Create(
                'edgenetwork.projects.locations.zones.interconnectAttachments',
                interconnectAttachmentsId=args.interconnect_attachment,
                projectsId=router_ref.projectsId,
                locationsId=router_ref.locationsId,
                zonesId=router_ref.zonesId)
            if args.ip_mask_length is not None and args.ip_address is not None:
                new_interface.linkedInterconnectAttachment = attachment_ref.RelativeName(
                )
                new_interface.ipv4Cidr = '{0}/{1}'.format(
                    args.ip_address, args.ip_mask_length)
            else:
                raise parser_errors.ArgumentException(
                    '--ip-address and --ip-mask-length must be set')

        if args.subnetwork is not None:
            subnet_ref = self._resource_parser.Create(
                'edgenetwork.projects.locations.zones.subnets',
                subnetsId=args.subnetwork,
                projectsId=router_ref.projectsId,
                locationsId=router_ref.locationsId,
                zonesId=router_ref.zonesId)
            new_interface.subnetwork = subnet_ref.RelativeName()

        replacement.interface.append(new_interface)
        return replacement
Esempio n. 14
0
  def is_hidden(self):
    if self._is_hidden:
      return True

    try:
      next(a for a in self.arguments if not a.is_hidden)
      return False
    except StopIteration:
      flags = []
      for arg in self.arguments:
        if hasattr(arg, 'option_strings'):
          flags += arg.option_strings
      raise parser_errors.ArgumentException(
          'Groups with arguments and subgroups that are all hidden should be '
          'marked hidden.\nCommand: [{}]\nGroup: [{}]\nFlags: [{}]'.format(
              '.'.join(self.command_name), self.help, ', '.join(flags)))
    def Modify(self, client, resources, args, existing):
        replacement = encoding.CopyProtoMessage(existing)

        iface = None
        for i in replacement.interfaces:
            if i.name == args.interface_name:
                iface = i
                break

        if iface is None:
            raise router_utils.InterfaceNotFoundError(args.interface_name)

        # Flags --ip-address and --mask-length must be specified together.
        # TODO(b/65850105): Use an argument group for these flags.
        if (args.ip_address is not None) and (args.mask_length is not None):
            iface.ipRange = '{0}/{1}'.format(args.ip_address, args.mask_length)
        elif (args.ip_address is not None) or (args.mask_length is not None):
            raise router_utils.RequireIpAddressAndMaskLengthError()

        if not args.vpn_tunnel_region:
            args.vpn_tunnel_region = replacement.region

        if args.vpn_tunnel is not None:
            vpn_ref = self.VPN_TUNNEL_ARG.ResolveAsResource(
                args,
                resources,
                scope_lister=compute_flags.GetDefaultScopeLister(client))
            iface.linkedVpnTunnel = vpn_ref.SelfLink()

        if not args.interconnect_attachment_region:
            args.interconnect_attachment_region = replacement.region

        if args.interconnect_attachment is not None:
            attachment_ref = self.INTERCONNECT_ATTACHMENT_ARG.ResolveAsResource(
                args, resources)
            iface.linkedInterconnectAttachment = attachment_ref.SelfLink()

        if (iface.linkedVpnTunnel is not None
                and iface.linkedInterconnectAttachment is not None):
            raise parser_errors.ArgumentException(
                'cannot have both vpn-tunnel and interconnect-attachment for the '
                'interface.')

        return replacement
    def AddRemainderArgument(self, *args, **kwargs):
        """Add an argument representing '--' followed by anything.

    This argument is bound to the parser, so the parser can use it's helper
    methods to parse.

    GA track methods are made non-strict for backwards compatibility. If a BETA
    track alternate exists, it is used as the suggested strict alternate. See
    arg_parsers.RemainderAction for more information.

    Args:
      *args: The arguments for the action.
      **kwargs: They keyword arguments for the action.

    Raises:
      ArgumentException: If there already is a Remainder Action bound to this
      parser.

    Returns:
      The created action.
    """
        if self._remainder_action:
            raise parser_errors.ArgumentException(
                'There can only be one pass through argument.')
        kwargs['action'] = arg_parsers.RemainderAction
        track = self._calliope_command.ReleaseTrack()
        # pylint:disable=protected-access
        cli_generator = self._calliope_command._cli_generator
        alternates = cli_generator.ReplicateCommandPathForAllOtherTracks(
            self._calliope_command.GetPath())
        # Assume GA has backwards compatability otherwise assume strict.
        is_strict = track is not base.ReleaseTrack.GA
        strict_alternate = None
        if not is_strict and base.ReleaseTrack.BETA in alternates:
            strict_alternate = ' '.join(alternates[base.ReleaseTrack.BETA])
        self._remainder_action = self.add_argument(
            is_strict=is_strict,
            strict_alternate=strict_alternate,
            *args,
            **kwargs)
        return self._remainder_action
Esempio n. 17
0
  def add_group(self, help=None, category=None, mutex=False, required=False,
                hidden=False, sort_args=True, **kwargs):
    """Adds an argument group with mutex/required attributes to the parser.

    Args:
      help: str, The group help text description.
      category: str, The group flag category name, None for no category.
      mutex: bool, A mutually exclusive group if True.
      required: bool, A required group if True.
      hidden: bool, A hidden group if True.
      sort_args: bool, Whether to sort the group's arguments in help/usage text.
        NOTE - For ordering consistency across gcloud, generally prefer using
        argument categories to organize information (instead of unsetting the
        argument sorting).
      **kwargs: Passed verbatim to ArgumentInterceptor().

    Returns:
      The added argument object.
    """
    if 'description' in kwargs or 'title' in kwargs:
      raise parser_errors.ArgumentException(
          'parser.add_group(): description or title kwargs not supported '
          '-- use help=... instead.')
    new_parser = self.parser.add_argument_group()
    group = ArgumentInterceptor(parser=new_parser,
                                is_global=self.is_global,
                                cli_generator=self.cli_generator,
                                allow_positional=self.allow_positional,
                                data=self.data,
                                help=help,
                                category=category,
                                mutex=mutex,
                                required=required,
                                hidden=hidden or self._is_hidden,
                                sort_args=sort_args,
                                **kwargs)
    self.arguments.append(group)
    return group
Esempio n. 18
0
  def AddRemainderArgument(self, *args, **kwargs):
    """Add an argument representing '--' followed by anything.

    This argument is bound to the parser, so the parser can use it's helper
    methods to parse.

    Args:
      *args: The arguments for the action.
      **kwargs: They keyword arguments for the action.

    Raises:
      ArgumentException: If there already is a Remainder Action bound to this
      parser.

    Returns:
      The created action.
    """
    if self._remainder_action:
      raise parser_errors.ArgumentException(
          'There can only be one pass through argument.')
    kwargs['action'] = arg_parsers.RemainderAction
    # pylint:disable=protected-access
    self._remainder_action = self.add_argument(*args, **kwargs)
    return self._remainder_action
Esempio n. 19
0
    def add_argument(self, *args, **kwargs):
        """add_argument intercepts calls to the parser to track arguments."""
        # TODO(b/36050238): do not allow short-options without long-options.

        # we will choose the first option as the name
        name = args[0]
        dest = kwargs.get('dest')
        if not dest:
            # this is exactly what happens in argparse
            dest = name.lstrip(self.parser.prefix_chars).replace('-', '_')

        default = kwargs.get('default')
        required = kwargs.get('required', False)

        # A flag that can only be supplied where it is defined and not propagated to
        # subcommands.
        do_not_propagate = kwargs.pop('do_not_propagate', False)
        # A global flag that is added at each level explicitly because each command
        # has a different behavior (like -h).
        is_replicated = kwargs.pop('is_replicated', False)
        # This is used for help printing.  A flag is considered global if it is
        # added at the root of the CLI tree, or if it is explicitly added to every
        # command level.
        is_global = self.is_root or is_replicated
        # The flag category name, None for no category. This is also used for help
        # printing. Flags in the same category are grouped together in a section
        # named "{category} FLAGS".
        category = kwargs.pop('category', None)
        # Any alias this flag has for the purposes of the "did you mean"
        # suggestions.
        suggestion_aliases = kwargs.pop('suggestion_aliases', [])
        # The unbound completer object (or legacy completer function).
        completer = kwargs.pop('completer', None)
        # The resource name for the purposes of doing remote completion.
        completion_resource = kwargs.pop('completion_resource', None)
        # An explicit command to run for remote completion instead of the default
        # for this resource type.
        list_command_path = kwargs.pop('list_command_path', None)
        # Callback function that receives the currently entered args at the time of
        # remote completion processing, and returns the command to run.
        list_command_callback_fn = kwargs.pop('list_command_callback_fn', None)
        # hidden=True => help=argparse.SUPPRESS, but retains help in the source.
        if kwargs.pop('hidden', False):
            kwargs['help'] = argparse.SUPPRESS

        positional = not name.startswith('-')
        if positional:
            if not self.allow_positional:
                # TODO(b/36054662): More informative error message here about which
                # group the problem is in.
                raise parser_errors.ArgumentException(
                    'Illegal positional argument [{0}] for command [{1}]'.
                    format(name, self.data.command_name))
            if '-' in name:
                raise parser_errors.ArgumentException(
                    "Positional arguments cannot contain a '-'. Illegal argument [{0}] "
                    'for command [{1}]'.format(name, self.data.command_name))
            if category:
                raise parser_errors.ArgumentException(
                    'Positional argument [{0}] cannot have a category in '
                    'command [{1}]'.format(name, self.data.command_name))
            if suggestion_aliases:
                raise parser_errors.ArgumentException(
                    'Positional argument [{0}] cannot have suggestion aliases in '
                    'command [{1}]'.format(name, self.data.command_name))

        self.defaults[dest] = default
        if self.mutex_group_id:
            self.mutex_groups[dest] = self.mutex_group_id
            if self.parser.required:
                self.required_mutex_groups.add(self.mutex_group_id)
                self.group_attr[self.mutex_group_id] = ArgumentGroupAttr(
                    description=_MUTEX_GROUP_REQUIRED_DESCRIPTION,
                    is_mutex=True,
                    is_required=True,
                )
            else:
                self.group_attr[self.mutex_group_id] = ArgumentGroupAttr(
                    description=_MUTEX_GROUP_OPTIONAL_DESCRIPTION,
                    is_mutex=True,
                    is_required=False,
                )
        elif self.argument_group_id:
            self.argument_groups[dest] = self.argument_group_id
            if self.parser.description:
                description = self.parser.description
            elif self.parser.title:
                description = self.parser.title.rstrip('.') + ':'
            else:
                description = None
            self.group_attr[self.argument_group_id] = ArgumentGroupAttr(
                description=description,
                is_mutex=False,
                is_required=False,
            )
        if required:
            self.required.append(dest)
        self.dests.append(dest)

        if positional and 'metavar' not in kwargs:
            kwargs['metavar'] = name.upper()
        if kwargs.get('nargs') is argparse.REMAINDER:
            added_argument = self.parser.AddRemainderArgument(*args, **kwargs)
        else:
            added_argument = self.parser.add_argument(*args, **kwargs)
        if completer:
            added_argument.completer = completer
        else:
            self._AddRemoteCompleter(added_argument, completion_resource,
                                     list_command_path,
                                     list_command_callback_fn)

        if positional:
            if category:
                raise parser_errors.ArgumentException(
                    'Positional argument [{0}] cannot have a category in '
                    'command [{1}]'.format(name, self.data.command_name))
            self.positional_args.append(added_argument)
        else:
            if category and required:
                raise parser_errors.ArgumentException(
                    'Required flag [{0}] cannot have a category in '
                    'command [{1}]'.format(name, self.data.command_name))
            if category == 'REQUIRED':
                raise parser_errors.ArgumentException(
                    "Flag [{0}] cannot have category='REQUIRED' in "
                    'command [{1}]'.format(name, self.data.command_name))
            added_argument.category = category
            added_argument.do_not_propagate = do_not_propagate
            added_argument.is_replicated = is_replicated
            added_argument.is_global = is_global
            added_argument.required = required
            added_argument.suggestion_aliases = suggestion_aliases
            if isinstance(added_argument.choices, dict):
                # choices is a name: description dict. Set the choices attribute to the
                # keys for argparse and the choices_help attribute to the dict for
                # the markdown generator.
                setattr(added_argument, 'choices_help', added_argument.choices)
                added_argument.choices = sorted(added_argument.choices.keys())
            self.flag_args.append(added_argument)

            inverted_flag = self._AddInvertedBooleanFlagIfNecessary(
                added_argument, name, dest, kwargs)
            if inverted_flag:
                inverted_flag.category = category
                inverted_flag.do_not_propagate = do_not_propagate
                inverted_flag.is_replicated = is_replicated
                inverted_flag.is_global = is_global
                # Don't add suggestion aliases for the inverted flag.  It can only map
                # to one or the other.
                self.flag_args.append(inverted_flag)

        return added_argument
Esempio n. 20
0
  def _AttachCompleter(self, arg, name, completer, positional,
                       deprecated_collection=None,
                       deprecated_list_command=None,
                       deprecated_list_command_callback=None):
    """Attaches a completer to arg if one is specified.

    Args:
      arg: The argument to attach the completer to.
      name: The arg name for messaging.
      completer: The completer Completer class or argcomplete function object.
      positional: True if argument is a positional.
      deprecated_collection: The collection name for the resource to complete.
      deprecated_list_command: The command whose Run() method returns the
        current resource list.
      deprecated_list_command_callback: A callback function that returns the
        list command to run.
    """
    if not completer:
      if not deprecated_collection:
        if deprecated_list_command or deprecated_list_command_callback:
          raise parser_errors.ArgumentException(
              'Command [{}] argument [{}] does not have completion_resource '
              'set but has one or more of the deprecated list_command_path '
              'and list_command_callback_fn attributes.'.format(
                  ' '.join(self.data.command_name), name))
        return

      class DeprecatedCompleter(
          deprecated_completers.DeprecatedListCommandCompleter):

        def __init__(self, **kwargs):
          super(DeprecatedCompleter, self).__init__(
              collection=deprecated_collection,
              list_command=deprecated_list_command,
              list_command_callback=deprecated_list_command_callback,
              **kwargs)

      DeprecatedCompleter.__name__ = (
          resource_property.ConvertToCamelCase(
              deprecated_collection.capitalize().replace('.', '_')) +
          'DeprecatedCompleter')

      completer = DeprecatedCompleter
    elif (deprecated_collection or
          deprecated_list_command or
          deprecated_list_command_callback):
      raise parser_errors.ArgumentException(
          'Command [{}] argument [{}] has a completer set with one or more '
          'of the deprecated completion_resource, list_command_path, and '
          'list_command_callback_fn attributes.'.format(
              ' '.join(self.data.command_name), name))
    if isinstance(completer, type):
      # A completer class that will be instantiated at completion time.
      if positional and issubclass(completer, completion_cache.Completer):
        # The list of positional resource completers is used to determine
        # parameters that must be present in the completions.
        self.data.positional_completers.add(completer)
      arg.completer = parser_completer.ArgumentCompleter(
          completer, argument=arg)
    else:
      arg.completer = completer
Esempio n. 21
0
 def DeprecationFunc(value):
     if show_message(value):
         if removed:
             raise parser_errors.ArgumentException(add_help.message)
         else:
             log.warn(add_help.message)
Esempio n. 22
0
  def add_argument(self, *args, **kwargs):
    """add_argument intercepts calls to the parser to track arguments."""
    name = args[0]

    # The flag category name, None for no category. This is also used for help
    # printing. Flags in the same category are grouped together in a section
    # named "{category} FLAGS".
    category = kwargs.pop('category', None)
    # The unbound completer object or raw argcomplete completer function).
    completer = kwargs.pop('completer', None)
    # The default value.
    default = kwargs.get('default')
    # The namespace destination attribute name.
    dest = kwargs.get('dest')
    if not dest:
      dest = name.lstrip(self.parser.prefix_chars).replace('-', '_')
    # A flag that can only be supplied where it is defined and not propagated to
    # subcommands.
    do_not_propagate = kwargs.pop('do_not_propagate', False)
    # hidden=True retains help but does not display it.
    hidden = kwargs.pop('hidden', False)
    help_text = kwargs.get('help')
    if not help_text:
      raise ValueError('Argument {} requires help text [hidden={}]'.format(
          name, hidden))
    if help_text == argparse.SUPPRESS:
      raise ValueError('Argument {} needs hidden=True instead of '
                       'help=argparse.SUPPRESS.'.format(name))
    # A global flag that is added at each level explicitly because each command
    # has a different behavior (like -h).
    is_replicated = kwargs.pop('is_replicated', False)
    # This is used for help printing.  A flag is considered global if it is
    # added at the root of the CLI tree, or if it is explicitly added to every
    # command level.
    is_global = self.is_global or is_replicated
    # The number positional args.
    nargs = kwargs.get('nargs')
    # The argument is required if True.
    required = kwargs.get('required', False)
    # Any alias this flag has for the purposes of the "did you mean"
    # suggestions.
    suggestion_aliases = kwargs.pop('suggestion_aliases', None)
    if suggestion_aliases is None:
      suggestion_aliases = []

    if self.is_global and category == base.COMMONLY_USED_FLAGS:
      category = 'GLOBAL'

    positional = not name.startswith('-')
    if positional:
      if not self.allow_positional:
        # TODO(b/36054662): More informative error message here about which
        # group the problem is in.
        raise parser_errors.ArgumentException(
            'Illegal positional argument [{0}] for command [{1}]'.format(
                name, '.'.join(self.data.command_name)))
      if '-' in name:
        raise parser_errors.ArgumentException(
            "Positional arguments cannot contain a '-'. Illegal argument [{0}] "
            'for command [{1}]'.format(name, '.'.join(self.data.command_name)))
      if category:
        raise parser_errors.ArgumentException(
            'Positional argument [{0}] cannot have a category in '
            'command [{1}]'.format(name, '.'.join(self.data.command_name)))
      if suggestion_aliases:
        raise parser_errors.ArgumentException(
            'Positional argument [{0}] cannot have suggestion aliases in '
            'command [{1}]'.format(name, '.'.join(self.data.command_name)))

    self.defaults[dest] = default
    if required:
      self.required.append(dest)
    self.dests.append(dest)

    if positional and 'metavar' not in kwargs:
      kwargs['metavar'] = name.upper()
    if kwargs.get('nargs') is argparse.REMAINDER:
      added_argument = self.parser.AddRemainderArgument(*args, **kwargs)
    else:
      added_argument = self.parser.add_argument(*args, **kwargs)
    self._AttachCompleter(added_argument, completer, positional)
    added_argument.is_global = is_global
    added_argument.is_group = False
    added_argument.is_hidden = hidden
    added_argument.is_required = required
    added_argument.is_positional = positional
    if hidden:
      # argparse uses SUPPRESS -- cli_tree uses hidden_help to work around
      added_argument.hidden_help = added_argument.help
      added_argument.help = argparse.SUPPRESS
    if positional:
      if category:
        raise parser_errors.ArgumentException(
            'Positional argument [{0}] cannot have a category in '
            'command [{1}]'.format(name, '.'.join(self.data.command_name)))
      if (nargs is None or
          nargs == '+' or
          isinstance(nargs, int) and nargs > 0):
        added_argument.is_required = True
      self.positional_args.append(added_argument)
    else:
      if category and required:
        raise parser_errors.ArgumentException(
            'Required flag [{0}] cannot have a category in '
            'command [{1}]'.format(name, '.'.join(self.data.command_name)))
      if category == 'REQUIRED':
        raise parser_errors.ArgumentException(
            "Flag [{0}] cannot have category='REQUIRED' in "
            'command [{1}]'.format(name, '.'.join(self.data.command_name)))
      added_argument.category = category
      added_argument.do_not_propagate = do_not_propagate
      added_argument.is_replicated = is_replicated
      added_argument.suggestion_aliases = suggestion_aliases
      if isinstance(added_argument.choices, dict):
        # choices is a name: description dict. Set the choices attribute to the
        # keys for argparse and the choices_help attribute to the dict for
        # the markdown generator.
        setattr(added_argument, 'choices_help', added_argument.choices)
        added_argument.choices = sorted(added_argument.choices.keys())
      self.flag_args.append(added_argument)

      inverted_flag = self._AddInvertedBooleanFlagIfNecessary(
          added_argument, name, dest, kwargs)
      if inverted_flag:
        inverted_flag.category = category
        inverted_flag.do_not_propagate = do_not_propagate
        inverted_flag.is_replicated = is_replicated
        inverted_flag.is_global = is_global
        # Don't add suggestion aliases for the inverted flag.  It can only map
        # to one or the other.
        self.flag_args.append(inverted_flag)

    if (not getattr(added_argument, 'is_replicated', False) or
        len(self.command_name) == 1):
      self.arguments.append(added_argument)
    return added_argument