forked from fisicaUSC/revista
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathfuncions.lua
More file actions
203 lines (157 loc) · 8.64 KB
/
funcions.lua
File metadata and controls
203 lines (157 loc) · 8.64 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
-- Este é un arquivo onde podemos meter funcións escritas con Lua. Podemos
-- chamalas despois no documento con \directlua{\minha_funcion()}
--
-- Documentación de Lua: https://www.lua.org/manual/5.3/
-- Documentacion de Luatex: https://ctan.org/pkg/luatex
-- :FACER: pode que mereza a pena sustituir esto por 'luagit' de ctan.
-- :FACER: algún modo de saber se estamos en 'dirty state' ?
-- :FACER: parece que hai un erro a veces, ao poñernos en 'detached state', pode ser polos regexes?
-- :FACER: qué pasa se usamos 'sparse-checkout' ?
function gitInfo()
--[[
Esta funcións devolve a rama e o hash da HEAD actual de git. Para dito fin,
busca nos directorios de git (.git e similares) para obter o nome da rama
na que estamos, e con esa información obter o hash da última contribución
Funciona con 2 estructuras:
.git/ | o normal, tendo os arquivos no mesmo directorio que .git/
ficheiro | e sendo .git/ un directorio con HEAD, config, refs/, etc.
ficheiro2 |
etc |
.git | parecido, pero aquí .git é un ARQUIVO que contén o texto:
ficheiro | "gitdir: /ruta/ata/meu/PROXECTO/worktrees/WT3"
ficheiro2 |
etc |
Sí, parecen estructuras iguais, pero o feito de que nun caso .git sexa un
directorio e no outro un ficheiro normal, é fundamentalmente diferente, e
cambia o modo de buscar a información que queremos
]]
-- Comprobamos se .git é un directorio (99% dos casos) ou un ficheiro (e.g.
-- usando worktrees) Alternativas a pelo:
-- https://www.geeks3d.com/hacklab/20210901/how-to-check-if-a-directory-exists-in-lua-and-in-python/
-- https://stackoverflow.com/questions/1340230/check-if-directory-exists-in-lua/40195356#40195356
-- Usando LFS (Lua File System) é sinxelo.
-- Véxase: https://lunarmodules.github.io/luafilesystem/manual.html
local tipo, _ = lfs.attributes(".git","mode")
-- Se non se atopa ou hai algún erro, mostrámolo e rematamos a función
if tipo == nil then tex.print("[SIN .GIT]") return end
-- O caso típico, temos o espazo de traballo cos nosos ficheiros e ao lado
-- o repositorio en .git/ o cal é un directorio
if tipo == "directory" then
-- Intento abrir o ficheiro HEAD
local HEAD = io.open(".git/HEAD")
-- Se non abre, rematamos o traballo
if HEAD == nil then tex.print("HEAD non abre") return end
-- Lemos a primeira liña con 'l', ousexa só unha liña do arquivo
local info = HEAD:read("l")
-- E cerramos o ficheiro
HEAD:close()
-- .git/HEAD ten unha liña como -> ref: refs/heads/principal
-- Uso algo de regex para coller a ultima palabra, que é o nome da rama
-- véxase https://www.lua.org/manual/5.3/manual.html#pdf-string.match
local rama = string.match( info , "/([^/]+)$" )
-- O nome da rama en xeral non ten caracteres raros, o máis comun pode
-- ser o '_', asique o escapo. Supoño que estaría ben facelo con máis
-- caracteres especiais de TeX, pero por agora val
local rama_escapada = string.gsub(rama, "_", "\\_")
-- E imprimímola directamente. Engado un ':' porque queda bonito
tex.sprint(rama_escapada .. ":")
-- A ruta para obter o hash, soe estar en .git/refs/heads/[rama]/
local ficheiro_HASH = io.open(".git/refs/heads/" .. rama, "r")
-- Outra comprobacion, se non se abre
if ficheiro_HASH == nil then
-- Pode ocurrir, que ao facer cousas como 'git gc' ou
-- 'maintenance', ou rulando 'git pack-refs', en vez de ter as
-- cousas en .git/refs/HEADS/[rama]/ estén en .git/packed-refs.
-- Véxase: https://git-scm.com/docs/git-pack-refs
--
-- IMPORTANTE: para máis lio, se temos 'packed-refs', e creamos
-- referencias NOVAS, estas gárdanse en .git/refs/heads/[rama] É
-- dicir, podemos ter as referencias en dous sitios distintos. Non
-- é problema, porque queremos a última referencia, a cal está en
-- .git/refs/heads/[rama], o cal é o PRIMEIRO sitio que buscamos.
-- Asique se existe, escollemos o correcto. Creo.
ficheiro_HASH = io.open(".git/packed-refs","r")
-- Se nin así funciona, rematamos
if ficheiro_HASH == nil then tex.sprint("HASH non abre") return end
-- Lemos o packed-refs. Usase 'a' porque son varias liñas.
-- IMPORTANTE: lendo con "a" todo o contido do arquivo pasa a ser
-- unha soa cadena. Se o ficheiro ten varias liñas, concaténanse.
-- Hai que telo enconta logo usando regex, dado que ^ e $ son máis
-- delicados
info = ficheiro_HASH:read("a")
ficheiro_HASH:close()
-- O ficheiro 'packed-refs' ten varias liñas como:
-- 152204658ccc8c4126477370cdfb5de8b49348ab refs/heads/[rama]
-- .- -> coincide con calquera caracter, a menor cantidade de veces
-- (%x+) -> coincide con caracteres hex, mínimo un
-- %srefs/heads/ -> espazo e logo o literal "refs/heads/"
-- Como comentei antes, non hai que usar ^ nin $ porque inda que o
-- que buscamos no arquivo esté agarrado ao comezo ^ ou ao final $,
-- esa estructura desfaise porque ao ler o arquivo xuntanse todas
-- as liñas!
local hash = string.match( info , ".-(%x+)%srefs/heads/"..rama )
-- O hash son 40 caracteres, collendo os 7 primeiros debería chegar
-- e.g. 5fde70ec
tex.sprint(string.sub(hash, 1, 7))
return
end
-- No caso de que si teñamos as cousas en .git/refs/HEADS/[rama]/ ,
-- entón o 'if' anterior non se executa, e rulase esto de aquí.
-- En principio, lendo con 'l' é suficiente, o contido será o hash de
-- 40 caracteres simplemente
info = ficheiro_HASH:read("l")
ficheiro_HASH:close()
tex.sprint(string.sub(info, 1, 7))
return
-- No caso de que temos nun worktree de git. Véxase:
-- https://git-scm.com/docs/git-worktree
-- Pode que haxa outros casos cun .git que sea un arquivo, non os coñezo
elseif tipo == "file" then
-- Primeiro, intento abrir .git como se fose un arquivo.
local GIT = io.open(".git")
-- Se non se pode, rematamos
if GIT == nil then tex.print("GIT non abre") return end
-- Lemos os contidos
local info = GIT:read("l")
GIT:close()
-- Ao usar worktrees, .git é un ficheiro que contén, por exemplo:
-- gitdir: /home/david/.deivis_datos/proxectos/uni/revista/worktrees/WT3
-- onde o directorio base do repositorio é "revista"
--
-- Uso regex e dúas capturas para coller a ruta correcta ao repo (que
-- sería análogo a onde está .git nun repositorio normal) e gardoo en
-- 'ruta_BASE'. Tamén gardo o nome do worktree en 'worktree' porque
-- logo fará falta
local _, _, ruta_BASE, worktree = string.find( info, "^gitdir:%s(.-)/worktrees/([^/]+)$" )
-- ruta_BASE: directorio onde está o repositorio, con HEAD (non do worktree), config, refs/, etc.
-- ruta_BASE/wortrees/[nome worktree]: dentro está o HEAD do propio Worktree que estamos usando
-- xa sei que é un rollo, non me culpedes, foi Torvalds quen creou esto
local HEAD = io.open(ruta_BASE .. "/worktrees/" .. worktree .. "/HEAD")
-- Abrir, checkear, ler... como antes
if HEAD == nil then tex.sprint("HEAD non abre") return end
local info = HEAD:read("l")
HEAD:close()
local rama = string.match( info , "/([^/]+)$" )
local rama_escapada = string.gsub(rama, "_", "\\_")
tex.sprint(rama_escapada .. ":")
-- Para o hash, en ruta_BASE/
local ficheiro_HASH = io.open(ruta_BASE .. "/refs/heads/" .. rama, "r")
-- Outra comprobacion, como antes
if ficheiro_HASH == nil then
-- O mesmo de antes, se temos 'packed-refs'
ficheiro_HASH = io.open(ruta_BASE .. "/packed-refs","r")
if ficheiro_HASH == nil then tex.sprint("HASH non abre") return end
-- Lemos o packed-refs
info = ficheiro_HASH:read("a")
ficheiro_HASH:close()
local hash = string.match( info , ".-(%x+)%srefs/heads/"..rama )
tex.sprint(string.sub(hash, 1, 7))
return
end
-- No caso de non ter packed-refs
info = ficheiro_HASH:read("l")
ficheiro_HASH:close()
tex.sprint(string.sub(info, 1, 7))
return
end
end