github.com/bugraaydogar/snapd@v0.0.0-20210315170335-8c70bb858939/cmd/snap/cmd_interface.go (about)

     1  // -*- Mode: Go; indent-tabs-mode: t -*-
     2  
     3  /*
     4   * Copyright (C) 2017 Canonical Ltd
     5   *
     6   * This program is free software: you can redistribute it and/or modify
     7   * it under the terms of the GNU General Public License version 3 as
     8   * published by the Free Software Foundation.
     9   *
    10   * This program is distributed in the hope that it will be useful,
    11   * but WITHOUT ANY WARRANTY; without even the implied warranty of
    12   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    13   * GNU General Public License for more details.
    14   *
    15   * You should have received a copy of the GNU General Public License
    16   * along with this program.  If not, see <http://www.gnu.org/licenses/>.
    17   *
    18   */
    19  
    20  package main
    21  
    22  import (
    23  	"encoding/json"
    24  	"fmt"
    25  	"io"
    26  	"sort"
    27  	"text/tabwriter"
    28  
    29  	"github.com/snapcore/snapd/client"
    30  	"github.com/snapcore/snapd/i18n"
    31  
    32  	"github.com/jessevdk/go-flags"
    33  )
    34  
    35  type cmdInterface struct {
    36  	clientMixin
    37  	ShowAttrs   bool `long:"attrs"`
    38  	ShowAll     bool `long:"all"`
    39  	Positionals struct {
    40  		Interface interfaceName `skip-help:"true"`
    41  	} `positional-args:"true"`
    42  }
    43  
    44  var shortInterfaceHelp = i18n.G("Show details of snap interfaces")
    45  var longInterfaceHelp = i18n.G(`
    46  The interface command shows details of snap interfaces.
    47  
    48  If no interface name is provided, a list of interface names with at least
    49  one connection is shown, or a list of all interfaces if --all is provided.
    50  `)
    51  
    52  func init() {
    53  	addCommand("interface", shortInterfaceHelp, longInterfaceHelp, func() flags.Commander {
    54  		return &cmdInterface{}
    55  	}, map[string]string{
    56  		// TRANSLATORS: This should not start with a lowercase letter.
    57  		"attrs": i18n.G("Show interface attributes"),
    58  		// TRANSLATORS: This should not start with a lowercase letter.
    59  		"all": i18n.G("Include unused interfaces"),
    60  	}, []argDesc{{
    61  		// TRANSLATORS: This needs to begin with < and end with >
    62  		name: i18n.G("<interface>"),
    63  		// TRANSLATORS: This should not start with a lowercase letter.
    64  		desc: i18n.G("Show details of a specific interface"),
    65  	}})
    66  }
    67  
    68  func (x *cmdInterface) Execute(args []string) error {
    69  	if len(args) > 0 {
    70  		return ErrExtraArgs
    71  	}
    72  
    73  	if x.Positionals.Interface != "" {
    74  		// Show one interface in detail.
    75  		name := string(x.Positionals.Interface)
    76  		ifaces, err := x.client.Interfaces(&client.InterfaceOptions{
    77  			Names: []string{name},
    78  			Doc:   true,
    79  			Plugs: true,
    80  			Slots: true,
    81  		})
    82  		if err != nil {
    83  			return err
    84  		}
    85  		if len(ifaces) == 0 {
    86  			return fmt.Errorf(i18n.G("no such interface"))
    87  		}
    88  		x.showOneInterface(ifaces[0])
    89  	} else {
    90  		// Show an overview of available interfaces.
    91  		ifaces, err := x.client.Interfaces(&client.InterfaceOptions{
    92  			Connected: !x.ShowAll,
    93  		})
    94  		if err != nil {
    95  			return err
    96  		}
    97  		if len(ifaces) == 0 {
    98  			if x.ShowAll {
    99  				return fmt.Errorf(i18n.G("no interfaces found"))
   100  			}
   101  			return fmt.Errorf(i18n.G("no interfaces currently connected"))
   102  		}
   103  		x.showManyInterfaces(ifaces)
   104  	}
   105  	return nil
   106  }
   107  
   108  func (x *cmdInterface) showOneInterface(iface *client.Interface) {
   109  	w := tabwriter.NewWriter(Stdout, 2, 2, 1, ' ', 0)
   110  	defer w.Flush()
   111  
   112  	fmt.Fprintf(w, "name:\t%s\n", iface.Name)
   113  	if iface.Summary != "" {
   114  		fmt.Fprintf(w, "summary:\t%s\n", iface.Summary)
   115  	}
   116  	if iface.DocURL != "" {
   117  		fmt.Fprintf(w, "documentation:\t%s\n", iface.DocURL)
   118  	}
   119  	if len(iface.Plugs) > 0 {
   120  		fmt.Fprintf(w, "plugs:\n")
   121  		for _, plug := range iface.Plugs {
   122  			var labelPart string
   123  			if plug.Label != "" {
   124  				labelPart = fmt.Sprintf(" (%s)", plug.Label)
   125  			}
   126  			if plug.Name == iface.Name {
   127  				fmt.Fprintf(w, "  - %s%s", plug.Snap, labelPart)
   128  			} else {
   129  				fmt.Fprintf(w, `  - %s:%s%s`, plug.Snap, plug.Name, labelPart)
   130  			}
   131  			// Print a colon which will make the snap:plug element a key-value
   132  			// yaml object so that we can write the attributes.
   133  			if len(plug.Attrs) > 0 && x.ShowAttrs {
   134  				fmt.Fprintf(w, ":\n")
   135  				x.showAttrs(w, plug.Attrs, "    ")
   136  			} else {
   137  				fmt.Fprintf(w, "\n")
   138  			}
   139  		}
   140  	}
   141  	if len(iface.Slots) > 0 {
   142  		fmt.Fprintf(w, "slots:\n")
   143  		for _, slot := range iface.Slots {
   144  			var labelPart string
   145  			if slot.Label != "" {
   146  				labelPart = fmt.Sprintf(" (%s)", slot.Label)
   147  			}
   148  			if slot.Name == iface.Name {
   149  				fmt.Fprintf(w, "  - %s%s", slot.Snap, labelPart)
   150  			} else {
   151  				fmt.Fprintf(w, `  - %s:%s%s`, slot.Snap, slot.Name, labelPart)
   152  			}
   153  			// Print a colon which will make the snap:slot element a key-value
   154  			// yaml object so that we can write the attributes.
   155  			if len(slot.Attrs) > 0 && x.ShowAttrs {
   156  				fmt.Fprintf(w, ":\n")
   157  				x.showAttrs(w, slot.Attrs, "    ")
   158  			} else {
   159  				fmt.Fprintf(w, "\n")
   160  			}
   161  		}
   162  	}
   163  }
   164  
   165  func (x *cmdInterface) showManyInterfaces(infos []*client.Interface) {
   166  	w := tabWriter()
   167  	defer w.Flush()
   168  	fmt.Fprintln(w, i18n.G("Name\tSummary"))
   169  	for _, iface := range infos {
   170  		fmt.Fprintf(w, "%s\t%s\n", iface.Name, iface.Summary)
   171  	}
   172  }
   173  
   174  func (x *cmdInterface) showAttrs(w io.Writer, attrs map[string]interface{}, indent string) {
   175  	if len(attrs) == 0 {
   176  		return
   177  	}
   178  	names := make([]string, 0, len(attrs))
   179  	for name := range attrs {
   180  		names = append(names, name)
   181  	}
   182  	sort.Strings(names)
   183  	for _, name := range names {
   184  		value := attrs[name]
   185  		switch value.(type) {
   186  		case string, bool, json.Number:
   187  			fmt.Fprintf(w, "%s  %s:\t%v\n", indent, name, value)
   188  		}
   189  	}
   190  }