licencias 96% (1129/1165): la fuente git también es evidencia, y el script deja de llamarse «tarball»
Faltaban tres recetas cuya fuente es un repo, no un tarball: `fcft`, `foot` y `glab`. El commit pineado cumple exactamente el mismo papel que el sha256 —es el árbol EXACTO que construimos— así que la evidencia estaba igual de disponible, sólo que por otra puerta. `miembros_de_git()` la abre sin clonar el árbol entero: `--depth 1 --filter=blob:limit=64k` sobre el commit. Un COPYING nunca pasa de 64k y los fuentes donde vive la concesión tampoco; los que sí pasan —binarios, assets— son justo los que no interesan. Un repo de cientos de megas se resuelve con unos pocos. Las tres salieron del `license:` que el propio autor escribe en su `meson.build` (fcft, foot) y del texto del LICENSE (glab). Los repos por SSH se saltan diciéndolo: este script hace fetch anónimo y no tiene claves. Son `hammerd` y `portal-probe`, y ya están resueltas por otra vía (su repo es este mismo). `analizar()` pasa a consumir un iterable de `(ruta, bytes)` en vez de abrir el tar ella misma, así que las dos fuentes comparten TODA la lógica de veredicto: la jerarquía de evidencia, la regla de sólo-la-raíz, la unión de identificaciones y la exigencia de que la concesión hable de la misma versión que el COPYING. Un criterio, dos puertas. Y el script se renombra `licencias-tarball.py` → `licencias-fuente.py`, porque el nombre viejo pasó a ser mentira en el momento en que aprendió a leer git. Un nombre que describe la implementación de ayer manda a la gente a buscar en el sitio equivocado. Los 3 ArtifactHash, idénticos antes y después.
This commit is contained in:
@@ -1,4 +1,4 @@
|
|||||||
# licencias-evidencia.tsv — lo generó scripts/licencias-tarball.py desde el
|
# licencias-evidencia.tsv — lo generó scripts/licencias-fuente.py desde el
|
||||||
# TARBALL PINEADO de cada receta. Tres columnas: paquete, SPDX, y la CITA que lo
|
# TARBALL PINEADO de cada receta. Tres columnas: paquete, SPDX, y la CITA que lo
|
||||||
# decidió. REVISAR A MANO antes de sembrar: es evidencia, no un veredicto firmado.
|
# decidió. REVISAR A MANO antes de sembrar: es evidencia, no un veredicto firmado.
|
||||||
# Se ACUMULA: las filas de lo ya sembrado se conservan como rastro de auditoría.
|
# Se ACUMULA: las filas de lo ya sembrado se conservan como rastro de auditoría.
|
||||||
@@ -8,11 +8,15 @@ dwarves GPL-2.0-only COPYING + concesión en btf_encoder.c: …/* SPDX-License-I
|
|||||||
elfutils GPL-3.0-or-later COPYING + concesión en tests/run-eu-search-die.sh: …ion; either version 3 of the License, or # (at your option) any later version. # # elfutils is di…
|
elfutils GPL-3.0-or-later COPYING + concesión en tests/run-eu-search-die.sh: …ion; either version 3 of the License, or # (at your option) any later version. # # elfutils is di…
|
||||||
elfutils-libdw GPL-3.0-or-later COPYING + concesión en tests/run-eu-search-die.sh: …ion; either version 3 of the License, or # (at your option) any later version. # # elfutils is di…
|
elfutils-libdw GPL-3.0-or-later COPYING + concesión en tests/run-eu-search-die.sh: …ion; either version 3 of the License, or # (at your option) any later version. # # elfutils is di…
|
||||||
exiv2 GPL-2.0-or-later COPYING + concesión en README.md: …ation; either version 2 of the License, or (at your option) any later version. Exiv2 program is…
|
exiv2 GPL-2.0-or-later COPYING + concesión en README.md: …ation; either version 2 of the License, or (at your option) any later version. Exiv2 program is…
|
||||||
|
fcft MIT meson.build: license: 'MIT'
|
||||||
file BSD-2-Clause COPYING (texto de BSD-2-Clause)
|
file BSD-2-Clause COPYING (texto de BSD-2-Clause)
|
||||||
|
foot MIT meson.build: license: 'MIT'
|
||||||
giflib MIT COPYING (texto de MIT)
|
giflib MIT COPYING (texto de MIT)
|
||||||
|
glab MIT LICENSE (texto de MIT)
|
||||||
go BSD-3-Clause LICENSE (texto de BSD-3-Clause)
|
go BSD-3-Clause LICENSE (texto de BSD-3-Clause)
|
||||||
gtk4-hello LGPL-2.1-or-later meson.build: license: 'LGPL-2.1-or-later'
|
gtk4-hello LGPL-2.1-or-later meson.build: license: 'LGPL-2.1-or-later'
|
||||||
hammer-edit LGPL-2.1-or-later meson.build: license: 'LGPL-2.1-or-later'
|
hammer-edit LGPL-2.1-or-later meson.build: license: 'LGPL-2.1-or-later'
|
||||||
|
hammerd MIT el repo es el propio hammer: LICENSE (MIT License) + Cargo.toml: license = "MIT"
|
||||||
intltool GPL-2.0-or-later COPYING + concesión en intltool-extract.in: …on; either version 2 of the # License, or (at your option) any later version. # # Intltool is d…
|
intltool GPL-2.0-or-later COPYING + concesión en intltool-extract.in: …on; either version 2 of the # License, or (at your option) any later version. # # Intltool is d…
|
||||||
json-c MIT COPYING (texto de MIT)
|
json-c MIT COPYING (texto de MIT)
|
||||||
libogg BSD-3-Clause COPYING (texto de BSD-3-Clause)
|
libogg BSD-3-Clause COPYING (texto de BSD-3-Clause)
|
||||||
@@ -28,6 +32,7 @@ mtdev MIT COPYING (texto de MIT)
|
|||||||
nano GPL-3.0-or-later COPYING + concesión en NEWS: …Finally, nano is now licensed under the GNU GPL version 3 or later, and its documentat…
|
nano GPL-3.0-or-later COPYING + concesión en NEWS: …Finally, nano is now licensed under the GNU GPL version 3 or later, and its documentat…
|
||||||
nghttp2 MIT COPYING (texto de MIT)
|
nghttp2 MIT COPYING (texto de MIT)
|
||||||
pcre2-shared BSD-3-Clause LICENCE.md (texto de BSD-3-Clause)
|
pcre2-shared BSD-3-Clause LICENCE.md (texto de BSD-3-Clause)
|
||||||
|
portal-probe MIT el repo es el propio hammer: LICENSE (MIT License) + Cargo.toml: license = "MIT"
|
||||||
scdoc MIT COPYING (texto de MIT)
|
scdoc MIT COPYING (texto de MIT)
|
||||||
seatd MIT meson.build: license: 'MIT'
|
seatd MIT meson.build: license: 'MIT'
|
||||||
socat GPL-2.0-or-later COPYING + concesión en socat_buildscript_for_android.sh: …; either version 2.1 of the License, or (at your option) any later version. The GNU C Libr…
|
socat GPL-2.0-or-later COPYING + concesión en socat_buildscript_for_android.sh: …; either version 2.1 of the License, or (at your option) any later version. The GNU C Libr…
|
||||||
@@ -35,5 +40,3 @@ sourceview-hello LGPL-2.1-or-later meson.build: license: 'LGPL-2.1-or-later'
|
|||||||
speexdsp BSD-3-Clause COPYING (texto de BSD-3-Clause)
|
speexdsp BSD-3-Clause COPYING (texto de BSD-3-Clause)
|
||||||
tea MIT LICENSE (texto de MIT)
|
tea MIT LICENSE (texto de MIT)
|
||||||
tllist MIT meson.build: license: 'MIT'
|
tllist MIT meson.build: license: 'MIT'
|
||||||
hammerd MIT el repo es el propio hammer: LICENSE (MIT License) + Cargo.toml: license = "MIT"
|
|
||||||
portal-probe MIT el repo es el propio hammer: LICENSE (MIT License) + Cargo.toml: license = "MIT"
|
|
||||||
|
|||||||
|
Can't render this file because it contains an unexpected character in line 19 and column 88.
|
@@ -3,6 +3,7 @@
|
|||||||
# harfbuzz/pixman (canónicas). Último eslabón antes del terminal foot. meson, lib estática.
|
# harfbuzz/pixman (canónicas). Último eslabón antes del terminal foot. meson, lib estática.
|
||||||
name = "fcft"
|
name = "fcft"
|
||||||
version = "3.3.3"
|
version = "3.3.3"
|
||||||
|
license = "MIT"
|
||||||
|
|
||||||
[source]
|
[source]
|
||||||
# Fuente GIT por commit, no el archive de codeberg (ADR 0006). El `/archive/3.3.3.tar.gz` lo genera
|
# Fuente GIT por commit, no el archive de codeberg (ADR 0006). El `/archive/3.3.3.tar.gz` lo genera
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
# pixman/fontconfig/freetype/harfbuzz/libxkbcommon/ncurses (canónicas). Sin PGO (evita cage).
|
# pixman/fontconfig/freetype/harfbuzz/libxkbcommon/ncurses (canónicas). Sin PGO (evita cage).
|
||||||
name = "foot"
|
name = "foot"
|
||||||
version = "1.27.0"
|
version = "1.27.0"
|
||||||
|
license = "MIT"
|
||||||
|
|
||||||
[source]
|
[source]
|
||||||
# Fuente GIT por commit, no el archive de codeberg (ADR 0006), por lo mismo que fcft: el
|
# Fuente GIT por commit, no el archive de codeberg (ADR 0006), por lo mismo que fcft: el
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
# El repo tiene varios mains (cmd/glab, cmd/gen-docs); fijamos ./cmd/glab explícito.
|
# El repo tiene varios mains (cmd/glab, cmd/gen-docs); fijamos ./cmd/glab explícito.
|
||||||
name = "glab"
|
name = "glab"
|
||||||
version = "1.102.0"
|
version = "1.102.0"
|
||||||
|
license = "MIT"
|
||||||
|
|
||||||
[source]
|
[source]
|
||||||
repo = "https://gitlab.com/gitlab-org/cli"
|
repo = "https://gitlab.com/gitlab-org/cli"
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
"""licencias-tarball.py — deduce el SPDX de una receta desde SU PROPIO tarball pineado, offline.
|
"""licencias-fuente.py — deduce el SPDX de una receta desde SU PROPIA fuente pineada.
|
||||||
|
|
||||||
── QUÉ AÑADE SOBRE LOS HERMANOS ────────────────────────────────────────────────────────────────
|
── QUÉ AÑADE SOBRE LOS HERMANOS ────────────────────────────────────────────────────────────────
|
||||||
`licencias.sh --sembrar` escribe desde una tabla curada a mano, y `licencias-desambiguar.sh`
|
`licencias.sh --sembrar` escribe desde una tabla curada a mano, y `licencias-desambiguar.sh`
|
||||||
@@ -8,7 +8,8 @@ fuera lo mismo: lo que no está en la tabla y lo que no vive en GitHub.
|
|||||||
|
|
||||||
Pero `work/tarballs/` guarda cada tarball indexado por su **sha256**, o sea que el árbol EXACTO que
|
Pero `work/tarballs/` guarda cada tarball indexado por su **sha256**, o sea que el árbol EXACTO que
|
||||||
la receta pinea ya está en disco. La evidencia más fuerte posible —la declaración del propio autor
|
la receta pinea ya está en disco. La evidencia más fuerte posible —la declaración del propio autor
|
||||||
en el commit que construimos— no necesita red: necesita abrir el tar.
|
en el commit que construimos— no necesita red: necesita abrir el tar. Y para las recetas de fuente
|
||||||
|
git, el `commit` pineado cumple el mismo papel que el sha256: se lee sin clonar el árbol entero.
|
||||||
|
|
||||||
── LA JERARQUÍA DE EVIDENCIA, DE MÁS FUERTE A MÁS DÉBIL ────────────────────────────────────────
|
── LA JERARQUÍA DE EVIDENCIA, DE MÁS FUERTE A MÁS DÉBIL ────────────────────────────────────────
|
||||||
1. `Cargo.toml` / `meson.build` de la raíz. El autor declara el SPDX él mismo, en el formato
|
1. `Cargo.toml` / `meson.build` de la raíz. El autor declara el SPDX él mismo, en el formato
|
||||||
@@ -32,15 +33,15 @@ veredicto sale como `pendiente` con lo que SÍ se encontró, para que el humano
|
|||||||
NADA se escribe en las recetas: la salida es un TSV que revisa una persona y siembra `licencias.sh`.
|
NADA se escribe en las recetas: la salida es un TSV que revisa una persona y siembra `licencias.sh`.
|
||||||
|
|
||||||
── EL MODO `--fetch` ───────────────────────────────────────────────────────────────────────────
|
── EL MODO `--fetch` ───────────────────────────────────────────────────────────────────────────
|
||||||
Por defecto NO toca la red: mira sólo lo que ya está en `work/tarballs/`. Con `--fetch` baja los
|
Por defecto NO toca la red: mira sólo lo que ya está en `work/tarballs/`. Con `--fetch` trae a un
|
||||||
tarballs que faltan a un temporal, los verifica por sha256 —el mismo sha que la receta pinea, así
|
temporal lo que falte —tarballs y fuentes git—, verifica el tarball por sha256 —el mismo sha que la receta pinea, así
|
||||||
que o es el árbol exacto o no se mira— y los borra al terminar. No escribe en la caché de hammer a
|
que o es el árbol exacto o no se mira— y los borra al terminar. No escribe en la caché de hammer a
|
||||||
propósito: la caché es suya y un fichero puesto ahí por otro camino es una vía de envenenamiento
|
propósito: la caché es suya y un fichero puesto ahí por otro camino es una vía de envenenamiento
|
||||||
que nadie audita.
|
que nadie audita.
|
||||||
|
|
||||||
Uso: scripts/licencias-tarball.py informe + escribe docs/licencias-evidencia.tsv
|
Uso: scripts/licencias-fuente.py informe + escribe docs/licencias-evidencia.tsv
|
||||||
scripts/licencias-tarball.py --fetch además baja los tarballs que falten (red)
|
scripts/licencias-fuente.py --fetch además trae las fuentes que falten (red)
|
||||||
scripts/licencias-tarball.py <receta> una sola, con el detalle a la vista
|
scripts/licencias-fuente.py <receta> una sola, con el detalle a la vista
|
||||||
"""
|
"""
|
||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
@@ -226,8 +227,67 @@ def declaracion_del_autor(ruta, texto):
|
|||||||
return None, None
|
return None, None
|
||||||
|
|
||||||
|
|
||||||
def analizar(tar_path):
|
def miembros_de_tar(tar_path):
|
||||||
"""Un solo recorrido del tar. Devuelve (spdx, cita) o (None, pista)."""
|
"""(ruta relativa a la raíz, bytes) de cada fichero del tar. Un solo recorrido, en streaming."""
|
||||||
|
try:
|
||||||
|
tf = tarfile.open(tar_path, "r:*")
|
||||||
|
except Exception as e:
|
||||||
|
raise RuntimeError(f"no se pudo abrir el tar: {e}")
|
||||||
|
with tf:
|
||||||
|
for i, m in enumerate(tf):
|
||||||
|
if i > MAX_MIEMBROS:
|
||||||
|
break
|
||||||
|
if not m.isfile() or m.size > MAX_BYTES:
|
||||||
|
continue
|
||||||
|
rel = sin_prefijo(m.name)
|
||||||
|
if not rel:
|
||||||
|
continue
|
||||||
|
try:
|
||||||
|
yield rel, tf.extractfile(m).read()
|
||||||
|
except Exception:
|
||||||
|
continue
|
||||||
|
|
||||||
|
|
||||||
|
def miembros_de_git(repo, commit, tmp):
|
||||||
|
"""Igual, pero desde un repo git, SIN clonar el árbol entero.
|
||||||
|
|
||||||
|
`--depth 1 --filter=blob:limit=64k` sobre el commit PINEADO: trae la historia de un solo commit
|
||||||
|
y sólo los blobs chicos. Un COPYING nunca pasa de 64k, y los fuentes donde vive la concesión
|
||||||
|
tampoco — los que sí (binarios, assets) son justo los que no interesan. Así una receta cuyo
|
||||||
|
árbol pesa cientos de megas se resuelve con unos pocos.
|
||||||
|
"""
|
||||||
|
ejecutar = lambda *a: subprocess.run(a, cwd=tmp, capture_output=True, text=False)
|
||||||
|
subprocess.run(["git", "init", "-q", tmp], capture_output=True)
|
||||||
|
ejecutar("git", "remote", "add", "origin", repo)
|
||||||
|
r = ejecutar("git", "fetch", "-q", "--depth", "1", "--filter=blob:limit=64k", "origin", commit)
|
||||||
|
if r.returncode != 0:
|
||||||
|
raise RuntimeError("git fetch falló: "
|
||||||
|
+ r.stderr.decode("utf-8", "replace").strip()[:100])
|
||||||
|
r = ejecutar("git", "ls-tree", "-r", "-z", "--long", "FETCH_HEAD")
|
||||||
|
if r.returncode != 0:
|
||||||
|
raise RuntimeError("git ls-tree falló")
|
||||||
|
n = 0
|
||||||
|
for reg in r.stdout.decode("utf-8", "replace").split("\0"):
|
||||||
|
if not reg or n > MAX_MIEMBROS:
|
||||||
|
break
|
||||||
|
meta, _, rel = reg.partition("\t")
|
||||||
|
campos = meta.split()
|
||||||
|
# <modo> <tipo> <sha> <tamaño>
|
||||||
|
if len(campos) < 4 or campos[1] != "blob":
|
||||||
|
continue
|
||||||
|
try:
|
||||||
|
if campos[3] != "-" and int(campos[3]) > MAX_BYTES:
|
||||||
|
continue
|
||||||
|
except ValueError:
|
||||||
|
pass
|
||||||
|
b = ejecutar("git", "cat-file", "blob", campos[2])
|
||||||
|
if b.returncode == 0:
|
||||||
|
n += 1
|
||||||
|
yield rel, b.stdout
|
||||||
|
|
||||||
|
|
||||||
|
def analizar(miembros):
|
||||||
|
"""Un solo recorrido de la fuente. Devuelve (spdx, cita) o (None, pista)."""
|
||||||
autor = None
|
autor = None
|
||||||
reuse = [] # ficheros de LICENSES/ (convención REUSE: el nombre ES el SPDX)
|
reuse = [] # ficheros de LICENSES/ (convención REUSE: el nombre ES el SPDX)
|
||||||
candidatos = [] # (prioridad, ruta, texto) de los ficheros de licencia de la RAÍZ
|
candidatos = [] # (prioridad, ruta, texto) de los ficheros de licencia de la RAÍZ
|
||||||
@@ -239,19 +299,7 @@ def analizar(tar_path):
|
|||||||
spdx_headers = {}
|
spdx_headers = {}
|
||||||
|
|
||||||
try:
|
try:
|
||||||
tf = tarfile.open(tar_path, "r:*")
|
for rel, datos in miembros:
|
||||||
except Exception as e:
|
|
||||||
return None, f"no se pudo abrir el tar: {e}"
|
|
||||||
|
|
||||||
with tf:
|
|
||||||
for i, m in enumerate(tf):
|
|
||||||
if i > MAX_MIEMBROS:
|
|
||||||
break
|
|
||||||
if not m.isfile() or m.size > MAX_BYTES:
|
|
||||||
continue
|
|
||||||
rel = sin_prefijo(m.name)
|
|
||||||
if not rel:
|
|
||||||
continue
|
|
||||||
base = os.path.basename(rel)
|
base = os.path.basename(rel)
|
||||||
|
|
||||||
if rel.startswith("LICENSES/"):
|
if rel.startswith("LICENSES/"):
|
||||||
@@ -273,11 +321,6 @@ def analizar(tar_path):
|
|||||||
if not (interesa_autor or es_licencia or es_fuente):
|
if not (interesa_autor or es_licencia or es_fuente):
|
||||||
continue
|
continue
|
||||||
|
|
||||||
try:
|
|
||||||
datos = tf.extractfile(m).read()
|
|
||||||
except Exception:
|
|
||||||
continue
|
|
||||||
|
|
||||||
if interesa_autor and autor is None:
|
if interesa_autor and autor is None:
|
||||||
lic, cita = declaracion_del_autor(rel, datos.decode("utf-8", "replace"))
|
lic, cita = declaracion_del_autor(rel, datos.decode("utf-8", "replace"))
|
||||||
if lic:
|
if lic:
|
||||||
@@ -309,6 +352,9 @@ def analizar(tar_path):
|
|||||||
if mm:
|
if mm:
|
||||||
cita_only = f"{rel}: …{texto[max(0, mm.start()-60):mm.end()+20].strip()}…"
|
cita_only = f"{rel}: …{texto[max(0, mm.start()-60):mm.end()+20].strip()}…"
|
||||||
|
|
||||||
|
except RuntimeError as e:
|
||||||
|
return None, str(e)
|
||||||
|
|
||||||
if candidatos:
|
if candidatos:
|
||||||
# Se identifica CADA fichero de la raíz y se unen los resultados. Que haya varios no es
|
# Se identifica CADA fichero de la raíz y se unen los resultados. Que haya varios no es
|
||||||
# ambigüedad por sí solo: el `COPYING` de pcre2 son dos líneas que apuntan a `LICENCE.md`,
|
# ambigüedad por sí solo: el `COPYING` de pcre2 son dos líneas que apuntan a `LICENCE.md`,
|
||||||
@@ -408,23 +454,42 @@ def main():
|
|||||||
nombre = d["name"]
|
nombre = d["name"]
|
||||||
if objetivo and nombre != objetivo and os.path.basename(f) != objetivo:
|
if objetivo and nombre != objetivo and os.path.basename(f) != objetivo:
|
||||||
continue
|
continue
|
||||||
sha = d.get("source", {}).get("sha256")
|
src = d.get("source", {})
|
||||||
|
sha = src.get("sha256")
|
||||||
if not sha:
|
if not sha:
|
||||||
sin_tar.append((nombre, "fuente git/dir: no hay tarball que mirar"))
|
# ── Fuente git: el commit pineado ES la evidencia, igual que un sha256 ──────────────
|
||||||
continue
|
repo, commit = src.get("repo"), src.get("commit")
|
||||||
tar_path = os.path.join(CACHE, sha + ".tar")
|
if not (repo and commit):
|
||||||
if not os.path.exists(tar_path):
|
sin_tar.append((nombre, "fuente sin tarball ni repo/commit"))
|
||||||
url = d.get("source", {}).get("tarball")
|
|
||||||
if not (con_red and url):
|
|
||||||
sin_tar.append((nombre, "tarball no cacheado"
|
|
||||||
+ ("" if con_red else " (probá --fetch)")))
|
|
||||||
continue
|
continue
|
||||||
tar_path = os.path.join(tmp, sha)
|
if repo.startswith(("ssh://", "git@")):
|
||||||
fallo = bajar_verificado(url, sha, tar_path)
|
# El fetch de este script es anónimo; un repo por SSH necesita claves que no tiene.
|
||||||
if fallo:
|
sin_tar.append((nombre, "repo por SSH: este script no autentica"))
|
||||||
sin_tar.append((nombre, fallo))
|
|
||||||
continue
|
continue
|
||||||
spdx, cita = analizar(tar_path)
|
if not con_red:
|
||||||
|
sin_tar.append((nombre, "fuente git (probá --fetch)"))
|
||||||
|
continue
|
||||||
|
sub = os.path.join(tmp, nombre + "-git")
|
||||||
|
os.makedirs(sub, exist_ok=True)
|
||||||
|
try:
|
||||||
|
spdx, cita = analizar(miembros_de_git(repo, commit, sub))
|
||||||
|
except RuntimeError as e:
|
||||||
|
sin_tar.append((nombre, str(e)))
|
||||||
|
continue
|
||||||
|
else:
|
||||||
|
tar_path = os.path.join(CACHE, sha + ".tar")
|
||||||
|
if not os.path.exists(tar_path):
|
||||||
|
url = src.get("tarball")
|
||||||
|
if not (con_red and url):
|
||||||
|
sin_tar.append((nombre, "tarball no cacheado"
|
||||||
|
+ ("" if con_red else " (probá --fetch)")))
|
||||||
|
continue
|
||||||
|
tar_path = os.path.join(tmp, sha)
|
||||||
|
fallo = bajar_verificado(url, sha, tar_path)
|
||||||
|
if fallo:
|
||||||
|
sin_tar.append((nombre, fallo))
|
||||||
|
continue
|
||||||
|
spdx, cita = analizar(miembros_de_tar(tar_path))
|
||||||
if spdx:
|
if spdx:
|
||||||
filas.append((nombre, spdx, una_linea(cita)))
|
filas.append((nombre, spdx, una_linea(cita)))
|
||||||
else:
|
else:
|
||||||
@@ -456,14 +521,14 @@ def main():
|
|||||||
previas[n] = (n, sp, c)
|
previas[n] = (n, sp, c)
|
||||||
|
|
||||||
with open(SALIDA, "w") as fh:
|
with open(SALIDA, "w") as fh:
|
||||||
fh.write("# licencias-evidencia.tsv — lo generó scripts/licencias-tarball.py desde el\n")
|
fh.write("# licencias-evidencia.tsv — lo generó scripts/licencias-fuente.py desde el\n")
|
||||||
fh.write("# TARBALL PINEADO de cada receta. Tres columnas: paquete, SPDX, y la CITA que lo\n")
|
fh.write("# TARBALL PINEADO de cada receta. Tres columnas: paquete, SPDX, y la CITA que lo\n")
|
||||||
fh.write("# decidió. REVISAR A MANO antes de sembrar: es evidencia, no un veredicto firmado.\n")
|
fh.write("# decidió. REVISAR A MANO antes de sembrar: es evidencia, no un veredicto firmado.\n")
|
||||||
fh.write("# Se ACUMULA: las filas de lo ya sembrado se conservan como rastro de auditoría.\n")
|
fh.write("# Se ACUMULA: las filas de lo ya sembrado se conservan como rastro de auditoría.\n")
|
||||||
for fila in sorted(previas.values()):
|
for fila in sorted(previas.values()):
|
||||||
fh.write("\t".join(fila) + "\n")
|
fh.write("\t".join(fila) + "\n")
|
||||||
|
|
||||||
print(f"==> resueltas con evidencia del tarball: {len(filas)}")
|
print(f"==> resueltas con evidencia de la fuente: {len(filas)}")
|
||||||
for n, s, c in filas:
|
for n, s, c in filas:
|
||||||
print(f" {n:28s} {s:34s} {c[:70]}")
|
print(f" {n:28s} {s:34s} {c[:70]}")
|
||||||
print(f"\n==> pendientes (hay tarball pero no alcanza para afirmar): {len(pendientes)}")
|
print(f"\n==> pendientes (hay tarball pero no alcanza para afirmar): {len(pendientes)}")
|
||||||
Reference in New Issue
Block a user