One place for hosting & domains

      sistemas

      Cómo usar el módulo pathlib para manipular las rutas de sistemas de archivos en Python 3


      El autor seleccionó el COVID-19 Relief Fund para que reciba una donación como parte del programa Write for DOnations.

      Introducción

      Python 3 incluye el módulo pathlib para manipular rutas de sistemas de archivos de forma agnóstica en cualquier sistema operativo. El módulo pathlib es similar al os.path, pero pathlib ofrece una interfaz de nivel más alto, y, a menudo, más conveniente, que os.path.

      Podemos identificar archivos en una computadora con rutas jerárquicas. Por ejemplo, podemos identificar el archivo wave.txt en una computadora con esta ruta: /Users/sammy/ocean/wave.txt. Cada sistema operativo tiene una manera ligeramente distinta de representar rutas. Windows puede representar la ruta al archivo wave.txt de la siguiente manera: C:Userssammyoceanwave.txt.

      El módulo pathlib le puede resultar útil si desea a crear o mover archivos en el sistema de archivos de su programa de Python, enumerar los archivos del sistema de archivos que coincidan con una extensión o un patrón determinado o crear rutas de archivos apropiadas para el sistema operativo basadas en colecciones de cadenas sin procesar. Si bien es posible usar otras herramientas (como el módulo os.path) para realizar muchas de estas tareas, el módulo pathlib le permite realizar estas operaciones con un alto grado de legibilidad y una cantidad de código mínima.

      En este tutorial, revisaremos algunas de las maneras de usar el módulo pathlib para representar y manipular las rutas de los sistemas de archivos.

      Requisitos previos

      Para sacar el máximo provecho de este tutorial, se recomienda tener cierta familiaridad con la programación en Python 3. Puede consultar estos tutoriales para obtener la información de fondo necesaria:

      Cómo crear instancias Path

      El módulo pathlib proporciona varias clases, pero una de las más importantes es la clase Path. Las instancias de la clase Path representan una ruta a un archivo o un directorio en el sistema de archivos de nuestra computadora.

      Por ejemplo, el siguiente código inicia una instancia Path que representa una parte de la ruta a un archivo wave.txt:

      from pathlib import Path
      
      wave = Path("ocean", "wave.txt")
      print(wave)
      

      Si ejecutamos este código, obtendremos un resultado como el siguiente:

      Output

      ocean/wave.txt

      from pathlib import Path permite que la clase Path esté disponible en nuestro programa. Luego, Path("ocean", "wave.txt") crea una instancia de Path nueva. El resultado muestra que Python ha añadido el separador / adecuado del sistema operativo entre los dos componentes de la ruta que le proporcionamos: "ocean" y "wave.txt".

      Nota: Sus resultados pueden diferir ligeramente de los que se muestran como ejemplo en este tutorial en función del sistema operativo que utilice. Si utiliza Windows, por ejemplo, su resultado para este primer ejemplo puede tener este aspecto: oceanwave.txt.

      Actualmente, el objeto Path asignado a la variable wave contiene una ruta relativa. En otras palabras, ocean/wave.txt puede existir en varias ubicaciones de nuestro sistema de archivos. Por ejemplo, puede estar presente en /Users/user_1/ocean/wave.txt o /Users/user_2/research/ocean/wave.txt, pero no especificamos exactamente a cuál nos estamos refiriendo. Por el contrario, una ruta absoluta se refiere inequívocamente a una ubicación en el sistema de archivos.

      Puede usar Path.home() para obtener la ruta absoluta al directorio principal del usuario actual:

      home = Path.home()
      wave_absolute = Path(home, "ocean", "wave.txt")
      print(home)
      print(wave_absolute)
      

      Si ejecutamos este código, obtendremos un resultado similar al siguiente:

      Output

      /Users/sammy /Users/sammy/ocean/wave.txt

      Nota: Como se mencionó anteriormente, su resultado variará dependiendo de su sistema operativo. Por supuesto, su directorio principal también será distinto de /Users/sammy.

      Path.home() devuelve una instancia Path con una ruta absoluta al directorio principal del usuario actual. Luego, pasamos esta instancia de Path y las cadenas "ocean" y "wave.txt" a otro constructor de Path para crear una ruta absoluta al archivo wave.txt. El resultado indica que la primera línea es el directorio principal y la segunda, el directorio principal más ocean/wave.txt.

      Este ejemplo también ilustra una característica importante de la clase Path: el constructor Path acepta tanto cadenas como objetos preexistentes de Path.

      Analicemos con mayor detalle cómo es que el constructor Path admite tanto cadenas como de objetos de Path:

      shark = Path(Path.home(), "ocean", "animals", Path("fish", "shark.txt"))
      print(shark)
      

      Si ejecutamos este código de Python, obtendremos un resultado similar al siguiente:

      Output

      /Users/sammy/ocean/animals/fish/shark.txt

      shark es un Path a un archivo que construimos usando tanto objetos Path (Path.home() y Path("fish", "shark.txt")) como cadenas ("ocean" y "animals"). El constructor Path gestiona de forma inteligente ambos tipos de objetos y los une de forma correcta usando el separador correspondiente del sistema operativo, en este caso: /.

      Acceder a los atributos de los archivos

      Ahora que hemos aprendido a crear instancias de Path, vamos a repasar cómo puede usar esas instancias para acceder a información sobre un archivo.

      Podemos usar los atributos name y suffix para acceder a los nombres y los sufijos de archivos:

      wave = Path("ocean", "wave.txt")
      print(wave)
      print(wave.name)
      print(wave.suffix)
      

      Al ejecutar este código, obtendremos un resultado similar al siguiente:

      Output

      /Users/sammy/ocean/wave.txt wave.txt .txt

      Este resultado indica que el nombre del archivo al final de nuestra ruta es wave.txt y el sufijo de ese archivo es .txt.

      Las instancias de Path también ofrecen la función with_name, que le permite crear de forma sencilla un objeto Path nuevo con un nombre distinto:

      wave = Path("ocean", "wave.txt")
      tides = wave.with_name("tides.txt")
      print(wave)
      print(tides)
      

      Si ejecutamos este código, obtendremos un resultado similar al siguiente:

      ocean/wave.txt
      ocean/tides.txt
      

      El código, primero, construye una instancia Path que apunta a un archivo llamado wave.txt. Luego, invoca el método with_name en wave para devolver una segunda instancia Path que apunta a un archivo nuevo denominado tides.txt. La parte del directorio ocean/ de la ruta permanece intacta, por lo tanto, la ruta final queda establecida como ocean/tides.txt

      Acceder a antecesores

      A veces, resulta útil acceder a directorios que contienen una ruta determinada. Consideremos un ejemplo:

      shark = Path("ocean", "animals", "fish", "shark.txt")
      print(shark)
      print(shark.parent)
      

      Si ejecutamos este código, obtendremos un resultado similar al siguiente:

      Output

      ocean/animals/fish/shark.txt ocean/animals/fish

      El atributo parent en una instancia de Path devuelve el antecesor más inmediato de una ruta de archivos determinada. En este caso, devuelve el directorio que contiene el archivo shark.txt: ocean/animals/fish.

      Podemos acceder al atributo parent varias veces seguidas para recorrer el árbol de ancestros de un archivo determinado:

      shark = Path("ocean", "animals", "fish", "shark.txt")
      print(shark)
      print(shark.parent.parent)
      

      Si ejecutamos este código, obtendremos el siguiente resultado:

      Output

      ocean/animals/fish/shark.txt ocean/animals

      El resultado es similar al anterior, pero, ahora, hemos llegado a un nivel más alto al acceder a .parent por segunda vez. El directorio ocean/animals se encuentra dos directorios por encima de shark.txt.

      Usar Glob para enumerar archivos

      También es posible usar la clase Path para enumerar archivos usando el método glob.

      Imaginemos que tenemos una estructura de directorios similar a la siguiente:

      └── ocean
          ├── animals
          │   └── fish
          │       └── shark.txt
          ├── tides.txt
          └── wave.txt
      

      Un directorio ocean que contiene los archivos tides.txt y wave.txt. Tenemos un archivo denominado shark.txt anidado en el directorio ocean, un directorio animals y otro fish: ocean/animals/fish.

      Para enumerar todos los archivos .txt del directorio ocean, podríamos escribir lo siguiente:

      for txt_path in Path("ocean").glob("*.txt"):
          print(txt_path)
      

      Este código tendría un resultado similar al siguiente:

      Output

      ocean/wave.txt ocean/tides.txt

      El patrón glob __"*.txt" busca todos los archivos que terminan en .txt. Como el código del ejemplo ejecuta ese glob en el directorio ocean, devuelve los dos archivos .txt del directorio ocean: wave.txt y tides.txt.

      Nota: Para duplicar los resultados que se muestran en este ejemplo, copie la estructura de directorios que se ilustra aquí en su computadora.

      También podemos usar el método glob de manera recursiva. Para enumerar todos los archivos .txt del directorio ocean y todos sus subdirectorios, podemos escribir lo siguiente:

      for txt_path in Path("ocean").glob("**/*.txt"):
          print(txt_path)
      

      Al ejecutar este código, obtendríamos un resultado similar al siguiente:

      Output

      ocean/wave.txt ocean/tides.txt ocean/animals/fish/shark.txt

      La sección ** del patrón glob coincidirá con este directorio y todos sus subdirectorios de manera recursiva. Por tanto, no solo tenemos los archivos wave.txt y tides.txt en el resultado, sino que también recibimos el archivo shark.txt que estaba anidado en ocean/animals/fish.

      Calcular rutas relativas

      Podemos usar el método Path.relative_to para calcular rutas relacionadas entre sí. El método relative_to es útil cuando, por ejemplo, se desea recuperar una porción de una ruta de archivos larga.

      Analice el siguiente código:

      shark = Path("ocean", "animals", "fish", "shark.txt")
      below_ocean = shark.relative_to(Path("ocean"))
      below_animals = shark.relative_to(Path("ocean", "animals"))
      print(shark)
      print(below_ocean)
      print(below_animals)
      

      Si ejecutamos este código, obtendremos un resultado similar al siguiente:

      Output

      ocean/animals/fish/shark.txt animals/fish/shark.txt fish/shark.txt

      El método relative_to devuelve un nuevo objeto Path relacionado con el argumento determinado. En nuestro ejemplo, calculamos el Path a shark.txt en relación con el directorio ocean y, luego, en relación con los directorios ocean y animals.

      Si relative_to no puede calcular una respuesta porque le indicamos una ruta no relacionada, presenta un ValueError:

      shark = Path("ocean", "animals", "fish", "shark.txt")
      shark.relative_to(Path("unrelated", "path"))
      

      Obtendremos una excepción ValueError generada a partir de este código que será similar a la siguiente:

      Output

      Traceback (most recent call last): File "<stdin>", line 1, in <module> File "/usr/local/lib/Python3.8/pathlib.py", line 899, in relative_to raise ValueError("{!r} does not start with {!r}" ValueError: 'ocean/animals/fish/shark.txt' does not start with 'unrelated/path'

      unrelated/path no forma parte de ocean/animals/fish/shark.txt, por lo tanto, Python no puede calcular una ruta relativa.

      Conclusión

      El módulo pathlib es un componente importante de la biblioteca estándar de Python que nos permite manipular rutas de sistemas de archivos de forma rápida en cualquier sistema operativo. En este tutorial, ha aprendido a usar algunas de las herramientas clave de pathlib para acceder a los atributos de archivos, enumerar archivos con patrones glob y desplazarse por archivos y directorios principales.

      El módulo pathlib expone clases y utilidades adicionales que no abarcamos en este tutorial. Ahora que tiene una referencia, puede usar la documentación del módulo pathlib para obtener más información sobre otras clases y utilidades disponibles.

      Si está interesado en utilizar otras bibliotecas de Python, consulte los siguientes tutoriales:



      Source link

      Compilando aplicativos em Go para diferentes Sistemas Operacionais e Arquiteturas


      No desenvolvimento de software, é importante considerar o sistema operacional e a arquitetura do processador subjacente para os quais você quer compilar seu binário. Como geralmente é lento ou impossível executar um binário em uma plataforma de SO/arquitetura, é uma prática comum compilar o seu binário final para muitas plataformas diferentes a fim de maximizar o público do seu programa. No entanto, isso pode ser difícil quando a plataforma que estiver usando para o desenvolvimento for diferente da plataforma na qual deseja implantar o seu programa. No passado, por exemplo, o desenvolvimento de um programa em Windows e a implantação em uma máquina Linux ou macOS envolveria a configuração de máquinas montadas para cada um dos ambientes para os quais quisesse binários. Você também precisaria manter suas ferramentas em sincronia, além de outras considerações que adicionariam custos e dificultariam a realização de testes e a distribuição.

      A linguagem Go resolve esse problema, criando o suporte para várias plataformas diretamente na ferramenta go build, assim como em todo o resto da cadeia de ferramentas do Go. Ao usar variáveis de ambiente e build tags (sinalizadores de compilação), você consegue controlar para qual SO e arquitetura o seu binário final será compilado, além de unir um fluxo de trabalho que pode alternar rapidamente a inclusão do código dependente de plataforma sem alterar sua base de códigos.

      Neste tutorial, você irá juntar um aplicativo exemplo que une strings a partir de um filepath, criar e incluir seletivamente snippets dependentes de plataforma e compilar binários para vários sistemas operacionais e arquiteturas de sistema em seu próprio sistema, mostrando a você como usar essa poderosa capacidade da linguagem de programação Go.

      Pré-requisitos

      Para seguir o exemplo neste artigo, será necessário:

      Possíveis plataformas para o GOOS e GOARCH

      Antes de mostrar como controlar o processo de compilação para compilar os binários para plataformas diferentes, vamos inspecionar primeiro para quais tipos de plataformas a linguagem Go consegue compilar e de que maneira a Go referencia tais plataformas utilizando as variáveis de ambiente GOOS e GOARCH.

      As ferramentas da Go têm um comando que pode imprimir uma lista das possíveis plataformas nais quais a Go consegue compilar. Essa lista pode mudar com cada nova versão da Go. Assim, as combinações discutidas aqui podem não ser as mesmas em outra versão da linguagem Go. No momento em que este tutorial é escrito, a versão da Go é a 1.13.

      Para encontrar essa lista com as possíveis plataformas, execute o seguinte:

      Você receberá um resultado similar ao seguinte:

      Output

      aix/ppc64 freebsd/amd64 linux/mipsle openbsd/386 android/386 freebsd/arm linux/ppc64 openbsd/amd64 android/amd64 illumos/amd64 linux/ppc64le openbsd/arm android/arm js/wasm linux/s390x openbsd/arm64 android/arm64 linux/386 nacl/386 plan9/386 darwin/386 linux/amd64 nacl/amd64p32 plan9/amd64 darwin/amd64 linux/arm nacl/arm plan9/arm darwin/arm linux/arm64 netbsd/386 solaris/amd64 darwin/arm64 linux/mips netbsd/amd64 windows/386 dragonfly/amd64 linux/mips64 netbsd/arm windows/amd64 freebsd/386 linux/mips64le netbsd/arm64 windows/arm

      Esse resultado é um conjunto de pares de chave-valor, por uma /. A primeira parte da combinação, antes da /, é o sistema operacional. Em Go, esses sistemas operacionais são valores possíveis para a variável de ambiente GOOS, pronuncia-se “goose”, que significa Go Operating System (Sistema Operacional Go). A segunda parte, após a /, é a arquitetura . Como antes, todos esses valores são possíveis para uma variável de ambiente: GOARCH. A pronúncia dessa variável é “gore-ch”, e significa Go Architecture (Arquitetura Go).

      Vamos detalhar uma dessas combinações para entender o que ela significa e como ela funciona, usando o linux/386 como exemplo. O par chave-valor começa com a variável GOOS, que, neste exemplo, seria o linux, referindo-se ao SO do Linux. Aqui, a GOARCH seria o 386, que significa microprocessador Intel 80386.

      Existem muitas plataformas disponíveis com o comando go build, mas na maior parte das vezes você vai acabar usando linux, windows ou darwin como um valor para o GOOS. Dentre elas, temos as três grandes plataformas de OS, quais sejam: Linux, Windows e macOS, o qual é baseado no sistema operacional Darwin e, por isso, é chamado de darwin. No entanto, o Go também pode incluir plataformas menos comuns, como a nacl, que representa o Cliente nativo do Google.

      Quando você executa um comando como o go build, o Go usa a plataforma atual do GOOS e da GOARCH para determinar como compilar o binário. Para descobrir a qual combinação sua plataforma corresponde, utilize o comando go env e passe o GOOS e a GOARCH como argumentos:

      Ao testar esse exemplo, executamos este comando no macOS de uma máquina com uma arquitetura AMD64. Dessa forma, iremos receber o seguinte resultado:

      Output

      darwin amd64

      Aqui, o resultado do comando nos diz que nosso sistema tem o GOOS=darwin e o GOARCH=amd64.

      Agora, você sabe qual deles é o GOOS e qual é o GOARCH no Go, bem como seus possíveis valores. Em seguida, você precisará de um programa para usar como exemplo de como usar essas variáveis de ambiente e os build tags para compilar binários em outras plataformas.

      Antes de começar a compilar binários para outras plataformas, vamos criar um programa de exemplo. Uma boa amostra para este propósito é a função Join no pacote path/filepath na biblioteca Go padrão. Essa função pega uma quantidade de strings e retorna uma string que é unida ao separador de caminho de arquivo correto.

      Este é um bom programa de exemplo porque a operação do programa depende do SO em que ele estiver executando. No Windows, o separador de caminho é uma barra invertida, , enquanto os sistemas baseados em Unix usam uma barra, /.

      Vamos começar a compilar um aplicativo que utilize o filepath.Join() e, mais tarde, você vai escrever sua própria implementação da função do Join() - que personaliza o código para os binários específicos de plataforma.

      Primeiro, crie uma pasta no seu diretório src com o nome do seu app:

      Acesse aquele diretório:

      Em seguida, crie um novo arquivo no seu editor de texto preferido chamado main.go. Para este tutorial, usaremos o Nano:

      Assim que o arquivo estiver aberto, adicione o seguinte código:

      src/app/main.go

      package main
      
      import (
        "fmt"
        "path/filepath"
      )
      
      func main() {
        s := filepath.Join("a", "b", "c")
        fmt.Println(s)
      }
      

      A função main() neste arquivo usa o filepath.Join() para concatenar três strings com o separador de caminho correto, dependente de plataforma.

      Salve e saia do arquivo e, em seguida, execute o programa:

      Ao executar esse programa, você receberá um resultado diferente, dependendo da plataforma que estiver usando. No Windows, você verá as strings separadas pela :

      Output

      abc

      Nos sistemas da Unix, como macOS e Linux, você receberá o seguinte:

      Output

      a/b/c

      Isso mostra que, devido aos diferentes protocolos de sistema de arquivos usados nesses sistemas operacionais, o programa terá que compilar um código diferente para as diferentes plataformas. Porém, uma vez que o programa já utiliza um separador de arquivos diferente de acordo com o SO, sabemos que o filepath.Join() já responde pela diferença na plataforma. Isso acontece porque a cadeia de ferramentas do Go detecta automaticamente o GOOS e a GOARCH da sua máquina e recorre dessa informação para usar o snippet do código com os build tags e o separador de arquivo corretos.

      Vamos considerar de onde a função filepath.Join() obtém o seu separador. Execute o comando a seguir para inspecionar o snippet relevante da biblioteca padrão do Go:

      • less /usr/local/go/src/os/path_unix.go

      Isso exibirá o conteúdo do path_unix.go. Procure pela seguinte parte do arquivo:

      /usr/local/go/os/path_unix.go

      . . .
      // +build aix darwin dragonfly freebsd js,wasm linux nacl netbsd openbsd solaris
      
      package os
      
      const (
        PathSeparator     = '/' // OS-specific path separator
        PathListSeparator = ':' // OS-specific path list separator
      )
      . . .
      

      Esta seção define o PathSeparator de todas as variedades de sistemas do tipo Unix compatíveis com o Go. Observe todos os build tags na parte superior - cada qual representando uma das possíveis plataformas GOOS associadas ao Unix. Quando o GOOS corresponder a esses termos, seu programa produzirá o separador de caminho de arquivo com estilo Unix.

      Pressione q para retornar à linha de comando.

      Em seguida, abra o arquivo que define o comportamento do filepath.Join() quando usado em Windows:

      • less /usr/local/go/src/os/path_windows.go

      Você verá o seguinte:

      /usr/local/go/os/path_unix.go

      . . .
      package os
      
      const (
              PathSeparator     = '\' // OS-specific path separator
              PathListSeparator = ';'  // OS-specific path list separator
      )
      . . .
      

      Embora o valor do PathSeparator seja \ aqui, o código irá renderizar somente uma única barra invertida () - necessária para os caminhos de arquivos do Windows, uma vez que a primeira barra invertida só é necessária como um caractere de escape.

      Note que, ao contrário do arquivo Unix, não há build tags na parte superior. Isso acontece porque o GOOS e a GOARCH também podem ser transmitidos para o go build, adicionando-se um sublinhado (_) e o valor da variável de ambiente como um sufixo do nome do arquivo. Nós vamos nos aprofundar sobre esse ponto na seção Usando sufixos de nome de arquivo no GOOS e na GOARCH. Aqui, a parte _windows do path_windows.go faz o arquivo agir como se ele tivesse o build tag // + build windows no parte superior do arquivo. Por causa disso, quando seu programa for executado em Windows, ele usará as constantes do PathSeparator e do PathListSeparator do snippet de código path_windows.go.

      Para retornar à linha de comando, saia do less pressionando q.

      Neste passo, você compilou um programa que mostrou como a linguagem Go converte o GOOS e a GOARCH automaticamente em build tags. Com isso em mente, você já pode atualizar o seu programa e escrever sua própria implementação do filepath.Join(), usando build tags para definir manualmente o PathSeparator correto para as plataformas Windows e Unix.

      Implementando uma função específica da Plataforma

      Agora que sabe como a biblioteca padrão do Go implementa o código específico da plataforma, você pode usar os build tags para fazer isso em seu próprio programa app. Para fazer isso, você irá escrever sua própria implementação do filepath.Join().

      Abra seu arquivo main.go:

      Substitua o conteúdo do main.go pelo seguinte, usando sua própria função chamada Join():

      src/app/main.go

      package main
      
      import (
        "fmt"
        "strings"
      )
      
      func Join(parts ...string) string {
        return strings.Join(parts, PathSeparator)
      }
      
      func main() {
        s := Join("a", "b", "c")
        fmt.Println(s)
      }
      

      A função Join pega um número de parts e as une usando o método strings.Join() do pacote strings para concatenar as parts usando o PathSeparator.

      Você ainda não definiu o PathSeparator. Assim, faça isso agora, em outro arquivo. Salve e saia do main.go, abra seu editor favorito e crie um novo arquivo chamado path.go:

      nano path.go
      

      Defina o PathSeparator e o configure como o separador de caminho de arquivo do Unix, /:

      src/app/path.go

      package main
      
      const PathSeparator = "/"
      

      Compile e execute o aplicativo:

      Você receberá o seguinte resultado:

      Output

      a/b/c

      Isso executa com sucesso a fim de obter o caminho de arquivo com estilo Unix. Mas isso ainda não é o que queremos: o resultado é sempre a/b/c, a despeito da plataforma na qual ele execute. Para adicionar na funcionalidade para criar os caminhos de arquivo com estilo Windows, você precisará adicionar uma versão do Windows do PathSeparator e dizer ao comando go build qual versão usar. Na próxima seção, você usará os build tags para realizar isso.

      Para considerar as plataformas Windows, agora você irá criar um arquivo alternativo para o path.go e usará build tags para garantir que os snippets de código somente executem quando o GOOS e a GOARCH forem a plataforma apropriada.

      Primeiro, porém, adicione o build tag ao path.go para dizer a ele que compile para tudo, exceto para o Windows. Abra o arquivo:

      Adicione o build tag - destacado a seguir, ao arquivo:

      src/app/path.go

      // +build !windows
      
      package main
      
      const PathSeparator = "/"
      

      Os build tags em Go permitem a inversão, ou seja, você pode instruir o Go a compilar esse arquivo para qualquer plataforma, exceto para o Windows. Para inverter um build tag, coloque um ! antes do tag.

      Salve e saia do arquivo.

      Agora, se você executasse esse programa no Windows, você receberia o seguinte erro:

      Output

      ./main.go:9:29: undefined: PathSeparator

      Neste caso, o Go não conseguiria incluir o path.go para definir o PathSeparator da variável.

      Agora que você garantiu que o path.go não irá executar quando o GOOS for o Windows, adicione um novo arquivo, o windows.go:

      No windows.go, defina o PathSeparator do Windows, bem como um build tag deixar que o comando go build saiba que se trata de uma implementação do Windows:

      src/app/windows.go

      // +build windows
      
      package main
      
      const PathSeparator = "\"
      

      Salve o arquivo e saia do editor de texto. O aplicativo agora pode compilar uma caminho para o Windows e outro para todas as outras plataformas.

      Ao mesmo tempo que os binários agora irão compilar corretamente para suas plataformas, existem mais alterações que você deverá fazer para compilar para uma plataforma à qual você não tenha acesso. Para fazer isso, no próximo passo você irá alterar duas suas variáveis de ambiente GOOS e GOARCH.

      Usando suas variáveis de ambiente locais GOOS e GOARCH

      Anteriormente, você executou o comando go env GOOS GOARCH para descobrir em qual SO e qual arquitetura estava trabalhando. Quando você executou o comando go env, ele procurou as duas variáveis de ambiente, GOOS e GOARCH; se ele as encontrasse, seus valores seriam usados, caso contrário, o Go as definiria com as informações da plataforma atual. Isso significa que você pode alterar o GOOS e a GOARCH para que eles não assumam sua SO e arquitetura locais como padrão.

      O comando go build se comporta de maneira similar ao comando go env. Você pode definir as variáveis de ambiente GOOS ou GOARCH para compilar uma plataforma diferente usando o go build.

      Se não estiver usando um sistema Windows, compile um binário windows do app, definindo a variável de ambiente GOOS para windows ao executar o comando go build:

      Agora, liste os arquivos no seu diretório atual:

      O resultado da ação de listar o diretório mostra que agora existe um arquivo executável do Windows, app.exe no diretório do projeto:

      Output

      app app.exe main.go path.go windows.go

      Usando o comando file, você pode obter mais informações sobre esse arquivo, confirmando sua compilação:

      Você receberá:

      Output

      app.exe: PE32+ executable (console) x86-64 (stripped to external PDB), for MS Windows

      Também é possível definir uma, ou ambas as variáveis de ambiente no momento da compilação. Execute o seguinte:

      • GOOS=linux GOARCH=ppc64 go build

      Seu executável app será substituído por um arquivo feito de uma arquitetura diferente. Execute o comando file neste binário:

      Você receberá um resultado como o seguinte:

      app: ELF 64-bit MSB executable, 64-bit PowerPC or cisco 7500, version 1 (SYSV), statically linked, not stripped
      

      Definindo suas variáveis de ambiente local GOOS e GOARCH, agora você poderá compilar binários para qualquer uma das plataformas compatíveis do Go, sem precisar de uma configuração ou preparação complicada. Em seguida, você usará as convenções de nome do arquivo para manter seus arquivos totalmente organizados e compilar em plataformas específicas - automaticamente, sem build tags.

      Usando os sufixos de nome do arquivo para GOOS e GOARCH

      Como você viu anteriormente, a biblioteca Go padrão faz intenso uso dos build tags para simplificar o código, separando as implementações de plataforma diferentes em arquivos diferentes. Quando você abriu o arquivo os/path_unix.go havia um build tag que listava todas as combinações possíveis que são consideradas plataformas do tipo Unix. No entanto, o arquivo os/path_windows.go não continha build tags, uma vez que o sufixo no nome do arquivo era o suficiente para dizer ao Go a qual plataforma o arquivo se destinava.

      Vejamos a sintaxe desse recurso. Ao nomear um arquivo .go, você pode adicionar o GOOS e a GOARCH como sufixos do nome do arquivo naquela ordem, separando os valores por sublinhados (_). Se você tivesse um arquivo Go chamado filename.go, poderia especificar o SO e a arquitetura, mudando o nome do arquivo para filename_GOOS_GOARCH.go. Por exemplo, se quisesse compilá-lo para o Windows com a arquitetura ARM 64-bit, você tornaria o nome do arquivo filename_windows_arm64.go​​​​​. Essa convenção de nomenclatura ajuda a manter o código totalmente organizado.

      Atualize seu programa para usar os sufixos do nome do arquivo, em vez dos build tags. Primeiro, renomeie os arquivos path.go e windows.go para usar a convenção usada no pacote os:

      • mv path.go path_unix.go
      • mv windows.go path_windows.go

      Com os dois nomes de arquivo alterados, você pode remover o build tag que você havia adicionado ao path_windows.go:

      Remova // +build windows para que seu arquivo se pareça com este:

      path_windows.go

      package main
      
      const PathSeparator = "\"
      

      Salve e saia do arquivo.

      Como o unix não é um GOOS válido, o sufixo _unix.go não tem significado para o compilador do Go. No entanto, ele transmite o objetivo pretendido do arquivo. Como o arquivo os/path_unix.go, seu arquivo path_unix.go ainda precisa usar build tags. Assim, mantenha esse arquivo inalterado.

      Ao usar as convenções de nome de arquivo, você recomeu os build tags desnecessários do seu código fonte, tornando o sistema de arquivos mais limpo e claro.

      Conclusão

      A capacidade de gerar binários para várias plataformas que não exijam dependências é uma característica poderosa da cadeia de ferramentas do Go. Neste tutorial, você usou essa capacidade, adicionando build tags e sufixos de nome de arquivo para marcar certos snippets de códigos para compilar somente para certas arquiteturas. Você criou seu próprio programa dependente de plataforma e manipulou as variáveis de ambiente GOOS e GOARCH para gerar binários para plataformas além da sua plataforma atual. Esta é uma habilidade valiosa, uma vez que se trata de uma prática comum para ter um processo de integração contínuo que executa automaticamente por essas variáveis de ambiente para compilar binários para todas as plataformas.

      Para obter outros estudos sobre o go build, consulte nosso tutorial Personalizando os binários em Go com os build tags. Se quiser aprender mais sobre a linguagem de programação Go, de um modo geral, confira a série completa sobre Como Codificar em Go.



      Source link

      Crear aplicaciones de Go para diferentes sistemas operativos y arquitecturas


      En el ámbito del desarrollo de software, es importante considerar el sistema operativo y la arquitectura subyacente del procesador para los que se busca compilar un binario. Debido a que a menudo la ejecución de un binario en una plataforma de SO o arquitectura diferente resulta lenta o imposible, es una práctica común la de crear un binario final para muchas plataformas diferentes, a fin de maximizar el público de su programa. Sin embargo, esto puede ser difícil cuando la plataforma que usando para el desarrollo es diferente de la plataforma en la que desea implementar su programa. En el pasado, por ejemplo, desarrollar un programa en Windows e implementarlo en un equipo con Linux o macOS implicaba configurar las máquinas para cada uno de los entornos a los que se buscaba destinar los binarios. También se debían mantener las herramientas sincronizadas y existían otras consideraciones que sumaban costos y dificultaban la prueba y distribución colaborativas.

      Go resuelve este problema creando compatibilidad para varias plataformas directamente en la herramienta go build y en el resto de las herramientas de Go. Al usar variables de entorno y etiquetas de compilación, puede controlar el SO y la arquitectura para los cuales se creó su binario final y crear un flujo de trabajo que puede alternar rápidamente la inclusión de código dependiente de la plataforma sin cambiar su base de código.

      A través de este tutorial, creará una aplicación de muestra que un a cadenas en una ruta de archivo, creará e incluirá selectivamente fragmentos dependientes de la plataforma y formará binarios para diferentes sistemas operativos y arquitecturas de sistema en su propio sistema, lo que le mostrará la forma de usar esta potente capacidad en el lenguaje de programación Go.

      Requisitos previos

      Para seguir el ejemplo de este artículo, necesitará lo siguiente:

      Posibles plataformas para GOOS y GOARCH

      Antes de mostrarle la manera de controlar el proceso de creación para crear binarios en diferentes plataformas, inspeccionaremos los tipos de plataformas para los cuales Go puede realizar compilaciones y la forma en que Go hace referencia a estas plataformas usando las variables de entorno GOOS y GOARCH.

      Las herramientas de Go tienen un comando que puede imprimir una lista de las posibles plataformas en las que Go puede realizar compilaciones. La lista puede cambiar con cada nueva versión de Go, de modo que las combinaciones explicadas aquí posiblemente no sean las mismas en otra versión de Go. En el momento en que se redactó este tutorial, la versión actual de Go era la 1.13.

      Para buscar esta lista de posibles plataformas, ejecute lo siguiente:

      Verá un resultado similar al siguiente:

      Output

      aix/ppc64 freebsd/amd64 linux/mipsle openbsd/386 android/386 freebsd/arm linux/ppc64 openbsd/amd64 android/amd64 illumos/amd64 linux/ppc64le openbsd/arm android/arm js/wasm linux/s390x openbsd/arm64 android/arm64 linux/386 nacl/386 plan9/386 darwin/386 linux/amd64 nacl/amd64p32 plan9/amd64 darwin/amd64 linux/arm nacl/arm plan9/arm darwin/arm linux/arm64 netbsd/386 solaris/amd64 darwin/arm64 linux/mips netbsd/amd64 windows/386 dragonfly/amd64 linux/mips64 netbsd/arm windows/amd64 freebsd/386 linux/mips64le netbsd/arm64 windows/arm

      Este resultado es un conjunto de pares clave-valor separados por una /. La primera parte de la combinación, antes de la /, corresponde al sistema operativo. En Go, estos sistemas operativos son posibles valores para la variable de entorno GOOS, que se pronuncia como “goose” y significa Go Operating System (Sistema operativo GO). La segunda parte, después de la /, corresponde a la arquitectura. Como antes, estos son todos los valores posibles para una variable de entorno: GOARCH. Esto se pronuncia como “gore-ch” y significa Go Architecture (Arquitectura de Go).

      Vamos a desglosar una de estas combinaciones para comprender su significado y funcionamiento usando linux/386 como ejemplo. El par clave-valor comienza con el GOOS, que en este ejemplo sería linux haciendo referencia al SO Linux. GOARCH aquí sería 386, que representa el microprocesador Intel 80386.

      Existen muchas plataformas disponibles con el comando go build, pero la mayoría del tiempo usará linux, windows o darwin como valor para GOOS. Estos abarcan las tres principales plataformas de SO: Linux, Windows y macOS, que se basa en el sistema operativo Darwin y por tanto se denomina darwin. Sin embargo, Go puede abarcar plataformas menos predominantes, como nacl, que representa a Google Native Client.

      Cuando se ejecuta un comando como go build, Go utiliza el GOOS y GOARCH de la plataforma actual para determinar la forma de crear el binario. Para conocer la combinación a la que responde su plataforma, puede usar el comando go env y pasar GOOS y GOARCH como argumentos:

      Al probar este ejemplo, ejecutamos este comando en macOS en una máquina con una arquitectura AMD64, por lo que obtendremos el siguiente resultado:

      Output

      darwin amd64

      Aquí, el resultado del comando nos indica que nuestro sistema tiene GOOS=darwin y GOARCH=amd64.

      Ahora sabe lo que GOOS y GOARCH representan en Go, además de sus posibles valores. A continuación, preparará un programa para usarlo como ejemplo de cómo emplear estas variables de entorno y etiquetas de compilación a fin de crear binarios para otras plataformas.

      Escribie un programa que dependa de la plataforma con filepath.Join()

      Antes de comenzar a crear binarios para otras plataformas, vamos a crear un programa de ejemplo. Un buen ejemplo para este fin es la función Join en el paquete path/filepath de la biblioteca estándar de Go. Esta función toma varias cadenas y muestra una que se une con el separador de ruta de archivo correcto.

      Este es un buen ejemplo de programa porque el funcionamiento depende del sistema operativo en el que se ejecute. En Windows, el separador de ruta es una barra diagonal inversa, , mientras que en los sistemas basados en Unix se utiliza una barra diagonal /.

      Comenzaremos creando una aplicación que utilice file path.Join() y, después, escribirá su propia implementación de la función Join() que personaliza el código para los binarios específicos de la plataforma.

      Primero, cree una carpeta en su directorio src con el nombre de su aplicación:

      Posiciónese en ese directorio:

      A continuación, cree un nuevo archivo llamado main.go en su editor de texto. Para este tutorial, usaremos Nano:

      Una vez abierto el archivo, añada el siguiente código:

      src/app/main.go

      package main
      
      import (
        "fmt"
        "path/filepath"
      )
      
      func main() {
        s := filepath.Join("a", "b", "c")
        fmt.Println(s)
      }
      

      La función main() de este archivo utiliza filepath.Join() para concatenar tres cadenas juntas con el separador de ruta dependiente de plataforma correcto.

      Guarde el archivo y ciérrelo. Luego, ejecute el programa:

      Cuando ejecute este programa, recibirá diferentes resultados dependiendo de la plataforma que utilice. En Windows, verá las cadenas separadas por ​​​:

      Output

      abc

      En sistemas Unix como macOS y Linux, verá lo siguiente:

      Output

      a/b/c

      Esto muestra que, debido a los diferentes protocolos de sistemas de archivos empleados en estos sistemas operativos, el programa tendrá que crear un código diferente para las diferentes plataformas. Sin embargo, ya que utiliza un separador de archivos diferente dependiendo del SO, sabemos que filepath.Join() ya tiene en cuenta la diferencia en la plataforma. Esto es porque la cadena de herramientas de Go detecta el GOOS y GOARCH de su máquina y utiliza esta información para usar un fragmento de código con las etiquetas de compilación y el separador de archivos correctos.

      Consideraremos la ubicación de la que obtiene su separador la función filepath.Join(). Ejecute el siguiente comando para inspeccionar el fragmento pertinente de la biblioteca estándar de Go.

      • less /usr/local/go/src/os/path_unix.go

      Con esto, se mostrará el contenido de path_unix.go. Busque la siguiente parte del archivo:

      /usr/local/go/os/path_unix.go

      . . .
      // +build aix darwin dragonfly freebsd js,wasm linux nacl netbsd openbsd solaris
      
      package os
      
      const (
        PathSeparator     = '/' // OS-specific path separator
        PathListSeparator = ':' // OS-specific path list separator
      )
      . . .
      

      Esta sección define el PathSeparator para todas las variedades de sistemas similares a Unix compatibles con Go. Observe todas las etiquetas de compilación de la parte superior, de las cuales cada una es una posible plataforma GOOS asociada con Unix. Cuando GOOS coincida con estos términos, su programa mostrará el separador de ruta de archivos con el estilo Unix.

      Pulse q para volver a la línea de comandos.

      A continuación, abra el archivo que define el comportamiento de filepath.Join() cuando se utiliza en Windows:

      • less /usr/local/go/src/os/path_windows.go

      Verá lo siguiente:

      /usr/local/go/os/path_unix.go

      . . .
      package os
      
      const (
              PathSeparator     = '\' // OS-specific path separator
              PathListSeparator = ';'  // OS-specific path list separator
      )
      . . .
      

      Aunque el valor de PathSeparator es \ aquí, el código representará la barra diagonal inversa única () necesaria para las rutas de archivos de Windows, ya que la primera barra diagonal inversa solo es necesaria como un carácter de escape.

      Observe que, a diferencia de lo que sucede con el archivo de Unix, no hay etiquetas de compilación en la parte superior. Esto es porque GOOS y GOARCH también pueden pasarse a go build añadiendo un guión bajo (_) y el valor de la variable de entorno como sufijo al nombre de archivo, algo que veremos en mayor profundidad en la sección Usar los sufijos de nombre de archivo de GOOS y GOARCH. Aquí, la parte _windows de path_windows.go hace que el archivo actúe como si tuviese una etiqueta de compilación //+build windows en la parte superior del archivo. Debido a esto, cuando nuestro programa se ejeute en Windows, usará las constantes de PathSeparator y PathListSeparator del fragmento de código path_windows.go.

      Para volver a la línea de comandos, cierre less pulsando q.

      En este paso, creó un programa que mostró la forma en que Go convierte GOOS y GOARCH automáticamente en etiquetas de compilación. Teniendo esto en cuenta, ahora puede actualizar su programa y escribir su propia implementación de filepath.Join() usando las etiquetas de compilación a fin de establecer el PathSeparator correcto para las plataformas Windows y Unix.

      Implementar una función específica de plataforma

      Ahora que conoce la forma en que la biblioteca estándar de Go implementa código específico de una plataforma, puede usar etiquetas de compilación para hacer esto en su propio programa app. Para hacer esto, escribirá su propia implementación de filepath.Join().

      Abra su archivo main.go:

      Reemplace el contenido de main.go por lo siguiente usando su propia función llamada Join():

      src/app/main.go

      package main
      
      import (
        "fmt"
        "strings"
      )
      
      func Join(parts ...string) string {
        return strings.Join(parts, PathSeparator)
      }
      
      func main() {
        s := Join("a", "b", "c")
        fmt.Println(s)
      }
      

      La función Join toma varias parts y las une usando el método strings.Join() del paquete strings para concatenar las parts usando PathSeparator.

      Aún no definido PathSeparator. Hágalo en otro archivo. Guarde main.go y ciérrelo, abra su editor favorito y cree un nuevo archivo llamado path.go:

      nano path.go
      

      Defina PathSeparator y configúrelo de modo que sea igual al separador de ruta de archivo de Unix, /:

      src/app/path.go

      package main
      
      const PathSeparator = "/"
      

      Compile y ejecute la aplicación:

      Obtendrá el siguiente resultado:

      Output

      a/b/c

      Esto se ejecutará correctamente para obtener una ruta de archivo de estilo Unix. Sin embargo, esto no es aún lo que queremos: el resultado es siempre a/b/c, independientemente de la plataforma en la que funcione. Para añadir la funcionalidad de creación de rutas de archivo de estilo Windows, deberá añadir una versión de Windows de PathSeparator e indicar al comando go build la versión que se usará. En la siguiente sección, usará las etiquetas de compilación para conseguir esto:

      Usar etiquetas de compilación de GOOS o GOARCH

      Para tener en cuenta plataformas basadas en Windows, creará un archivo alternativo a path.go y usará las etiquetas de compilación para garantizar que los fragmentos de código solo se ejecuten cuando GOOS y GOARCH son la plataforma correspondiente.

      No obstante, primero añada una etiqueta de compilación a path.go para indicarle que realice operaciones de compilación para todo, a excepción Windows. Abra el archivo:

      Añada la siguiente etiqueta de compilación resaltada al archivo:

      src/app/path.go

      // +build !windows
      
      package main
      
      const PathSeparator = "/"
      

      Las etiquetas de compilación de Go admiten inversión, lo cual significa que puede indicar a Go que compile este archivo para cualquier plataforma, a excepción de Windows. Para invertir una etiqueta de compilación, disponga un ! antes de la etiqueta.

      Guarde el archivo y ciérrelo.

      Ahora, si ejecutara este programa en Windows, vería el siguiente error:

      Output

      ./main.go:9:29: undefined: PathSeparator

      En este caso, Go no podría incluir path.go para definir la variable PathSeparator.

      Ahora que se aseguró de que path.go no se ejecutará cuando GOOS tenga el valor Windows, añada un nuevo archivo, windows.go:

      En windows.go, defina el PathSeparator de Windows, además de la etiqueta de compilación para indicar al comando go build que es la implementación Windows:

      src/app/windows.go

      // +build windows
      
      package main
      
      const PathSeparator = "\"
      

      Guarde el archivo y cierre el editor de texto. La aplicación ahora podrá realizar compilaciones de una forma para Windows y de otra para todas las demás plataformas.

      Aunque los binarios ahora se compilarán correctamente para sus plataformas, existen cambios adicionales que debe aplicar a fin de realizar compilaciones para una plataforma a la que no tenga acceso. Para hacer esto, alterará sus variables de entorno GOOS y GOARCH locales en el siguiente paso.

      Utilizar sus variables de entorno GOOS y GOARCH locales

      Anteriormente, ejecutó el comando go env GOOS GOARCH para conocer el sistema operativo y la arquitectura en los que estaba trabajando. Cuando ejecutó el comando go env, buscó las dos variables de entorno GOOS y GOARCH; si las encontró, se usan los valores de estas, pero si no las encontró Go las configura con la información de la plataforma actual. Esto significa que puede cambiar GOOS o GOARCH para que no se establezcan de forma predeterminada en su SO y arquitectura locales.

      El comando go build tiene un comportamiento similar al del comando go env. Puede configurar las variables de entorno GOOS o GOARCH de modo que realicen tareas de compilación para una plataforma diferente usando go build.

      Si no usa un sistema Windows, compile un binario windows de app fijando la variable de entorno GOOS en windows cuando se ejecute el comando go build:

      A continuación, enumere los archivos en su directorio actual:

      En el resultado del listado del directorio se muestra que ahora hay un ejecutable app.exe de Windows en el directorio del proyecto:

      Output

      app app.exe main.go path.go windows.go

      Usando el comando file, puede obtener más información sobre este archivo y confirmar su compilación:

      Verá lo siguiente:

      Output

      app.exe: PE32+ executable (console) x86-64 (stripped to external PDB), for MS Windows

      También puede establecer una o ambas variables de entorno en el momento de la compilación. Ejecute lo siguiente:

      • GOOS=linux GOARCH=ppc64 go build

      Su ejecutable app ahora se reemplazará por un archivo para una arquitectura diferente. Ejecute el comando file en este binario:

      Verá un resultado como el siguiente:

      app: ELF 64-bit MSB executable, 64-bit PowerPC or cisco 7500, version 1 (SYSV), statically linked, not stripped
      

      Al establecer sus variables de entorno GOOS y GOARCH locales, ahora puede crear binarios para cualquiera de las plataformas compatibles con Go sin complicaciones en la configuración. A continuación, usará las convenciones de nombres de archivo a fin de mantener sus archivos bien organizados y realizar compilaciones para plataformas específicas automáticamente sin etiquetas de compilación.

      Utilizar los sufijos de nombre de archivo GOOS y GOARCH

      Como vio previamente, la biblioteca estándar de Go utiliza de forma intensiva las etiquetas de compilación para simplificar el código separando las implementaciones de las diferentes plataformas en diferentes archivos. Cuando abrió el archivo os/path_unix.go, había una etiqueta de compilación que listaba todas las posibles combinaciones que se consideran plataformas similares a Unix. El archivo os/path_windows.go, sin embargo, no contuvo etiquetas de compilación porque el sufijo del nombre de archivo bastó para indicar a Go la plataforma a la cual se destinó el archivo.

      Veremos la sintaxis de esta función. Al nombrar un archivo .go, puede añadir GOOS y GOARCH como sufijos al nombre del archivo en ese orden y separar los valores mediante guiones bajos (_). Si tuviese un archivo de Go llamado filename.go, podría especificar el SO y la arquitectura cambiando el nombre del archivo a filename_GOOS_GOARCH.go. Por ejemplo, si deseara compilarlo para Windows con arquitectura ARM de 64 bits, el nombre del archivo tendría que ser filename_windows_arm64.go. La convención de nomenclatura permite mantener bien organizado el código.

      Actualice su programa para que utilice los sufijos de nombre de archivo en vez de etiquetas de compilación. Primero, cambie el nombre de los archivos path.go y windows.go para usar la convención empleada en el paquete os:

      • mv path.go path_unix.go
      • mv windows.go path_windows.go

      Una vez cambiados los dos nombres de archivo, podrá eliminar la etiqueta de compilación que añadió a path_windows.go:

      Elimine // +build windows para que su archivo tenga este aspecto:

      path_windows.go

      package main
      
      const PathSeparator = "\"
      

      Guarde el archivo y ciérrelo.

      Debido a que unix no es un GOOS válido, el sufijo _unix.go no tiene significado para el compilador de Go. Sin embargo, transmite el propósito previsto del archivo. Al igual que el archivo os/path_unix.go, su archivo path_unix.go de todos modos necesita usar etiquetas de compilación. Por lo tanto, mantenga ese archivo inalterado.

      Usando las convenciones de nombres de archivo, eliminó las etiquetas de compilación innecesarias de su código fuente y aportó limpieza y claridad al sistema de archivos.

      Conclusión

      La capacidad de generar binarios para varias plataformas que no requieren dependencias es una función potente de la cadena de herramientas de Go. En este tutorial, recurrió a esta capacidad añadiendo etiquetas de compilación y sufijos de nombres de archivos a fin de marcar determinados fragmentos de código para que solo realicen tareas de compilación orientadas a ciertas arquitecturas. Creó su propio programa dependiente de plataforma y luego manipuló las variables de entorno GOOS y GOARCH a fin de generar binarios para plataformas diferentes de su plataforma actual. Esta es una capacidad valiosa, porque es común disponer de un proceso de integración continuo que se ejecute automáticamente a través de estas variables de entorno a fin de compilar binarios para todas las plataformas.

      Para continuar aprendiendo sobre go build, consulte nuestro tutorial Personalizar binarios de Go con etiquetas de compilación. Si desea obtener más información acerca del lenguaje de programación Go en general, consulte toda la serie Cómo realizar codificaciones en Go.



      Source link