viernes, marzo 31, 2023

Git Large File Storage

 El día de hoy  por primera vez desde que uso git tuve un problema al querer subir archivos grandes a github. Contexto: tengo un modelo entrenado con extensión pkl el cual pesa algo así como 280 MB, cuando quise subirlo a mi repositorio me dio el siguiente error:


remote: error: Trace: a30bc8551829cfe15407cd6a30fdf32fa02d500188c7d36f07e868f79f85f1ba
remote: error: See https://gh.io/lfs for more information.
remote: error: File modelacionrename.pkl is 278.13 MB; this exceeds GitHub's file size limit of 100.00 MB
remote: error: GH001: Large files detected. You may want to try Git Large File Storage - https://git-lfs.github.com.
To github.com:bullkservices/api-predictions.git
! [remote rejected] develop -> develop (pre-receive hook declined)
error: failed to push some refs to 'github.com:bullkservices/api-predictions.git'

Siguiendo el mensaje de error conocí la existencia de git-lfs, básicamente es un proyecto que nos permite almacenar archivos grandes en nuestros repositorios.

Seguí los pasos de la documentación pero mi error seguía sucediendo, investigando un poco me di cuenta que hay que seguir los pasos en orden. 

En mi caso lo que hice fue lo siguiente:

a) Descargar nuevamente mi repositorio

b) Ejecute el comando: git lfs install

c) Habilite el seguimiento de archivos grandes con extensión pkl: git lfs track "*.pkl"

d) En el paso anterior se creo automáticamente el archivo .gitattributes por lo que hice el git add . y commit

e) Agregue el archivo del modelo prediccion.pkl al repo, luego hice push con los cambios

Luego de hacer los pasos en orden pude subir mi archivo grande al repositorio.




miércoles, marzo 22, 2023

Error "cgo: C compiler "gcc" not found: exec: "gcc": executable file not found in $PATH" al hacer Build Image

Tengo una aplicación desarrollado en Go que usa una BD SQLite y al intentar crear mi imagen me da el siguiente error:

#10 0.467 cgo: C compiler "gcc" not found: exec: "gcc": executable file not found in $PATH

El dockerfile que estoy utilizando es el siguiente:

FROM golang:1.19-alpine

# Set destination for COPY
WORKDIR /app


# syntax=docker/dockerfile:1
FROM golang:1.19-alpine


RUN apk add curl


WORKDIR /go/src/app
COPY . .

RUN go get -d -v ./...
RUN go install -v ./...

RUN go build -o gestion
COPY start.sh .

ENTRYPOINT ["/bin/sh"]
HEALTHCHECK CMD curl --fail http://localhost:8080/healthcheck || exit 1
CMD ["start.sh"]

Luego de analizar y buscar en google me di cuenta que falta instalar build-base por lo que mi dockerfile queda de la siguiente manera:

FROM golang:1.19-alpine

# Set destination for COPY
WORKDIR /app


# syntax=docker/dockerfile:1
FROM golang:1.19-alpine


RUN apk add curl
RUN apk add build-base

WORKDIR /go/src/app
COPY . .

RUN go get -d -v ./...
RUN go install -v ./...

RUN go build -o gestion
COPY start.sh .

ENTRYPOINT ["/bin/sh"]
HEALTHCHECK CMD curl --fail http://localhost:8080/healthcheck || exit 1
CMD ["start.sh"]

Luego de indicar que instale build-base la imagen se crea de forma correcta.


lunes, marzo 20, 2023

GitHub Copilot (Go)

 Desde hace unas semanas en la StartUp que me encuentro trabajando surgió la idea de utilizar GitHub Copilot. La verdad que al principio no podía darme cuenta de como poder sacarle provecho a esta herramienta de AI.

Con el correr del tiempo me di cuenta que la herramienta analiza tu forma de programar y según el contexto de tu código le puedes sacar mas o menos provecho.  Lo bueno que esta herramienta te completo o sugiere el código que debes poner según el contexto de tu código.

En mi caso le pude sacar mucho provecho creando las pruebas unitarias ya que me proponía los test unitarios que me faltaban hacer o me los completaba.

Ejemplo:

Debía escribir prueba unitarias para encriptar y para desencriptar por lo que solo con el nombre que le puse a la func ya comenzó a proponerme código.  


func TestRsaEncrypt(t *testing.T) {
//GenerateKeyPair(2048)
pub, _, err := CreateKeys(2048)
if err != nil {
t.Error(err)
}
// encrypt
encrypted, err := RsaEncrypt([]byte("hello world"), []byte(pub.String()))
if err != nil {
t.Error(err)
}
assert.NotNil(t, encrypted)
}

Copilot detecto que quería realizar un test para hacer una encriptación RSA por lo que solo con nombrar la func el completo el código. En realidad solo escribí la primer línea y el resto me lo propuso. Hasta ahí me había sorprendido ya que me propuso el código de forma correcta pero mi sorpresa fue al hacer el unit test para el Decrypt.

func TestRsaDecrypt(t *testing.T) {
//GenerateKeyPair(2048)
pub, pri, err := CreateKeys(2048)
if err != nil {
t.Error(err)
}
// encrypt
encrypted, err := RsaEncrypt([]byte("hello world"), []byte(pub.String()))
if err != nil {
t.Error(err)
}
// decrypt
decrypted, err := RsaDecrypt(encrypted, []byte(pri.String()))
if err != nil {
t.Error(err)
}
assert.Equal(t, "hello world", string(decrypted))
}

Al poner el título de la función me propuso todo el código, solo con un error el cual tuve que corregir pero me ahorre de escribir mas de 15 líneas.


En síntesis:

La herramienta es muy potente, solo debemos ayudarla teniendo un buen código ya que toma como contexto el código de nuestro repo para proponer código siguiendo nuestra lógica. Es importante los comentarios y los nombres de las funciones o estructuras. Creo que este tipo de herramientas se están haciendo cada día mas populares y como desarrollador es importante que aprendamos a convivir con este tipo de ayuda dado que nos brinda la posibilidad de aumentar nuestra productividad.