One place for hosting & domains

      paquete

      Cómo crear un paquete y publicar una aplicación de Snap en Ubuntu 18.04


      El autor seleccionó la Electronic Frontier Foundation para recibir una donación como parte del programa Write for DOnations.

      Introducción

      Uno de los mayores desafíos en el desarrollo de aplicaciones es el paso final de distribuir el producto acabado a sus usuarios o clientes. Muchos de los métodos para la implementación de aplicaciones carecen de sencillez y seguridad o no incorporan estrategias para actualizar de forma automática una aplicación una vez que se instaló.

      Snap es un formato moderno de empaquetamiento de aplicaciones que cuenta con potentes funciones de banco de pruebas y seguridad e incluye aislamiento del sistema de archivos, actualizaciones automáticas y gestión de dependencias integrada. Las aplicaciones Snap, conocidas como Snaps, pueden descargarse e instalarse usando un programa de línea de comandos, similar a apt o yum. Ubuntu viene con Snap previamente instalado, lo cual significa que las aplicaciones Snap tienen muchos adeptos.

      A través de este tutorial, creará una aplicación Snap y la publicará en la Snap Store.

      Requisitos previos

      Para completar este tutorial, necesitará lo siguiente:

      • Un servidor de Ubuntu 18.04 configurado conforme a la Configuración inicial de servidores con Ubuntu 18.04, con un usuario sudo no root.

      • Una aplicación que quiere empaquetar y publicar en el formato Snap. Esta puede ser una aplicación compleja que creó, un proyecto común de código abierto, o un simple “¡Hello, world!”. Mundo!”. Si aún no tiene una aplicación, en el paso 1 de este tutorial se abordará la manera de crear un programa Hello World en Go.

      • Una cuenta en el panel de control de Snapcraft para desarrolladores.

      Una vez que tenga todo esto listo, inicie sesión en su servidor como usuario no root.

      Paso 1: Preparar su aplicación para agregarla a un paquete

      Primero, preparará su aplicación para empaquetarla como aplicación Snap asegurándose de que todo lo necesario esté presente en un único directorio.

      Comience creando un nuevo directorio para su Snap y posicionándose en él:

      • mkdir ~/your-snap
      • cd ~/your-snap

      A continuación, si ya dispone de una aplicación, disponga una copia completa del código fuente de su aplicación en el directorio que acaba de crear. El proceso aquí variará considerablemente según la aplicación exacta que empaquete; sin embargo, en caso de que el código fuente se almacene en un repositorio de Git, puede aplicar git init en un repositorio del directorio y extraer todo el código pertinente.

      Si aún no tiene una aplicación que desee empaquetar, puede crear un programa “Hello World” para usarlo como alternativa. Si desea más información sobre cómo escribir este programa con Go, consulte el tutorial Cómo escribir su primer programa en Go.

      Puede hacer esto creando primero un nuevo archivo de Go y abriéndolo con su editor de texto preferido:

      A continuación, añada el siguiente código al archivo:

      helloworld.go

      package main
      import "fmt"
      func main() {
        fmt.Println("Hello, world!")
      }
      

      Guarde el archivo y ciérrelo.

      Si no tiene Go instalado, puede instalarlo usando el siguiente comando:

      • sudo apt install golang-go

      Una vez instalado Go, puede ejecutar su nuevo programa para comprobar que funcione:

      Verá el siguiente resultado:

      Output

      Hello, world!

      Con esto, habrá preparado su aplicación para empaquetarla con el formato Snap. A continuación, instalará el software necesario para iniciar el proceso de empaquetamiento.

      Paso 2: Instalar Snapcraft

      En este paso, descargará e instalará Snapcraft; este es el nombre que recibe la herramienta oficial de creación de paquetes de aplicaciones Snap. Snapcraft está disponible en la Snap Store, que existe en Ubuntu por defecto. Esto significa que puede instalar Snapcraft desde la línea de comandos usando el comando snap.

      El comando snap es equivalente al comando apt, pero puede usarlo para instalar software desde la Snap Store, en lugar de paquetes desde los repositorios Apt.

      Para instalar Snapcraft, ejecute el siguiente comando:

      • sudo snap install snapcraft --classic

      Se utiliza el argumento de comando --classic para que Snapcraft se instalae sin las funciones de banco de pruebas estrictas que normalmente se usan en las Snaps. Snapcraft requiere este argumento, ya que necesita más acceso privilegiado a su sistema para empaquetar las aplicaciones de forma fiable.

      Una vez que instale Snapcraft, verá lo siguiente:

      Output

      snapcraft 3.9.8 from Canonical✓ installed

      Finalmente, puede verificar la instalación de Snapcraft ejecutando lo siguiente:

      Con esto se mostrará algo similar a lo siguiente:

      Output

      snapcraft, version 3.9.8

      Ahora que instaló Snapcraft, puede empezar a definir la configuración y los metadatos para su aplicación Snap.

      En este paso, empezará a definir la configuración, la estructura y los metadatos para su aplicación Snap.

      Comience verificando que aún esté trabajando en el directorio de su aplicación Snap:

      A continuación, cree y edite el archivo snapcraft.yaml usando su editor de texto preferido:

      Usará el archivo snapcraft.yaml para almacenar toda la configuración para su aplicación Snap, incluidos el nombre, la descripción y la versión, además de los ajustes relacionados con la gestión de dependencias y el banco de pruebas.

      Comience definiendo el nombre, el resumen, la descripción y el número de la versión de su aplicación:

      snapcraft.yaml

      name: your-snap
      summary: A summary of your application in 78 characters or less.
      description: |
        A detailed description of your application.
        The description can have multiple lines.
      version: '1.0'
      

      El nombre de su Snap debe ser único si desea publicarla en la Snap Store; busque otras aplicaciones con el mismo nombre para asegurarse de que no exista aún.

      A continuación, puede definir el comando o los comandos que desee asociar a su aplicación. Esto permitirá usar su Snap desde la línea de comandos Bash como un comando normal.

      Agregue lo siguiente a su archivo snapcraft.yaml:

      snapcraft.yaml

      . . .
      apps:
        your-snap-command:
          command: your-snap
      

      your-snap-command es el nombre del comando que desea definir. Por ejemplo, es posible que desee usar el comando helloworld para ejecutar su programa Hello World.

      Se utiliza el comando: your-snap para indicar a Snapcraft lo que debe hacer cuando se ejecuta el comando de la aplicación. En el caso del programa Hello World, usaría el valor helloworld para hacer referencia al archivo helloworld.go, lo que permitirá a Snapcraft ejecutar su programa de forma correcta.

      Como resultado, se obtiene la siguiente configuración de ejemplo:

      snapcraft.yaml

      apps:
        helloworld:
          command: helloworld
      

      Si el nombre del comando coincide exactamente con el nombre de la Snap, podrá ejecutarlo de manera directa desde la línea de comandos. Si el comando no coincide con el nombre de la Snap, se le añadirá automáticamente el nombre de la Snap. Por ejemplo, helloworld.command1.

      Por último, puede definir las partes que formarán su aplicación Snap. Las aplicaciones Snap constan de varias partes, que son todos los componentes que forman su aplicación. En muchos casos solo hay una parte, que es la aplicación en sí misma.

      Cada parte tiene un complemento asociado. Por ejemplo, para los componentes de su aplicación escritos en Ruby se utiliza el complemento ruby y para los componentes escritos en Go se utiliza el complemento go.

      Puede usar el comando list-plugins de Snapcraft a fin de identificar los complementos correctos para su aplicación.

      Con esto, se mostrará algo similar a lo siguiente:

      Output

      ant catkin-tools conda dump gradle make nil python rust autotools cmake crystal go kbuild maven nodejs qmake scons catkin colcon dotnet godeps kernel meson plainbox-provider ruby waf

      Los complementos más comunes son aquellos para los lenguajes de programación más habituales, como Go, Rust, Ruby o Python.

      Una vez que haya identificado los complementos correctos para su aplicación, podrá comenzar a añadir la configuración parts a su archivo snapcraft.yaml:

      snapcraft.yaml

      . . .
      parts:
        your-snap:
          plugin: plugin-name
          source: .
      

      Se utiliza el parámetro de configuración source para especificar la ruta relativa del código fuente de su aplicación. Normalmente, este será el mismo directorio que el del archivo snapcraft.yaml, de modo que el valor source es un punto (.).

      Nota: Si en el componente de su aplicación hay dependencias que se necesiten para su compilación o ejecución, puede especificarlas usando los atributos build-packages y stage-packages. Los nombres de dependencias especificados se obtendrán automáticamente a través del administrador de paquetes predeterminado de su sistema.

      Por ejemplo:

      snapcraft.yaml

      parts:
        your-snap:
        plugin: plugin-name
        source: .
        build-packages:
        - gcc
        - make
        stage-packages:
        - libcurl4
      

      Algunos complementos de Snapcraft tienen sus propias opciones específicas que pueden ser necesarias para su aplicación, de modo que vale la pena revisar las páginas pertinentes del manual para su complemento:

      • snapcraft help plugin-name

      En el caso de las aplicaciones de Go, especificaría también el go-importpath. Para la configuración de Hello World, como resultado de esto se obtiene la siguiente configuración de ejemplo:

      snapcraft.yaml

      parts:
        helloworld:
          plugin: go
          source: .
          go-importpath: helloworld
      

      Puede dejar su archivo snapcraft.yaml abierto para añadir ajustes en el siguiente paso.

      Con esto, definió la configuración básica para su aplicación Snap. A continuación, configurará los aspectos de seguridad y banco de pruebas de su aplicación.

      Paso 4: Proteger su aplicación Snap

      Las aplicaciones Snap están diseñadas para ejecutarse en un entorno de banco de pruebas. Por ello, en este paso configurará el banco de pruebas para su Snap. Primero, deberá habilitar el banco de pruebas para su aplicación, conocido en Snapcraft como confinement.

      Agregue lo siguiente a su archivo snapcraft.yaml:

      snapcraft.yaml

      . . .
      confinement: strict
      

      Esto permitirá la aplicación de un banco de pruebas para su aplicación, lo cual evitará que esta acceda a Internet, a otras Snaps en ejecución o al sistema host. Sin embargo, en la mayoría de los casos, no es necesario que las aplicaciones puedan comunicarse fuera de su banco de pruebas, como cuando necesitan acceder a Internet o realizar tareas de lectura y escritura en el sistema de archivos.

      Estos permisos, conocidos en Snapcraft como interfaces, pueden concederse a su aplicación Snap mediante Plugs. Usando los Plugs, puede controlar de forma exhaustiva el banco de pruebas de su aplicación para darle el acceso que requiere y nada más (principio de privilegio menor).

      Las interfaces exactas necesarias variarán dependiendo de su aplicación. Las siguientes son algunas de las interfaces más comunes:

      • audio-playback: permite la salida de audio y la reproducción de sonidos.
      • audio-record: permite la entrada y grabación de audio.
      • camera: permite el acceso a cámaras web conectadas.
      • home: permite el acceso a archivos no ocultos en su directorio de inicio.
      • network: permite el acceso a la red y a Internet.
      • network-bind: permite la vinculación a puertos para el funcionamiento como servicio de red.
      • system-files: permite el acceso a todo el sistema de archivos del equipo host.

      La lista completa de interfaces disponibles está en la documentación de Snapcraft, en la sección Supported Interfaces (interfaces compatibles).

      Una vez que haya identificado todas las interfaces requeridas para su aplicación, puede comenzar a asignarlas a los plugs en su archivo snapcraft-yaml.

      La siguiente configuración de ejemplo permitirá que la aplicación acceda a la red y al área de inicio de los usuarios:

      snapcraft.yaml

      . . .
      plugs:
        your-snap-home:
          interface: home
        your-snap-network:
          interface: network
      

      Guarde y cierre su archivo.

      El nombre del Plug debería ser descriptivo para ayudar a los usuarios a identificar su finalidad.

      Habilitó el banco de pruebas para su Snap y configuró algunos Plugs para conceder acceso limitado a recursos del sistema. A continuación, terminará de compilar su aplicación Snap.

      Paso 5: Compilar y probar su aplicación Snap

      Ahora que escribió toda la configuración necesaria para su Snap, puede proceder con la compilación y prueba del paquete de Snap a nivel local.

      Si ha seguido los pasos de este tutorial con un programa Hello World como aplicación, su archivo snapcraft.yaml completo ahora tendrá un aspecto similar al siguiente:

      snapcraft.yaml

      name: helloworld
      summary: A simple Hello World program.
      description: |
        A simple Hello World program written in Go.
        Packaged as a Snap application using Snapcraft.
      version: '1.0'
      confinement: strict
      
      apps:
        helloworld:
          command: helloworld
      
      parts:
        helloworld:
          plugin: go
          source: .
          go-importpath: helloworld
      
      plugs:
        helloworld-home:
          interface: home
        helloworld-network:
          interface: network
      

      Para compilar su aplicación Snap, ejecute el comando snapcraft desde el directorio de esta:

      Snapcraft iniciará automáticamente una máquina virtual (VM) y comenzará a compilar su Snap. Una vez completado el proceso, Snapcraft se cerrará y verá algo similar a lo siguiente:

      Output

      Snapped your-snap_1.0_amd64.snap

      Ahora puede instalar su Snap localmente para comprobar si funciona:

      • sudo snap install your-snap.snap --dangerous

      El argumento del comando --dangerous es necesario ya que se instala un Snap local sin firma.

      Output

      your-snap 1.0 installed

      Una vez completado el proceso de instalación, puede ejecutar su Snap usando su comando asociado. Por ejemplo:

      En el caso del programa Hello World de ejemplo, el resultado será el siguiente:

      Output

      Hello, world!

      También puede ver la política de banco de pruebas para su Snap, a fin de garantizar que los permisos asignados se hayan concedido de forma adecuada:

      • snap connections your-snap

      Esto dará como resultado una lista de Plugs e interfaces similar a la siguiente:

      Output

      snap connections your-snap Interface Plug Slot Notes home your-snap:your-snap-home :home - network your-snap:your-snap-network :network -

      En este paso, compiló su Snap y lo instaló localmente para probar que funciona. A continuación, publicará su Snap en la Snap Store.

      Paso 6: Publicar su Snap

      Ahora que compiló y probó su aplicación Snap, es el momento de publicarla en la Snap Store.

      Comience iniciando sesión en su cuenta de desarrollador de Snap usando la aplicación de línea de comandos de Snapcraft:

      Siga las instrucciones para introducir su dirección de correo electrónico y su contraseña.

      A continuación, deberá registrar el nombre de la aplicación en la Snap Store:

      • snapcraft register your-snap

      Una vez que registre el nombre de la Snap, podrá subir el paquete de Snap a la tienda:

      • snapcraft push your-snap.snap

      Visualizará un resultado similar al siguiente:

      Output

      Preparing to push 'your-snap_1.0_amd64.snap'. Install the review-tools from the Snap Store for enhanced checks before uploading this snap. Pushing 'your-snap_1.0_amd64.snap' [===================================================================================================] 100% Processing...| Ready to release! Revision 1 of 'your-snap' created.

      Cada vez que suba contenido a la Snap Store, el número de revisión aumentará, comenzando por uno. Esto es útil para ayudar a identificar las diferentes compilaciones de su Snap.

      Finalmente, puede publicar su Snap:

      • snapcraft release your-snap revision-number channel

      Si esta es la primera vez que sube contenido a la Snap Store, el número de revisión será 1. También puede optar por realizar su publicación en los canales stable, candidate, beta y edge, si tiene varias versiones de su aplicación en diferentes etapas de desarrollo.

      Por ejemplo, con el siguiente comando se publicará la revisión 1 de la Snap Hello World en el canal stable:

      • snapcraft release helloworld 1 stable

      Visualizará un resultado similar al siguiente:

      Output

      Track Arch Channel Version Revision latest amd64 stable 1.0 1 candidate ^ ^ beta ^ ^ edge ^ ^ The 'stable' channel is now open.

      Ahora puede buscar su aplicación en la Snap Store e instalarla en cualquiera de sus dispositivos.

      Tienda de Snapcraft con la aplicación HelloWord n los resultados de búsqueda

      En este paso final, subió su paquete de Snap compilado a la Snap Store y lo puso a disponibilidad del público en general.

      Conclusión

      A través de este artículo, configuró y compiló una aplicación Snap, y luego la publicó a través de la Snap Store. Ahora tiene el conocimiento básico necesario para realizar el mantenimiento de su aplicación y crear nuevas aplicaciones.

      Si desea explorar las Snaps en mayor profundidad, es posible que desee recorrer toda la Snap Store. Es posible que desee revisar la Referencia YAML de Snapcraft para comprender mejor el tema e identificar atributos adicionales para la configuración de su Snap.

      Por último, si desea obtener más información sobre el desarrollo de Snaps, le gustará leer material sobre enlaces de Snap e implementarlos; estos permiten que los Snaps reaccionen de forma dinámica a los cambios del sistema, como las actualizaciones o los ajustes de las políticas de seguridad.



      Source link

      Introducción al paquete de Strings en Go


      Introducción

      El paquete string de Go tiene varias funciones disponibles para trabajar con el tipo de datos de cadena. Estas funciones nos permiten modificar y manipular fácilmente las cadenas. Podemos pensar que las funciones son acciones que realizamos en elementos de nuestro código. Las funciones integradas son aquellas que se definen en el lenguaje de programación de Go y están inmediatamente disponibles para su uso.

      En este tutorial, revisaremos varias funciones diferentes que podemos usar para trabajar con cadenas en Go.

      Aplicar mayúsculas y minúsculas a cadenas

      Las funciones strings.ToUpper y strings.ToLower mostrarán una cadena con todas las letras de una cadena original convertidas a mayúsculas o minúsculas. Debido a que las cadenas son tipos de datos inmutables, la cadena devuelta será nueva. Cualquier carácter de la cadena que no sea una letra no se cambiará.

      Para convertir la cadena "Sammy Shark" de modo que esté totalmente en mayúsculas, utilizaría la función strings.ToUpper:

      ss := "Sammy Shark"
      fmt.Println(strings.ToUpper(ss))
      

      Output

      SAMMY SHARK

      Para la conversión a minúsculas:

      fmt.Println(strings.ToLower(ss))
      

      Output

      sammy shark

      Debido a usará el paquete strings, primero deberá importarlo a un programa. Para convertir la cadena a mayúsculas y minúsculas, todo el programa tendría el siguiente aspecto:

      package main
      
      import (
          "fmt"
          "strings"
      )
      
      func main() {
          ss := "Sammy Shark"
          fmt.Println(strings.ToUpper(ss))
          fmt.Println(strings.ToLower(ss))
      }
      

      Las funciones strings.ToUpper y strings.ToLower facilitan la evaluación y comparación de cadenas haciendo que las letras sean mayúsculas o minúsculas de manera uniforme. Por ejemplo, si un usuario escribe su nombre en minúsculas, aún podemos determinar si su nombre está en nuestra base de datos comparándolo con una versión totalmente en mayúsculas.

      Funciones de búsqueda de cadena

      El paquete strings tiene varias funciones que permiten determinar si una cadena contiene una secuencia de caracteres específica.

      Función Uso
      strings.HasPrefix Realiza búsquedas en la cadena desde el principio.
      strings.HasSuffix Realiza búsquedas en la cadena desde el final.
      strings.Contains Realiza búsquedas en cualquier parte de la cadena.
      strings.Count Cuenta la cantidad de veces que aparece la cadena.

      Las funciones strings.HasPrefix y strings.HasSuffix le permiten comprobar si una cadena comienza o finaliza con un conjunto específico de caracteres.

      Por ejemplo, para comprobar si la cadena "Sammy Shark" comienza con Sammy y finaliza con Shark:

      ss := "Sammy Shark"
      fmt.Println(strings.HasPrefix(ss, "Sammy"))
      fmt.Println(strings.HasSuffix(ss, "Shark"))
      

      Output

      true true

      Usaría la función strings.Contains para comprobar si "Sammy Shark" contiene la secuencia Sh:

      fmt.Println(strings.Contains(ss, "Sh"))
      

      Output

      true

      Finalmente, para ver cuántas veces aparece la letra S en la frase Sammy Shark:

      fmt.Println(strings.Count(ss, "S"))
      

      Output

      2

      Nota: Para todas las cadenas de Go se distinguen mayúsculas y minúsculas. Esto significa que Sammy no es igual que sammy.

      Usar una s en minúsculas para obtener un recuento de Sammy Shark no es lo mismo que usar una S mayúscula:

      fmt.Println(strings.Count(ss, "s"))
      

      Output

      0

      Debido a que S es diferente de s, el recuento será 0.

      Las funciones de cadenas son útiles cuando desea comparar o buscar cadenas en su programa.

      Determinar la longitud de la cadena

      La función integrada len() muestra el número de caracteres de una cadena. Esta función es útil cuando necesita aplicar extensiones mínimas o máximas de contraseñas, o para acortar cadenas más grandes de modo que estén dentro de ciertos límites para su uso como abreviaturas.

      Para demostrar esta función, buscaremos la extensión de una cadena larga como una oración:

      import (
          "fmt"
          "strings"
      )
      
      func main() {
              openSource := "Sammy contributes to open source."
              fmt.Println(len(openSource))
      }
      

      Output

      33

      Establecemos la variable openSource igual a la cadena "Sammy contributes to open source." y dicha variable se pasa a la función len() con len(openSource). Finalmente, pasamos la función a la función fmt.Println() para poder ver el resultado del programa en la pantalla.

      Tenga en cuenta que la función len() contará cualquier carácter vinculado por dobles comillas, como letras, números, caracteres de espacios en blanco y símbolos.

      Funciones para la manipulación de cadenas

      Las funciones strings.Join, strings.Split y strings.ReplaceAll son algunas formas adicionales de manipular cadenas en Go.

      La función strings.Join es útil para combinar un segmento de cadenas en una nueva cadena única.

      Para crear una cadena separada por comas a partir de un segmento de cadenas, usaríamos esta función de la siguiente forma:

      fmt.Println(strings.Join([]string{"sharks", "crustaceans", "plankton"}, ","))
      

      Output

      sharks,crustaceans,plankton

      Si deseamos añadir una coma y un espacio entre los valores de cadena de nuestra nueva cadena, podemos simplemente reescribir nuestra expresión con un espacio en blanco después de la coma: strings.Join([]string{"sharks", "crustaceans", "plankton"}, ", ").

      Así como podemos unir cadenas, también podemos dividirlas. Para hacer esto, podemos usar la función strings.Split y realizar divisiones en los espacios:

      balloon := "Sammy has a balloon."
      s := strings.Split(balloon, " ")
      fmt.Println(s)
      

      Output

      [Sammy has a balloon]

      El resultado es un segmento de cadenas. Debido a que se utilizó strings.Println, es difícil determinar el resultado con solo mirar. Para ver que es de hecho un segmento de cadenas, utilice la función fmt.Printf con el verbo %q para poner las cadenas entre comillas:

      fmt.Printf("%q", s)
      

      Output

      ["Sammy" "has" "a" "balloon."]

      Otra función útil además de strings.Split es strings.Fields. La diferencia es que strings.Fields ignorará todos los espacios en blanco y solo dividirá los fields reales en una cadena:

      data := "  username password     email  date"
      fields := strings.Fields(data)
      fmt.Printf("%q", fields)
      

      Output

      ["username" "password" "email" "date"]

      La función strings.ReplaceAll puede tomar una cadena original y mostrar una cadena actualizada con alguna sustitución.

      Digamos que el globo que Sammy tenía se perdió. Debido a que Sammy ya no tiene este globo, cambiaremos la subcadena "has" de la cadena original balloon por "had" en una nueva cadena:

      fmt.Println(strings.ReplaceAll(balloon, "has", "had"))
      

      Dentro de los paréntesis, primero está balloon, la variable que almacena la cadena original; la segunda subcadena "has" es lo que queremos sustituir y la tercera, "had", es la alternativa con la sustituiremos la segunda subcadena. Nuestro resultado tendrá este aspecto cuando lo incorporemos a un programa:

      Output

      Sammy had a balloon.

      Usando la función de la cadena strings.Join, strings.Split y strings.ReplaceAll tendrá un mayor control para manipular cadenas en Go.

      Conclusión

      En este tutorial se repasaron algunas de las funciones más comunes del paquete string para el tipo de datos de cadena que puede usar para manipular y trabajar con cadenas en sus programas de Go.

      Puede obtener más información sobre otros tipos de datos en Información sobre tipos de datos y leer más sobre las cadenas en Introducción al uso de cadenas.



      Source link

      Cómo usar el paquete flag en Go


      Introducción

      Los servicios de línea de comandos rara vez son útiles cuando vienen listos para usar sin configuración adicional. Es importante disponer de buenos valores predeterminados, pero las utilidades prácticas deben aceptar la configuración de parte de los usuarios. En la mayoría de las plataformas, los servicios de línea de comandos aceptan indicadores para personalizar la ejecución del comando. Los parámetros son cadenas delimitadas por el valor de clave agregadas después del nombre del comando. Go le permite crear servicios de línea de comandos que acepten indicadores usando el paquete flag de la biblioteca estándar.

      En este tutorial, explorará varias formas de usar el paquete flag para crear diferentes tipos de utilidades de línea de comandos. Utilizará un indicador para controlar el resultado del programa, introducir argumentos en posición en los que intercambie indicadores y otros datos, y luego implementará subcomandos.

      Cómo usar un indicador para cambiar el comportamiento de un programa

      Al usar el paquete flag se deben seguir tres pasos: primero, definir variables para capturar valores de indicadores, definir los parámetros que utilizará su aplicación de Go y, por último, analizar los parámetros proporcionados a la aplicación al ejecutarse. La mayor parte de las funciones del paquete flag se ocupan de definir los indicadores y vincularlos a las variables que definió. La función Parse() lleva a cabo la fase de análisis.

      Para ilustrar esto, creará un programa que defina un indicador booleano que cambie el mensaje que se imprimirá para un resultado estándar. Si se proporciona un indicador -color, el programa imprimirá un mensaje en azul. Si no se proporciona un indicador, el mensaje se imprimirá sin color.

      Cree un nuevo archivo llamado boolean.go:

      Añada el siguiente código al archivo para crear el programa:

      boolean.go

      package main
      
      import (
          "flag"
          "fmt"
      )
      
      type Color string
      
      const (
          ColorBlack  Color = "u001b[30m"
          ColorRed          = "u001b[31m"
          ColorGreen        = "u001b[32m"
          ColorYellow       = "u001b[33m"
          ColorBlue         = "u001b[34m"
          ColorReset        = "u001b[0m"
      )
      
      func colorize(color Color, message string) {
          fmt.Println(string(color), message, string(ColorReset))
      }
      
      func main() {
          useColor := flag.Bool("color", false, "display colorized output")
          flag.Parse()
      
          if *useColor {
              colorize(ColorBlue, "Hello, DigitalOcean!")
              return
          }
          fmt.Println("Hello, DigitalOcean!")
      }
      

      En este ejemplo, se utilizan secuencias de escape ANSI para dar instrucciones al terminal a fin de que muestre un resultado colorido. Estas son secuencias especializadas de caracteres, por lo que tiene sentido definir un nuevo tipo para ellos. En este ejemplo, asignamos el nombre Color al tipo y lo definimos como una string. Luego, definimos una paleta de colores para usar en el bloque const que sigue. La función colorize definida después del bloque const acepta una de estas constantes Color y una variable string para que el mensaje sea de color. Luego, indica al terminal que cambie de color imprimiendo primero la secuencia de escape para el color solicitado, luego imprime el mensaje y finalmente solicita que el terminal restablezca su color imprimiendo la secuencia especial de restablecimiento de color.

      En main, usamos la función flag.Bool paradefinirun indicador booleano llamado color. El segundo parámetro de esta función, false, establece el valor predeterminado para este indicador cuando no se proporciona. En contra de las expectativas que pueda tener, fijar esto en true no invierte el comportamiento de modo tal que la incorporación de un indicador haga que se convierta en falso. Por lo tanto, el valor de este parámetro es casi siempre false con indicadores de booleano.

      El parámetro final es una cadena de documentación que puede imprimirse como mensaje de uso. El valor devuelto de esta función es un puntero de un bool. La función flag.Parse en la siguiente línea utiliza este puntero para configurar la variable bool en función de los indicadores pasados por el usuario. Luego, podemos verificar el valor de este puntero bool eliminado su referencia. Se puede encontrar más información sobre las variables de punteros en el tutorial sobre punteros. Mediante este valor booleano, podemos invocar colorize cuando esté configurado el puntero -color e invocar la variable fmt.Println cuando no se encuentre el indicador.

      Guarde el archivo y ejecute el programa sin indicadores:

      Verá el siguiente resultado:

      Output

      Hello, DigitalOcean!

      Ahora, ejecute este programa de nuevo con el indicador color:

      El resultado será el mismo texto, pero esta vez en color azul.

      Los indicadores no son los únicos valores pasados a comandos. Es posible que también envíe nombres de archivo u otros datos.

      Trabajar con argumentos posicionales

      Normalmente, los comandos toman una serie de argumentos que actúan como sujeto del foco del comando. Por ejemplo, el comando head, que imprime las primeras líneas de un archivo, a menudo se invoca como head example.txt. El archivo example.txt es un argumento posicional en la invocación del comando head.

      La función Parse() continuará analizando los indicadores que encuentre hasta detectar un argumento sin indicador. El paquete flag los pone a disposición a través de las funciones Args () y Arg ().

      Para ilustrar esto, compilará una nueva implementación simplificada del comando head, que muestra las primeras líneas de un archivo dado:

      Cree un nuevo archivo llamado head.go y agregue el siguiente código:

      head.go

      package main
      
      import (
          "bufio"
          "flag"
          "fmt"
          "io"
          "os"
      )
      
      func main() {
          var count int
          flag.IntVar(&count, "n", 5, "number of lines to read from the file")
          flag.Parse()
      
          var in io.Reader
          if filename := flag.Arg(0); filename != "" {
              f, err := os.Open(filename)
              if err != nil {
                  fmt.Println("error opening file: err:", err)
                  os.Exit(1)
              }
              defer f.Close()
      
              in = f
          } else {
              in = os.Stdin
          }
      
          buf := bufio.NewScanner(in)
      
          for i := 0; i < count; i++ {
              if !buf.Scan() {
                  break
              }
              fmt.Println(buf.Text())
          }
      
          if err := buf.Err(); err != nil {
              fmt.Fprintln(os.Stderr, "error reading: err:", err)
          }
      }
      

      Primero, definimos una variable count para contener el número de líneas que el programa debería leer del archivo. Luego definimos el indicador -n usando flag.IntVar, para reflejar el comportamiento del programa head original. Esta función nos permite pasar nuestro propio puntero a una variable en contraste con las funciones flag que no tienen el sufijo Var. Además de esta diferencia, el resto de los parámetros de flag.IntVar siguen a su homólogo flag.Int: el nombre del indicador, un valor predeterminado y una descripción. Como en el ejemplo anterior, invocamos a flag.Parse () para procesar la entrada del usuario.

      La siguiente sección lee el archivo. Primero definimos una variable io.Reader que se establecerá en el archivo solicitado por el usuario o la entrada estándar pasada al programa. Dentro de la instrucción if, usamos la función flag.Arg para acceder al primer argumento posicional después de todos los indicadores. Si el usuario proporcionó un nombre de archivo, se establecerá. De lo contrario, será la cadena vacía (""). Cuando hay un nombre de archivo presente, usamos la función os.Open para abrir ese archivo y configurar el io.Reader que definimos antes para él. De lo contrario, usamos os.Stdin para la lectura desde entrada estándares.

      En la sección final se utiliza un * bufio.Scanner creado con bufio.NewScanner para leer líneas de la variable in de io.Reader. Realizamos iteraciones hasta el valor de count utilizando un bucle for, invocando break si del análisis de la línea con buf.Scan surge un valor false, lo cual indica que el número de líneas es menor que el número solicitado por el usuario.

      Ejecute este programa y muestre el contenido del archivo que acaba de escribir usando head.go como argumento del archivo:

      • go run head.go -- head.go

      El separador -- es un indicador especial reconocido por el paquete flag que señala que no hay más argumentos de indicador a continuación. Cuando ejecute este comando, verá el siguiente resultado:

      Output

      package main import ( "bufio" "flag"

      Utilice el indicador -n que definió para ajustar la cantidad de resultado:

      • go run head.go -n 1 head.go

      Como resultado solo se muestra la instrucción del paquete:

      Output

      package main

      Por último, cuando el programa detecta que no se proporcionaron argumentos posicionales, lee la entrada estándar como en el caso de head. Intente ejecutar este comando:

      • echo "fishnlobstersnsharksnminnows" | go run head.go -n 3

      Verá el resultado:

      Output

      fish lobsters sharks

      El comportamiento de las funciones flag que vio hasta ahora se limitó a examinar toda la invocación del comando. No siempre le convendrá este comportamiento, sobre todo si escribe una herramienta de línea de comandos que admite subcomandos.

      Usar FlagSet para implementar subcomandos

      Las aplicaciones de línea de comandos modernas a menudo implementan “subcomandos” para empaquetar una serie de herramientas bajo un único comando. La herramienta más conocida que utiliza este patrón es git. Si se examina un comando como git init, git es el comando e init es el subcomando de git. Una característica notable de los subcomandos es que cada uno puede tener su propio conjunto de indicadores.

      Las aplicaciones de Go pueden admitir subcomandos con su propio conjunto de indicadores usando el tipo flag.( *FlagSet). Para ilustrar esto, cree un programa que ejecute un comando usando dos subcomandos con diferentes indicadores.

      Cree un nuevo archivo llamado subcommand.go y agregue a este el siguiente contenido:

      package main
      
      import (
          "errors"
          "flag"
          "fmt"
          "os"
      )
      
      func NewGreetCommand() *GreetCommand {
          gc := &GreetCommand{
              fs: flag.NewFlagSet("greet", flag.ContinueOnError),
          }
      
          gc.fs.StringVar(&gc.name, "name", "World", "name of the person to be greeted")
      
          return gc
      }
      
      type GreetCommand struct {
          fs *flag.FlagSet
      
          name string
      }
      
      func (g *GreetCommand) Name() string {
          return g.fs.Name()
      }
      
      func (g *GreetCommand) Init(args []string) error {
          return g.fs.Parse(args)
      }
      
      func (g *GreetCommand) Run() error {
          fmt.Println("Hello", g.name, "!")
          return nil
      }
      
      type Runner interface {
          Init([]string) error
          Run() error
          Name() string
      }
      
      func root(args []string) error {
          if len(args) < 1 {
              return errors.New("You must pass a sub-command")
          }
      
          cmds := []Runner{
              NewGreetCommand(),
          }
      
          subcommand := os.Args[1]
      
          for _, cmd := range cmds {
              if cmd.Name() == subcommand {
                  cmd.Init(os.Args[2:])
                  return cmd.Run()
              }
          }
      
          return fmt.Errorf("Unknown subcommand: %s", subcommand)
      }
      
      func main() {
          if err := root(os.Args[1:]); err != nil {
              fmt.Println(err)
              os.Exit(1)
          }
      }
      

      Este programa se divide en algunas partes: la función main, la función root y las funciones individuales para implementar el subcomando. La función main maneja los errores que muestran los comandos. Si alguna función muestra un error, la instrucción if lo detectará y lo imprimirá, y el programa se cerrará con un código de estado 1, lo cual indica que se produjo un error en el resto del sistema operativo. Dentro de main, pasamos todos los argumentos con los que se invocó el programa a root. Eliminamos el primer argumento, que es el nombre del programa (en los ejemplos anteriores, ./subcommand) cortando os.Args primero.

      La función root define [] Runner, donde se definirían todos los subcomandos. Runner es una interfaz para subcomandos que permite a root recuperar el nombre del subcomando usando Name () y compararlo con la variable subcommand de contenido. Una vez que se encuentre el subcomando correcto después de la iteración de la variable cmds, inicializamos el subcomando con el resto de los argumentos e invocamos el método Run() de ese comando.

      Solo definimos un subcomando, aunque este marco nos permitiría crear fácilmente otros. Se crean instancias de GreetCommand usando NewGreetCommand donde creamos un nuevo *flag.FlagSet usando flag.NewFlagSet. flag.NewFlagSet toma dos argumentos: un nombre para el conjunto de indicadores y una estrategia para informar errores de análisis. Es posible acceder al nombre de *flag.FlagSet con el método flag.( *FlagSet. Name. Lo usamos en (*GreetCommand). El método Name() para que el nombre del subcomando coincida con el nombre que asignamos a *flag.FlagSet. NewGreetCommand también define un indicador -name de una manera similar a la de los ejemplos anteriores, pero como alternativa lo invoca como un método fuera del campo *flag.FlagSet del *GreetCommand, gc.fs. Cuando root invoca al método Init () del * GreetCommand, pasamos los argumentos proporcionados al método Parse del campo *flag.FlagSet.

      Será más sencillo ver subcomandos si compila este programa y lo ejecuta. Compile el programa:

      Ahora, ejecute el programa sin argumentos:

      Verá este resultado:

      Output

      You must pass a sub-command

      Ahora, ejecute el programa con el subcomando greet:

      Esto produce el siguiente resultado:

      Output

      Hello World !

      Ahora, utilice el indicador -name con greet para especificar un nombre:

      • ./subcommand greet -name Sammy

      Verá este resultado del programa:

      Output

      Hello Sammy !

      Este ejemplo permite ver algunos principios relacionados con la estructura que podrían tener las aplicaciones de línea de comandos más grandes en Go. Los FlagSets están diseñados para dar a los desarrolladores más control respecto de dónde y cómo lógica de análisis de indicadores los procesa.

      Conclusión

      Los indicadores hacen que sus aplicaciones sean más útiles en más contextos porque dan a sus usuarios control respecto de cómo se ejecutan los programas. Es importante proporcionar a los usuarios valores predeterminados útiles, pero debería darles la oportunidad de anular ajustes que no funcionen en sus casos. Pudo observar que el paquete flag ofrece alternativas flexibles para presentar opciones de configuración a sus usuarios. Puede elegir algunos indicadores sencillos o crear una serie de subcomandos extensible. En cualquiera de los casos, usar el paquete flag le permitirá crear utilidades siguiendo el estilo de la larga historia de herramientas de línea de comandos flexibles y programables.

      Para obtener más información sobre el lenguaje de programación de Go, consulte nuestra serie Cómo realizar codificaciones en Go.



      Source link