version turbo y version .go

This commit is contained in:
Luis Gutierrez Lopez 2026-02-23 13:05:16 +01:00
parent 778b286369
commit 4e0067a368
9 changed files with 395 additions and 0 deletions

10
compila-go.sh Normal file
View File

@ -0,0 +1,10 @@
#!/bin/bash
echo "Compilando version Linux:"
GO111MODULE=off GOOS=linux GOARCH=amd64 go build -o pipinfo.bin pipinfo.go
GO111MODULE=off GOOS=linux GOARCH=amd64 go build -o pipbusca.bin pipbusca.go
echo
echo "Compilando version Windows:"
GO111MODULE=off GOOS=windows GOARCH=amd64 go build -o pipinfo.exe pipinfo.go
GO111MODULE=off GOOS=windows GOARCH=amd64 go build -o pipbusca.exe pipbusca.go
echo

37
pip_busca-turbo Normal file
View File

@ -0,0 +1,37 @@
#!/usr/bin/env python3
import sys
import requests
if len(sys.argv) < 2:
print("Uso: pip_busca <cadena>")
sys.exit(1)
query = sys.argv[1].lower()
url = "https://pypi.org/simple/"
# Descarga en streaming (sin cargar todo en memoria)
resp = requests.get(url, stream=True)
if resp.status_code != 200:
print("❌ Error al descargar índice de PyPI")
sys.exit(1)
print(f"🔍 Buscando: {query}\n")
encontrados = 0
max_resultados = 50 # configurable
for line in resp.iter_lines(decode_unicode=True):
if not line:
continue
# Las líneas tienen formato: <a href="...">Nombre</a>
if "<a href=" in line.lower():
nombre = line.split(">")[1].split("<")[0]
if query in nombre.lower():
print(f"📦 {nombre}")
encontrados += 1
if encontrados >= max_resultados:
break
if encontrados == 0:
print("❌ No se encontraron paquetes.")

107
pip_info-turbo Normal file
View File

@ -0,0 +1,107 @@
#!/bin/bash
# pip_info v2.0 — Luis GuLo Edition
mostrar_ayuda() {
echo "═══════════════════════════════════════════════════════════════════════"
echo "Uso: $0 <paquete> [--all] [--json]"
echo ""
echo "Opciones:"
echo " --all Mostrar TODAS las versiones (incluye pre-release)"
echo " --json Salida en JSON puro"
echo ""
echo "Por defecto muestra las 10 últimas versiones estables."
echo "═══════════════════════════════════════════════════════════════════════"
}
# ----------------------
# Validación de argumentos
# ----------------------
if [[ "$1" == "--help" || "$1" == "-h" ]]; then
mostrar_ayuda
exit 0
fi
if [ -z "$1" ]; then
echo "❌ Error: Debe indicar el nombre del paquete."
mostrar_ayuda
exit 1
fi
PAQUETE="$1"
FLAG_ALL="$2"
FLAG_JSON="$3"
URL="https://pypi.org/pypi/$PAQUETE/json"
RESPUESTA=$(curl -s "$URL")
# ----------------------
# Validación del JSON
# ----------------------
if ! echo "$RESPUESTA" | jq empty 2>/dev/null; then
echo "❌ PyPI devolvió una respuesta no válida (¿paquete inexistente?)."
exit 1
fi
if ! echo "$RESPUESTA" | jq -e '.info.name' >/dev/null; then
echo "❌ No se encontró información para '$PAQUETE'"
exit 1
fi
# Salida JSON pura
if [[ "$FLAG_ALL" == "--json" || "$FLAG_JSON" == "--json" ]]; then
echo "$RESPUESTA"
exit 0
fi
# ----------------------
# Obtener campos principales
# ----------------------
NOMBRE=$(echo "$RESPUESTA" | jq -r '.info.name')
VERSION=$(echo "$RESPUESTA" | jq -r '.info.version')
DESCRIPCION=$(echo "$RESPUESTA" | jq -r '.info.summary')
echo "📦 Paquete: $NOMBRE"
echo "🔢 Última versión: $VERSION"
echo "📝 Descripción: $DESCRIPCION"
echo
# ----------------------
# Funciones para listar versiones
# ----------------------
mostrar_estables() {
echo "📚 Últimas 10 versiones ESTABLES:"
echo
echo "$RESPUESTA" \
| jq -r '.releases | keys[]' \
| grep -E '^[0-9]+\.[0-9]+\.[0-9]+$' \
| sort -V -r \
| head -n 10 \
| while read v; do
PY=$(echo "$RESPUESTA" | jq -r ".releases[\"$v\"][0].requires_python // \"N/A\"")
printf " %-15s (Python %s)\n" "$v" "$PY"
done
}
mostrar_todas() {
echo "📚 Todas las versiones:"
echo
echo "$RESPUESTA" \
| jq -r '.releases | keys[]' \
| sort -V -r \
| while read v; do
PY=$(echo "$RESPUESTA" | jq -r ".releases[\"$v\"][0].requires_python // \"N/A\"")
printf " %-15s (Python %s)\n" "$v" "$PY"
done
}
# ----------------------
# Selección del modo
# ----------------------
if [[ "$FLAG_ALL" == "--all" ]]; then
mostrar_todas
else
mostrar_estables
fi

BIN
pipbusca.bin Normal file

Binary file not shown.

BIN
pipbusca.exe Normal file

Binary file not shown.

143
pipbusca.go Normal file
View File

@ -0,0 +1,143 @@
package main
import (
"bufio"
"flag"
"fmt"
"net/http"
"os"
"strings"
"time"
)
func extractAnchorText(line string) (string, bool) {
// Busca el texto entre > y < del primer <a ...>...</a>
gt := strings.Index(line, ">")
if gt == -1 {
return "", false
}
lt := strings.Index(line[gt+1:], "<")
if lt == -1 {
return "", false
}
text := line[gt+1 : gt+1+lt]
text = strings.TrimSpace(text)
if text == "" {
return "", false
}
return text, true
}
func main() {
// Flags
maxResults := flag.Int("max", 30, "Número máximo de resultados a mostrar")
prefix := flag.Bool("prefix", false, "Buscar por prefijo en lugar de subcadena")
timeout := flag.Duration("timeout", 20*time.Second, "Timeout de la petición HTTP (e.g., 10s, 2m)")
noColor := flag.Bool("nocolor", false, "Desactivar iconos/colores")
flag.Parse()
if flag.NArg() < 1 {
fmt.Println("Uso: pip_busca [opciones] <cadena_busqueda>")
fmt.Println("Opciones:")
fmt.Println(" -max N Limitar el número de resultados (por defecto 30)")
fmt.Println(" -prefix Coincidencia por prefijo (más rápida si buscas por inicio)")
fmt.Println(" -timeout DUR Timeout de HTTP (por defecto 20s)")
fmt.Println(" -nocolor Desactiva iconos/colores en salida")
os.Exit(1)
}
query := strings.ToLower(flag.Arg(0))
url := "https://pypi.org/simple/"
client := &http.Client{Timeout: *timeout}
req, err := http.NewRequest("GET", url, nil)
if err != nil {
fmt.Fprintf(os.Stderr, "❌ Error creando petición: %v\n", err)
os.Exit(1)
}
req.Header.Set("User-Agent", "pip_busca-go/1.0 (+https://pypi.org)")
req.Header.Set("Accept", "text/html")
resp, err := client.Do(req)
if err != nil {
fmt.Fprintf(os.Stderr, "❌ Error conectando con PyPI: %v\n", err)
os.Exit(1)
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
fmt.Fprintf(os.Stderr, "❌ Respuesta HTTP no OK: %s\n", resp.Status)
os.Exit(1)
}
if !*noColor {
fmt.Printf("🔍 Buscando: %s\n\n", query)
} else {
fmt.Printf("Buscando: %s\n\n", query)
}
scanner := bufio.NewScanner(resp.Body)
// Aumenta el buffer por si alguna línea es grande (aunque en /simple suele ser pequeño)
const maxLine = 1024 * 1024 // 1 MiB
buf := make([]byte, 64*1024)
scanner.Buffer(buf, maxLine)
encontrados := 0
queryStarted := false // para modo -prefix: romper cuando superemos el bloque
for scanner.Scan() {
line := scanner.Text()
// Normalizamos a minúsculas para buscar
lower := strings.ToLower(line)
// Solo nos interesan líneas con anclas
if !strings.Contains(lower, "<a ") || !strings.Contains(lower, "</a>") {
continue
}
name, ok := extractAnchorText(line)
if !ok {
continue
}
nameLower := strings.ToLower(name)
match := false
if *prefix {
// Coincidencia por prefijo
if strings.HasPrefix(nameLower, query) {
match = true
queryStarted = true
} else if queryStarted {
// /simple/ está ordenado; si ya pasamos el bloque del prefijo, podemos cortar.
// Cuando el nombre actual ya no empieza por el prefijo y ya habíamos empezado
// a encontrar coincidencias, significa que hemos superado la zona.
break
}
} else {
// Coincidencia por subcadena
if strings.Contains(nameLower, query) {
match = true
}
}
if match {
if !*noColor {
fmt.Printf("📦 %s\n", name)
} else {
fmt.Println(name)
}
encontrados++
if encontrados >= *maxResults {
break
}
}
}
if err := scanner.Err(); err != nil {
fmt.Fprintf(os.Stderr, "⚠️ Aviso: error leyendo la respuesta: %v\n", err)
}
if encontrados == 0 {
fmt.Println("❌ No se encontraron paquetes.")
}
}

BIN
pipinfo.bin Normal file

Binary file not shown.

BIN
pipinfo.exe Normal file

Binary file not shown.

98
pipinfo.go Normal file
View File

@ -0,0 +1,98 @@
package main
import (
"encoding/json"
"fmt"
"net/http"
"os"
"regexp"
"sort"
)
type ReleaseInfo struct {
RequiresPython string `json:"requires_python"`
}
type PackageInfo struct {
Info struct {
Name string `json:"name"`
Version string `json:"version"`
Summary string `json:"summary"`
} `json:"info"`
Releases map[string][]ReleaseInfo `json:"releases"`
}
func main() {
if len(os.Args) < 2 {
fmt.Println("Uso: pipinfo <paquete> [--all]")
return
}
pkg := os.Args[1]
showAll := len(os.Args) > 2 && os.Args[2] == "--all"
url := fmt.Sprintf("https://pypi.org/pypi/%s/json", pkg)
resp, err := http.Get(url)
if err != nil {
fmt.Printf("❌ Error de conexión: %v\n", err)
return
}
defer resp.Body.Close()
if resp.StatusCode != 200 {
fmt.Printf("❌ No se encontró el paquete '%s'\n", pkg)
return
}
var data PackageInfo
if err := json.NewDecoder(resp.Body).Decode(&data); err != nil {
fmt.Printf("❌ Error procesando JSON: %v\n", err)
return
}
fmt.Printf("📦 Paquete: %s\n", data.Info.Name)
fmt.Printf("🔢 Última versión: %s\n", data.Info.Version)
fmt.Printf("📝 Descripción: %s\n\n", data.Info.Summary)
// Obtener lista de versiones
versions := make([]string, 0, len(data.Releases))
for v := range data.Releases {
versions = append(versions, v)
}
sort.Slice(versions, func(i, j int) bool {
return versions[i] > versions[j]
})
stableRegex := regexp.MustCompile(`^[0-9]+\.[0-9]+\.[0-9]+$`)
count := 0
if showAll {
fmt.Println("📚 Todas las versiones:")
for _, v := range versions {
req := "N/A"
if len(data.Releases[v]) > 0 && data.Releases[v][0].RequiresPython != "" {
req = data.Releases[v][0].RequiresPython
}
fmt.Printf(" %-12s (Python %s)\n", v, req)
}
} else {
fmt.Println("📚 Últimas 10 versiones estables:\n")
for _, v := range versions {
if stableRegex.MatchString(v) {
req := "N/A"
if len(data.Releases[v]) > 0 && data.Releases[v][0].RequiresPython != "" {
req = data.Releases[v][0].RequiresPython
}
fmt.Printf(" %-12s (Python %s)\n", v, req)
count++
if count == 10 {
break
}
}
}
}
}