Código de Elisp para verificar la conexión a internet

13

Cuando abro Emacs, evalúa mi archivo de inicio, que incluye la actualización de mis archivos de paquetes a través de una conexión a Internet. Esto es problemático cuando no tengo una conexión a Internet, por lo tanto, necesito evitar la ejecución de ese código al iniciar Emacs sin una conexión a Internet. Para resolver este problema, me pregunto si hay una manera de hacer que Emacs ignore el código de actualización del paquete cuando no tengo una conexión a Internet.

Aquí están las primeras líneas de mi init.el:

;; Requisites: Emacs >= 24
(require 'package)
(package-initialize)

;; PACKAGE MANAGEMENT
(add-to-list 'package-archives 
  '("melpa" . "http://melpa.milkbox.net/packages/") t)

(package-refresh-contents)       

Me imagino que puedo agregar código para cargar mi archivo Emacs de la siguiente manera:

;; Requisites: Emacs >= 24
(when (connected-to-internet-p)   ; I need this predicate function
  (require 'package)
  (package-initialize)
  (add-to-list 'package-archives 
               '("melpa" . "http://melpa.milkbox.net/packages/") t)
  (package-refresh-contents))

¿Existe una (connected-to-internet)función, o un enfoque similar, para resolver este problema?

modulitos
fuente
2
Hay una respuesta relacionada aquí stackoverflow.com/a/21065704/3170376 .
Nombre el
2
¿Por qué desea actualizar los archivos del paquete cuando inicia Emacs?
phils
@Name Eso es más que relacionado. Es la respuesta (suponiendo que funcione).
Malabarba
1
Le recomiendo encarecidamente que no ejecute package-refresh-content en cada inicio. Es muy probable que necesite ejecutarlo una vez cuando primero baje su configuración en una nueva máquina y luego no la vuelva a necesitar durante meses. Hacerlo cuando tienes una conexión es la respuesta incorrecta a este problema, el verdadero problema es que lo estás ejecutando cuando no es necesario.
Jordon Biondo

Respuestas:

7

Bueno, si aún desea actualizar el contenido automáticamente, siempre que sea posible, puede hacer algo como el código a continuación:

(defun can-retreive-packages ()
  (cl-loop for url in '("http://marmalade-repo.org/packages/"
                        "http://melpa.milkbox.net/packages/"
                        "http://elpa.gnu.org/packages/")
           do (condition-case e
                  (kill-buffer (url-retrieve-synchronously url))
                (error (cl-return)))
           finally (cl-return t)))

Pocas notas se deben:

  1. Esto es lento y será lento cuando se inicie normalmente, así que prefiero hacerlo manualmente.
  2. No hay forma de probar la conexión a Internet en general. Solo puede descubrir que no puede conectarse a un servicio en particular después de una cantidad de tiempo que ha probado. Esta es también una de las razones por las que es tan lento.
  3. El código es más una ilustración de cómo abordar el problema. Podría haberlo hecho fácilmente (ignore-errors (package-refresh-contents))si no le importara si tuvo éxito o no.
wvxvw
fuente
Esa es claramente la forma correcta de hacerlo. En cualquier momento, algunas partes de Internet son accesibles y otras no, y la forma correcta de lidiar con esto es sondear la conectividad.
jch
1
Esto también creará un montón de grandes búferes invisibles, sería mejor hacerlo (kill-buffer (url-ret ...))
Jordon Biondo
@JordonBiondo ok, punto tomado. No lo he pensado.
wvxvw
6

Una solución simple que he adoptado de mis scripts de shell es

(defun internet-up-p (&optional host)
    (= 0 (call-process "ping" nil nil nil "-c" "1" "-W" "1" 
                       (if host host "www.google.com"))))

Puede probar esto en el *scratch*búfer:

(message (if (internet-up-p) "Up" "Down"))
"Up"
Tyler Earnest
fuente
Esta solución me gusta más porque es simple, rápida y prueba la conexión a Internet en general.
miguelmorin
4

Una cosa que puedes probar es la función network-interface-list. Devuelve una lista de interfaces de red y sus direcciones IP.

Para mí, esto es lo que devuelve cuando estoy conectado a Ethernet y wifi:

(("en5" .
  [10 151 0 63 0])
 ("en0" .
  [10 151 2 76 0])
 ("lo0" .
  [127 0 0 1 0]))

Y cuando apago el wifi, en0desaparece:

(("en5" .
  [10 151 0 63 0])
 ("lo0" .
  [127 0 0 1 0]))

Experimente con eso y vea lo que obtiene cuando no tiene una conexión a Internet. Por ejemplo, para actualizar solo los paquetes cuando en0está activo, haga algo como:

(when (assoc "en0" (network-interface-list))
  (package-refresh-contents))
legoscia
fuente
Esa es una función interesante. Lo consigo (("eth0" . [10 72 153 234 0]) ("lo" . [127 0 0 1 0]))porque estoy conectado a Ethernet.
Kaushal Modi
3

Para ampliar la respuesta de Legoscia:

(defun test-internet ()
  (remove-if (lambda (el)
                   (string-match-p "lo.*" (car el)))
                 (network-interface-list)))

Esto devolverá una lista de conexiones de red activas ( lo.*es la interfaz de bucle invertido, en algunos casos loen otros lo#.

Si la prueba regresa non-nil, entonces hay una conexión de red (wifi / ethernet, sin embargo, no hay garantía de que realmente llegue a Internet externo. Tendría que hacer ping en alguna parte como prueba para eso), si regresa, nilentonces no hay forma de recuperar el paquete lista.

Jonathan Leech-Pepin
fuente
2

Utilizo lo siguiente para excluir loopbackinterfaces y también interfaces VirtualBox y Docker. Espero que sea útil.

(defun tzz-has-network ()
  (remove-if (lambda (i)
               (or (string-match-p "\\(vboxnet\\|docker\\).*" i)
                   (member 'loopback (nth 4 (network-interface-info i)))))
             (mapcar 'car (network-interface-list))))
Ted Zlatanov
fuente
2

En un sistema Linux moderno con DBus y NetworkManager:

(defun nm-is-connected()
  (equal 70 (dbus-get-property
             :system "org.freedesktop.NetworkManager" "/org/freedesktop/NetworkManager"
             "org.freedesktop.NetworkManager" "State")))
db48x
fuente
1

Creo que lo estás mirando de la manera incorrecta. Si realmente desea actualizar automáticamente sus paquetes, no lo haga sincrónicamente al inicio: hágalo desde un temporizador inactivo de algún tipo. P.ej

(run-with-idle-timer 10 nil
  (lambda ()
    (package-refresh-contents)
    ..etc..))
Stefan
fuente