diff --git a/compila-go.sh b/compila-go.sh new file mode 100644 index 0000000..a835bb1 --- /dev/null +++ b/compila-go.sh @@ -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 + diff --git a/pip_busca-turbo b/pip_busca-turbo new file mode 100644 index 0000000..1536c74 --- /dev/null +++ b/pip_busca-turbo @@ -0,0 +1,37 @@ +#!/usr/bin/env python3 +import sys +import requests + +if len(sys.argv) < 2: + print("Uso: pip_busca ") + 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: Nombre + if "")[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.") diff --git a/pip_info-turbo b/pip_info-turbo new file mode 100644 index 0000000..eada45a --- /dev/null +++ b/pip_info-turbo @@ -0,0 +1,107 @@ +#!/bin/bash +# pip_info v2.0 — Luis GuLo Edition + +mostrar_ayuda() { + echo "═══════════════════════════════════════════════════════════════════════" + echo "Uso: $0 [--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 diff --git a/pipbusca.bin b/pipbusca.bin new file mode 100644 index 0000000..a2c8df2 Binary files /dev/null and b/pipbusca.bin differ diff --git a/pipbusca.exe b/pipbusca.exe new file mode 100644 index 0000000..e82f400 Binary files /dev/null and b/pipbusca.exe differ diff --git a/pipbusca.go b/pipbusca.go new file mode 100644 index 0000000..4b53214 --- /dev/null +++ b/pipbusca.go @@ -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 ... + 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] ") + 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, "") { + 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.") + } +} diff --git a/pipinfo.bin b/pipinfo.bin new file mode 100644 index 0000000..c9da961 Binary files /dev/null and b/pipinfo.bin differ diff --git a/pipinfo.exe b/pipinfo.exe new file mode 100644 index 0000000..ecec389 Binary files /dev/null and b/pipinfo.exe differ diff --git a/pipinfo.go b/pipinfo.go new file mode 100644 index 0000000..2b364b9 --- /dev/null +++ b/pipinfo.go @@ -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 [--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 + } + } + } + } +}