Code Elisp pour vérifier la connexion Internet

13

Lorsque j'ouvre Emacs, il évalue mon fichier init, qui comprend l'actualisation des archives de mon package via une connexion Internet. C'est problématique lorsque je n'ai pas de connexion Internet, donc je dois empêcher l'exécution de ce code lors du démarrage d'Emacs sans connexion Internet. Pour résoudre ce problème, je me demande s'il existe un moyen pour qu'Emacs ignore le code d'actualisation du package lorsque je n'ai pas de connexion Internet?

Voici les premières lignes de mon 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)       

J'imagine que je peux ajouter du code pour charger mon fichier Emacs comme suit:

;; 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-t-il une (connected-to-internet)fonction ou une approche similaire pour résoudre ce problème?

modulitos
la source
2
Il existe une réponse connexe ici stackoverflow.com/a/21065704/3170376 .
Nom du
2
Pourquoi souhaitez-vous actualiser les archives du package lorsque vous démarrez Emacs?
phils
@Name C'est plus que lié. C'est la réponse (en supposant que cela fonctionne).
Malabarba
1
Je vous conseille fortement de ne pas exécuter le package-refresh-contents à chaque démarrage. Il est fort probable que vous ayez besoin de l'exécuter une fois lors de la première extraction de votre configuration sur une nouvelle machine, puis vous n'en aurez plus besoin pendant des mois. Le faire lorsque vous avez une connexion n'est pas la bonne réponse à ce problème, le vrai problème est que vous l'exécutez quand vous n'en avez pas besoin.
Jordon Biondo

Réponses:

7

Eh bien, si vous vouliez toujours actualiser le contenu automatiquement, chaque fois que possible, vous pourriez faire quelque chose comme le code ci-dessous:

(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)))

Peu de notes sont dues:

  1. C'est lent, et ce sera lent lors du démarrage normal, donc je préfère le faire manuellement.
  2. Il n'y a aucun moyen de tester la connexion Internet en général. Vous ne pouvez découvrir que vous ne pouvez pas vous connecter à un service particulier après un certain temps que vous avez essayé. C'est aussi l'une des raisons pour lesquelles il est si lent.
  3. Le code est plus une illustration de la façon d'aborder le problème. Vous auriez pu facilement le faire (ignore-errors (package-refresh-contents))si vous n'aviez pas voulu savoir si cela avait réussi ou non.
wvxvw
la source
C'est clairement la bonne façon de procéder. À tout moment, certaines parties d'Internet sont accessibles et d'autres ne le sont pas, et la bonne façon de le gérer consiste à sonder la connectivité.
2015
1
Cela créera également un tas de grands tampons invisibles, il serait préférable de le faire (kill-buffer (url-ret ...))
Jordon Biondo
@JordonBiondo ok, remarque prise. Je n'y ai pas pensé.
wvxvw
6

Une solution simple que j'ai adoptée à partir de mes scripts shell est

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

Vous pouvez tester cela dans le *scratch*tampon:

(message (if (internet-up-p) "Up" "Down"))
"Up"
Tyler Earnest
la source
J'aime le plus cette solution car elle est simple, rapide et teste la connexion à Internet plus large.
miguelmorin
4

Une chose que vous pourriez essayer est la fonction network-interface-list. Il renvoie une liste des interfaces réseau et leurs adresses IP.

Pour moi, c'est ce que cela renvoie lorsque je suis connecté à la fois à Ethernet et à wifi:

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

Et quand je désactive le wifi, en0disparaît:

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

Expérimentez avec cela et voyez ce que vous obtenez lorsque vous n'avez pas de connexion Internet. Par exemple, pour actualiser uniquement les packages lorsqu'il en0est activé, faites quelque chose comme:

(when (assoc "en0" (network-interface-list))
  (package-refresh-contents))
legoscia
la source
C'est une fonction intéressante. Je reçois (("eth0" . [10 72 153 234 0]) ("lo" . [127 0 0 1 0]))parce que je suis connecté à Ethernet.
Kaushal Modi
3

Pour développer la réponse de Legoscia:

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

Cela renverra une liste des connexions réseau actives ( lo.*c'est l'interface de bouclage, dans certains cas lodans d'autres lo#.

Si les déclarations de test non-nil, alors il y a une connexion réseau (wifi / ethernet, aucune garantie qu'elle parvienne effectivement l'internet extérieur cependant. Faudrait ping quelque part comme un test pour cela), si elle retourne nilalors il n'y a aucun moyen de récupérer le paquet liste.

Jonathan Leech-Pepin
la source
2

J'utilise les éléments suivants pour exclure les loopbackinterfaces et également les interfaces VirtualBox et Docker. J'espère que c'est utile.

(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
la source
2

Sur un système Linux moderne avec DBus et NetworkManager:

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

Je pense que vous le regardez dans le mauvais sens. Si vous voulez vraiment mettre à jour automatiquement vos packages, ne le faites pas de manière synchrone au démarrage: faites-le à partir d'une minuterie inactive. Par exemple

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