# GitLib

La `gitlib.py` es una librería de Python también usable como programa de línea
de comandos para pruebas.

Contiene las funciones de gestión de git, y la parte de línea de comandos permite ejecutarlas sin necesitar escribir un programa que use la librería.


## Requisitos

La gitlib esta diseñada para funcionar dentro de un entorno opengnsys existente. Invoca algunos de los comandos de opengnsys internamente, y lee los parámetros pasados al kernel en el oglive.

Por lo tanto, no va a funcionar correctamente fuera de un entorno oglive.

## Instalación de dependencias para python

La conversion del código a Python 3 requiere actualmente los paquetes especificados en `requirements.txt`

Para instalar dependencias de python se usa el modulo venv (https://docs.python.org/3/library/venv.html) que instala todas las dependencias en un entorno independiente del sistema.

**Nota:** Ubuntu 24.04 tiene la mayoría de las dependencias necesarias como paquetes, pero no hay paquete de `blkid`, por lo cual es necesario usar pip y un virtualenv.

Ejecutar:

    sudo apt install -y python3 libarchive-dev libblkid-dev pkg-config libacl1-dev
    python3 -m venv venvog
    . venvog/bin/activate
    python3 -m pip install --upgrade pip
    pip3 install -r requirements.txt


# Uso

Ejecutar con:

    # . venvog/bin/activate
    # ./gitlib.py

En modo de linea de comando, hay ayuda que se puede ver con:

    ./gitlib.py --help


**Nota:** Ejecutar como usuario `root`, ya que `sudo` borra los cambios a las variables de entorno realizadas por venv. El resultado probable es un error de falta de módulos de Python, o un fallo del programa por usar dependencias demasiado antiguas.

**Nota:** Los comandos que comienzan por `--test` existen para hacer pruebas internas, y existen temporalmente para probar partes especificas del código. Es posible que necesiten condiciones especificas para funcionar, y van a eliminarse al completarse el desarrollo.


## Inicializar un repositorio:

    ./gitlib.py --init-repo-from /dev/sda2 --repo linux


Esto inicializa el repositorio 'linux' con el contenido /mnt/sda2.

`--repo` especifica el nombre de uno de los repositorios fijados durante la instalación de git (ver git installer).

El repositorio de sube al ogrepository, que se obtiene del parámetro de arranque pasado al kernel.

## Clonar un repositorio:

    ./gitlib.py --clone-repo-to /dev/sda2 --boot-device /dev/sda --repo linux

Esto clona un repositorio del ogrepository. El destino es un dispositivo físico que se va a formatear con el sistema de archivos necesario.

`--boot-device` especifica el dispositivo de arranque donde se va a instalar el bootloader (GRUB o similar)

`--repo` es el nombre de repositorio contenido en ogrepository.

# Consideraciones especiales para Windows

## Clonación

* Windows debe haber sido apagado completamente, sin hibernar. Ver https://learn.microsoft.com/en-us/troubleshoot/windows-client/setup-upgrade-and-drivers/disable-and-re-enable-hibernation
* Windows debe haber sido apagado limpiamente, usando "Apagar sistema". Es posible que gitlib no pueda montar un disco de un sistema apagado incorrectamente. En ese caso hay que volver a iniciar Windows, y apagarlo.
* No se puede usar cifrado de disco (Bitlocker)

## Restauración

Windows usa una estructura llamada BCD (https://learn.microsoft.com/en-us/windows-hardware/manufacture/desktop/bcd-system-store-settings-for-uefi?view=windows-11) para almacenar la configuración de arranque.

La estructura puede variar dependiendo en que maquina se despliegue, por esto gitlib soporta almacenar internamente multiples versiones del BCD, y elegir el correspondiente a una maquina especifica.

## Identificadores de disco

El arranque de Windows dependiendo de como esté configurado por Windows puede referirse
a UUIDs de particiones y discos cuando se usa particionado GPT.

El código actual conserva los UUIDs y los restaura al clonar.

## BCDs específicos

Los datos de arranque de Windows se guardan en `.opengsnys-metadata/efi_data`. Es posible incluir versiones adicionales en caso necesario. Se hace creando un directorio adicional con el nombre `efi_data.(id)`, donde id es un número de serie obtenido con el comando `/usr/sbin/dmidecode -s system-uuid`.

Por ejemplo:

```
# Obtener ID único del equipo

dmidecode -s system-uuid
a64cc65b-12a6-42ef-8182-5ae4832e9f19

# Copiar la partición EFI al directorio correspondiente a esa máquina particular
mkdir /mnt/sda3/.opengnsys-metadata/efi_data.a64cc65b-12a6-42ef-8182-5ae4832e9f19
cp -Rdpv /mnt/sda1/* /mnt/sda3/.opengnsys-metadata/efi_data.a64cc65b-12a6-42ef-8182-5ae4832e9f19

# commit
```

Con esto, al desplegar el repo, para la máquina a64cc65b-12a6-42ef-8182-5ae4832e9f19 se va a usar su propia configuración de arranque, en vez de la general.



# Documentación

Se puede generar documentación de Python con una utilidad como pdoc3 (hay multiples alternativas posibles):

    # Instalar pdoc3
    pip install --user pdoc3

    # Generar documentación
    pdoc3 --force --html opengnsys_git_installer.py

# Funcionamiento



## Metadatos

Git no es capaz de almacenar datos de atributos extendidos, sockets y otros tipos de archivos especiales. El gitlib los almacena en .opengnsys-metadata en
el raíz del repositorio.

Los datos se guardan en archivos de tipo `jsonl`, una estructura de JSON por linea. Esto es para facilitar aplicaciones parciales solo aplicando el efecto de las lineas necesarias.

Existen estos archivos:

* `acls.jsonl`: ACLs
* `empty_directories.jsonl`: Directorios vacíos, ya que Git no es capaz de guardarlos
* `filesystems.json`: Información sobre sistemas de archivos: tipos, tamaños, UUIDs
* `gitignores.jsonl`: Lista de archivos .gitignore (los renombramos para que no interfieran con git)
* `metadata.json`: Metadatos generales acerca del repositorio
* `special_files.jsonl`: Archivos especiales como sockets
* `xattrs.jsonl`: Atributos extendidos
* `renamed.jsonl`: Archivos renombrados para no interferir con Git
* `unix_permissions.jsonl`: Permisos UNIX (Git no los almacena exactamente)
* `ntfs_secaudit.txt`: Datos de seguridad de NTFS
* `efi_data`: Copia de la partición EFI (ESP)
* `efi_data.(id)`: Copia de la partición EFI correspondiente a un equipo especifico.
* `efi_data.(nombre)`: Copia de la partición EFI correspondiente a un nombre especificado por el administrador.
