Gestión de DependenciasTutoriales

Swift Package Manager – Paquetes y Dependencias

En esta ocasión aprenderemos sobre Swift Package Manager, el gestor de paquetes de Swift, una herramienta con la cual podremos crear paquetes / proyectos ya sean librerías o ejecutables, gestionar las dependencias de estos y en general administrar de una manera más fácil y consensuada la distribución de nuestro código Swift.

Swift Package Manager fue introducido en la versión 3.0 de Swift y desde entonces viene mejorando mucho en cada versión, volviéndose mucho más funcional y estable. Actualmente se encuentra muy bien integrado con el sistema de compilación de Swift, de esta manera se automatiza el proceso de descarga, compilación y vinculación de dependencias tal y como se espera de una herramienta de este tipo y en estos tiempos.

Visión conceptual

Antes de entrar en materia repasaremos ciertos conceptos básicos manejados en este artículo relacionados con la funcionalidad del Swift Package Manager.

Módulos

Swift organiza el código en módulos. Cada módulo especifica un espacio de nombres e impone controles de acceso sobre qué partes de ese código se pueden usar fuera del mismo. Un programa puede tener todo su código en un solo módulo, o puede importar otros módulos como dependencias. Además del puñado de módulos proporcionados por el sistema, como Darwin en macOS o Glibc en Linux, la mayoría de las dependencias requieren que el código se descargue y construya para poder ser utilizado.

Cuando hacemos uso del código de un módulo para resolver un problema este no está limitado a un caso en particular, por el contrario este módulo o librería externa se puede reutilizar en otras situaciones. Por ejemplo, un módulo que nos ayuda con las peticiones de red se puede compartir entre una aplicación para compartir fotos y una aplicación de clima. El uso de módulos nos ayuda a agilizar los tiempo de desarrollo, permitiendo construir nuestro proyecto (o ciertas áreas de este) sobre el código bien escrito (en la mayoría de los casos) de otros desarrolladores en lugar de volver a implementar la misma funcionalidad nosotros mismos y perder un tiempo precioso para al final, muchas veces, ni siquiera obtener un mejor desempeño.

Paquetes

Un paquete consta de archivos fuentes y un archivo de manifiesto. El archivo de manifiesto, llamado Package.swift, define el nombre del paquete y su contenido utilizando el módulo PackageDescription. Un paquete cuenta con uno o más targets (objetivos). Cada target especifica un producto y puede declarar una o más dependencias.

Productos

Mediante un target podemos especificar un producto, ya sea una librería o un ejecutable. Una librería contiene un módulo que puede ser importado por otro código Swift y un ejecutable es un programa que puede ejecutar el sistema operativo.

Dependencias

Las dependencias de un target son módulos requeridos por el código del paquete. Una dependencia consiste en una URL relativa o absoluta que apunta al origen del paquete así como un conjunto de requisitos para la versión compatible del paquete que podemos usar en nuestro proyecto. El rol de Package Manager es reducir los costos de coordinación al automatizar el proceso de descarga y creación de todas las dependencias para un proyecto. Esto resulta en la mayoría de las veces en un proceso recursivo: una dependencia puede tener sus propias dependencias, cada una de las cuales a su vez también pueden tener otras más, formando un árbol de dependencias, que gestionar a mano sería extremadamente engorroso. Por esta razón es que Package Manager nos ayuda con la descarga e instalación de todo lo necesario para satisfacer el árbol de dependencias.

¿Qué es el super comando swift?

Mediante el comando swift ejecutamos la gran mayoría de nuestras acciones. Muchas veces se confunde con Swift REPL (Read Eval Print Loop) ya que si lo ejecutas sin parámetros entra por defecto en este modo. Pero hagamos una pausa y responsamos la siguiente pregunta primero:

¿Qué es Swift REPL?

Swift REPL es un modo del comando swift que a su vez nos brinda la funcionalidad de un interprete interactivo de instrucciones Swift, traduciendo las siglas sería algo como: Ciclo de Lectura , Evaluación e Impresión. Pero al mismo tiempo mediante Swift REPL también podemos a su vez acceder al depurador LLDB para tareas más que evidentes. Pasemos a la terminal para ejemplificar lo que acabo de comentar:

Probando Swift REPL

En esta imagen vemos la ejecución del modo Swift REPL del comando swift en Ubuntu (en macOS es similar). Podemos constatar como las instrucciones que pasamos son leídas (Read) e interpretadas (Eval) para al final mostrarnos la respectiva salida en pantallas (Print), tal y como también se observa pudiéramos seguir escribiendo (Loop) hasta que decidamos salir con la opción :q (al estilo vi / vim).

Respondiendo a la primera pregunta: Cuando observamos todo el panorama nos percatamos que con el comando swift podemos hacer muchas cosas, es como un meta-comando lleno de funcionalidades y hasta un modo interactivo. Por esta razón lo he llamado el super comando swift, en la ayuda funge como “Swift Compiler” (Compilador Swift) pero el que realmente compila el código fuente es el comando swiftc. Este comando (swift) viene siendo como una interfaz a nivel de terminal desde la cual (como ya comenté) podemos entrar en el modo interactivo de Swift REPL, podemos compilar o interpretar un archivo, y también podemos acceder a Package Manager.

Si en alguna de estas capturas te preguntas que interprete de comandos estoy usando o como instalar cierta herramienta que uso y que no viene por defecto pues te invito a leer nuestro artículo sobre la configuración de un entorno de desarrollo Swift (iOS, macOS, tvOS y watchOS) en sistemas macOS.

Conociendo la versión instalada

Siempre es útil conocer la versión de Swift que tenemos instalada y esto lo conseguimos ejecutando el siguiente parámetro sobre el super comando swift. En la terminal de macOS ejecutemos lo siguiente:

…obtenemos la siguiente salida en pantalla:

Como deben de imaginar el comando swift se instala en el sistema junto a Xcode…

En el caso de Linux hay que seguir algunos pasos que ya hemos descrito en nuestra guía sobre la instalación del lenguaje Swift en sistema Linux.

Obteniendo ayuda

Un comando con tantas opciones resulta bien confuso, así que junto a opciones como este propio artículo y recursos similares como la documentación oficial de Apple y del proyecto Swift, también contamos con una documentación propia del comando: una lista y descripción de los parámetros que podemos pasar sobre este nuestro super comando swift. Para acceder a este modo ejecutemos en la terminal el parámetro -help:

Showing Swift Help

…en esta imagen vemos claramente que la salida en pantalla no cabe en el marco de la terminal, así que lo ejecutaremos de esta otra manera haciendo un pipeline redirigiendo el flujo de la salida de este comando hacia less:

Puedes copiar el comando anterior aquí:

Showing Swift Help with Less

Puedes copiar el comando anterior aquí:

Ahora nos podemos desplazar por la documentación mediante las flechas de arriba y abajo del teclado y salimos presionando la tecla q;

Scripting

Luego de leer la documentación tendremos una mejor idea de todo cuanto podemos hacer con este comando, entre ellas la lectura de un archivo externo o la creación de un script y esto lo podemos probar de una manera bien sencilla. Creemos un archivo:

…luego lo abrimos y le añadimos la siguinete línea:

…salvamos y pasamos este archivo fuente al comando swift:

Executing Swift Script

El resultado lo podemos observar en la imagen anterior. Visto esto:

¿Acaso podemos crear un script al clásico estilo Bash o Python?

La respuesta es sí, modifiquemos el archivo fuente anterior a la siguiente versión:

Salvamos el archivo y en la terminal le damos permisos de ejecución:

…luego de esto ya lo podemos ejecutar:

Testing Swift Script

Puedes copiar el comando anterior aquí:

En este punto ya tenemos un script programado en Swift que podemos instalar en nuestro ordenador personal o servidor para automatizar ciertas tareas.

¿Cómo usar Swift Package Manager?

En este punto y luego de esta introducción al comando swift y a todo cuanto podemos hacer con él. Hagamos una revisión de los comandos básicos de Package Manager que nos permitirán llevar a cabo esas tareas más frecuentes del día a día.

Creando un paquete de tipo Librería

Para esta sección voy a hacer uso de un ejemplo que muestran en el proyecto Swift para ejemplificar estos temas y que me parece bien didáctico y por ende ideal para este artículo.

PlayingCard

Este ejemplo consta de cuatro paquetes distintos que interactúan entre ellos. Dicho esto comencemos con la creación del primero, como ya conocemos a Package Manager se accede a través del comando swift así que pasamos directamente a la creación del paquete:

Comenzamos por crear una carpeta vacía para nuestro proyecto y nos movemos dentro de esta con el comando:

Ahora ejecutamos el siguiente comando:

Creating Swift Library Package

Puedes copiar el comando anterior aquí:

Este comando nos crea un paquete de tipo librería con toda la estructura de directorios necesaria:

Estructura de Directorios
Directorio / Fichero Descripción
Package.swift Nuestro paquete se describe por completo dentro de este fichero que en realidad es un código fuente en Swift. En él especificamos la versión de Swift con la que trabajaremos así como las dependencias de nuestro paquete y las versiones mínimas o máximas de estas.
.build En este directorio oculto (comienza por un punto “.”) es donde Swift coloca nuestro ejecutable compilado.
Packages Es donde Package Manager almacena las dependencias descargadas. Si miramos dentro veremos todas las dependencias de nuestro proyecto más las propias dependencias de estas.
Sources Es donde debemos colocar nuestro código fuente. En este momento, contiene solo “MyTest“, que a su vez solo contiene main.swift que es el punto de entrada de nuestra aplicación. Evidentemente podemos agregarle más códigos fuentes y estos se compilarán automáticamente como parte de nuestro proyecto.
Tests Aquí es donde colocamos nuestros tests compatibles con XCTest.
README.md Este fichero es bien famoso en la industria y es donde describimos lo que hace nuestro proyecto para que otros lo lean y sepan de que va.
.gitignore También tenemos este otro archivo oculto donde establecemos los ficheros y directorios que git tiene que ignorar, ya que por alguna razón no deseamos que se gestionen mediante este o sencillamente porque se generan dinámicamente.

Es importante recalcar que esta estructura de directorios es similar para los paquetes de tipo ejecutables como veremos más adelante.

Para continuar con nuestros ejemplos se impone añadir algunas dependencias en pos de poder ejemplificar otras opciones de Package Manager. Editemos el fichero Package.swift a la versión siguiente:

Salvamos el archivo y acto seguido compilamos nuestro paquete ejecutando el siguiente comando:

Swift Build

Puedes copiar el comando anterior aquí:

Aquí tenemos una salida en pantalla bien sencilla dado que es una librería que no tiene dependencias y prácticamente tampoco tiene códigos. Digo prácticamente ya que por defecto Package Manager nos crea un fichero fuente del mismo nombre de la librería, en este caso PlayingCard.swift en el cual nos crea una estructura del mismo nombre así como una variable de tipo String y de nombre text con la cadena de texto asociado “Hello, World!”:

Showing Default Content of Library Package

Código que vamos a sobreescribir con el siguiente:

En este ejemplo hay segmentos que no abordaré debido a que no es el objetivo de este artículo y también porque ya han sido explicados. Me refiero a las extensiones, la sobrecarga de operadores y a los protocolos… pueden referirse a estos links para más información. Básicamente en este código creamos una estructura con dos constantes, una de nombre rank donde almacenaremos el rango de una carta (Diamantes, Corazones, Espadas) y en suit el tipo de la misma (As, dos, tres, Jota, Reina, Rey). Luego extendemos nuestra estructura para que adopte los protocolos Equatable, Comparable y CustomStringConvertible junto a sus respectivos requerimientos.

El paso siguiente para terminar con este paquete será la creación de dos archivos fuentes más junto a este que se nos fue creado por defecto. Rank.swift:

…y Suit.swift:

Como ya comenté, los contenidos aplicados en estos ejemplos ya han sido abordados en este sitio, incluida las enumeraciones vistas en estos dos últimos ficheros.

Si en este momento compilamos nuevamente el paquete:

Swift Build with More Source Codes

…comprobamos que se han detectado automáticamente los nuevos archivos de código fuente y se han compilado correctamente. Por último imaginemos que subimos este paquete a github para que cualquier otra persona pueda usar las funcionalidades de  nuestra librería.

FisherYates

Nuestro segundo paquete será FisherYates, el cual se encargará de barajar las cartas. Este módulo también lo crearemos como una librería (ya vimos como hacerlo) ya que es una funcionalidad que podremos utilizar en varios proyectos. El fichero Package.swift luciría así:

Dentro de la carpeta Source tendremos dos archivos, el primero será FisherYates.swift:

…y el segundo random.swift:

Recuerden que el objetivo de estos ejemplos no es lo que hacen como tal, los estamos compartiendo para que quede los más real posible. Este último paquete es también una librería, en él solo se declaran funcionalidades para luego ser usadas desde un proyecto ejecutable o también desde otra librería. En el archivo FisherYates.swift proponemos dos extensiones a los protocolos Collection y MutableCollection, por su parte el archivo random.swift hace una distinción entre macOS y Linux enfocado en la ejecución de la función arc4random_uniform (línea 7) que solo está disponible en macOS y por ende en Linux abogamos por su homólogo random (línea 23).

Esto sería todo sobre este paquete, pero antes de continuar compilamos el módulo y verificamos que todo vaya bien. Al igual que con el paquete anterior imaginemos que lo subimos a github para que cualquier otra persona pueda usar las funcionalidades de esta librería.

DeckOfPlayingCards

El paquete DeckOfPlayingCards combina las dos librerías anteriores: define un tipo Deck que usa el método shuffle de FisherYates en una matriz de valores de PlayingCard. Para usar los módulos FisherYates y PlayingCards, el paquete DeckOfPlayingCards debe declarar estos paquetes como dependencias en el manifiesto Package.swift:

En las líneas 14 y 15 obtenemos los paquetes / módulos anteriores desde github, tal y como les comenté que imaginasen subían. No les digo que realmente lo hagan debido a que es solo un ejemplo y porque como ven estos ya han sido subidos por Apple.

El contenido del fichero DeckOfPlayingCards.swift:

Salvamos y compilamos:

Swift Build Getting Dependencies

…como pueden observar las librerías que antes hemos desarrollado se han descargado desde la fuente establecida (github), se han compilado y enlazado dentro de este nuevo módulo que acabamos de finalizar. Al igual que con las dos librerías anteriores imaginemos que esta también la subimos a github, ya sabemos las razones.

Creando un paquete de tipo Ejecutable

Tras abordar lo básico en cuanto a crear dos librerías y luego otra librería más pero que en este caso hace uso de las dos anteriores, pues ya estamos listos para crear un paquete ejecutable que se llamará Dealer y que hará uso de esta última librería (DeckOfPlayingCards).

Los pasos son similares a los anteriores y la tabla donde explicamos la estructura de directorios es igual de válida. Comenzamos por crear la carpeta del paquete:

…entramos en el directorio:

…y dentro de este ejecutamos:

Swift Package Init Help

Puedes copiar el comando anterior aquí:

Pues sí, no hay que saberlo todo de memoria aunque con el tiempo es inevitable, así que la ayuda es nuestra mejor aliada. Aquí pueden ver las opciones con las que contamos, donde se incluyen library (la que hemos usado hasta el momento) y executable que será nuestra próxima opción. Dicho esto continuamos:

Creating Swift Executable Package

Puedes copiar el comando anterior aquí:

El archivo manifiesto (Package.swift) de nuestro paquete ejecutable luce así:

Como ya se habrán imaginado en la línea 14 definimos como única dependencia a nuestra última librería DeckOfPlayingCards.

Ahora, a diferencia de los paquetes de tipo librería, los ejecutables no vienen por defecto con un fichero de código fuente cuyo nombre es idéntico al del módulo, en este caso el fichero se llama main.swift y constituye el punto de entrada de nuestro ejecutable. Pueden abrirlo y ver su contenido por defecto, el cual ya les adelanto es el clásico “Hello, world!”.

El contenido del fichero main.swift para nuestro paquete luciría así:

Salvamos y compilamos:

Executable Package Importing All Custom Libraries

Aquí vemos como nuestra dependencia al igual que sus dependencias se descargan, se compilan y se enlazan en nuestro paquete ejecutable, acto seguido ejecutamos el binario mediante el comando:

Swift Run Dealer

Puedes copiar el comando anterior aquí:

La salida en pantalla no está del todo bien formateada pero esto no lo puedo cambiar ya que estamos obteniendo las dependencias (como ya les comenté) desde los repositorios oficiales de Apple en github, aunque quizás para cuando hayas ejecutado todo esto ya lo hayan mejorado.

Actualizando dependencias

Eventualmente necesitaremos agregar nuevas dependencias o cambiar la versión de alguna ya añadida, eventos para los que Swift Package Manager también está preparado, imaginemos que necesitamos trabajar con Perfect en nuestro paquete así que necesitamos agregarlo como otra dependencia del mismo:

Así ha quedado nuestro manifiesto Package.swift, en este acabamos de agregar Perfect en la línea 15. Acto seguido salvamos y ejecutamos el siguiente comando:

Swift Package Update

Puedes copiar el comando anterior aquí:

Como podemos ver en la salida estándar las dependencias han aumentado considerablemente ya que Swift Package Manager nos incluye también las dependencias de Perfect. Este cambio se ve mucho mejor cuando compilamos nuestro proyecto:

Swift Build Dealer Package

…donde la salida en pantalla no cabe en la ventana de la Terminal incluso después de agrandarla bastante.

¿Podemos utilizar Xcode?

Para muchos de seguro no será muy cómodo programar en Visual Studio Code, Atom o peor aún en Vim, sobre todo si estás acostumbrado a la interfaz de Xcode y a todo lo que este nos brinda. Pues resulta que mediante el comando swift podemos generar un proyecto de Xcode a partir de nuestro paquete recién creado. Exacto, primero creamos el paquete ya sea ejecutable o una librería y luego de esto ejecutamos el siguiente comando:

Swift Package Generate Xcodeproj

Puedes copiar el comando anterior aquí:

…luego de ejecutar el comando que observan en la imagen listamos el contenido del paquete y vemos el fichero correspondiente al proyecto Xcode como el primero de la lista. Al dar doble click:

Showing Xcode Dealer Package

…ya lo tenemos abierto en Xcode donde podremos interactuar con el paquete como cualquier otro proyecto. Creo válido aclarar que en dependencia de la versión de Swift que usen las librerías que estamos importando en nuestro paquete: tendremos advertencias (Warning) relacionadas con esto y una más que clara migración a efectuar.

¿Cómo funciona la ayuda?

Quizás te habrás dado cuenta que cuando accedimos a la ayuda del comando swift tuvimos una salida en pantalla distinta a cuando verificamos los tipos de paquetes que podemos crear. Estos se debe a que la ayuda está muy bien pensada y es dinámica. Así que apoyándonos en la última opción que comentamos, supongamos que deseamos conocer las otras opciones disponibles aparte de update, para esto solamente tenemos que acceder a la ayuda de esta manera:

Swift Package Help

Puedes copiar el comando anterior aquí:

Si analizas el patrón que hemos seguido hasta ahora, para acceder a la ayuda, te darás cuenta de que la salida varía en dependencia de la opción a la que pasemos “–help” como parámetro, por esto les comentaba que era dinámica. Ejemplo: cuando ejecutamos el comando “swift package init -help” estamos accediendo a las opciones válidas a escribir tras el parámetro “init”, de igual manera sucede cuando ejecutamos “swift package –help” y se nos muestra una ayuda distinta donde se nos informa sobre las opciones que podemos pasar al parámetro “package”. Siguiendo esta lógica, amigos, podemos ir nosotros mismos concatenando opciones y dar con ese comando final del cual quizás nadie te ha hablado aún.

Conclusiones

Como hemos podido constatar Swift Package Manager es muy útil: nos permite crear paquetes de varios tipos y también gestionar las dependencias que estos puedan tener. En los ejemplos que hemos visto, el compilador descarga las dependencias de nuestro proyecto (que en estos casos se han encontrado en github (algo frecuente)), se clonan los repositorios de estas, luego se compilan junto a nuestros códigos fuentes para al final enlazarlas al módulo de nuestro paquete ejecutable, todo muy fluido y sin mayor esfuerzo.

Swift Package Manager nos ayuda con algo que muchos tuvimos que hacer a mano hace ya algún tiempo,  incluso cuando hablamos de aplicaciones para la terminal, en el caso de macOS, no existía brew y en Linux incluso peor ya que tampoco contábamos con APT, YUM o DNF para instalar aplicaciones de uso diario. En esa época había que instalar las aplicaciones compilándolas o instalar los paquetes (precompilados) y cada una de sus dependencias a mano usando comandos como dpkg o rpm.

Falta aún mucho por aprender en nuestro camino a convertirnos en iOS Developer. Suscríbete a nuestra lista de correo mediante el formulario en el panel derecho y síguenos en nuestras redes sociales. Mantente así al tanto de todas nuestras publicaciones futuras.

Espero que todo cuanto se ha dicho aquí, de una forma u otra le haya servido de aprendizaje, de referencia, que haya valido su preciado tiempo.

Este artículo, al igual que el resto, será revisado con cierta frecuencia en pos de mantener un contenido de calidad y actualizado.

Cualquier sugerencia, ya sea errores, información o ejemplos a añadir será, más que bienvenida, necesaria!

Josué V. Herrera

Ciudadano del mundo. Me gusta mucho la naturaleza y rodearme de esta, la literatura, la música y el cine, aficionado a la aviación y a todo lo que es tecnología y ciencia. Desde el 2005 me dedico de manera profesional a la informática, trabajando principalmente como administrador de redes / sistemas y también como programador, especializándome en Linux y en C++ / Qt. Soy Experto en Administración y Seguridad de Redes por la Universidad Tecnológica Nacional FRVM de Argentina. Desde el 2014 me dedico al estudio de Swift y el entorno que lo rodea, ya sea tanto del lado de Apple como del Open Source.

Related Articles

RECIBE CONTENIDO SIMILAR EN TU CORREO

RECIBE CONTENIDO SIMILAR EN TU CORREO

Suscríbete a nuestra lista de correo y mantente actualizado con las nuevas publicaciones.

Se ha suscrito correctamente!

Close

Adblock Detected

Please consider supporting us by disabling your ad blocker