version turbo y version .go
This commit is contained in:
1 parent
778b286369
commit
4e0067a368
9 files changed
+395
No files matched your search
@@ -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
|
||||||
|
|
||||||
@@ -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
@@ -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
|
||||||
Binary file not shown.
Binary file not shown.
+143
@@ -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
Binary file not shown.
BIN
Binary file not shown.
+98
@@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in new issue
Block a user