Elisp-Code zur Überprüfung der Internetverbindung

13

Wenn ich Emacs öffne, wertet es meine Init-Datei aus, einschließlich der Aktualisierung meiner Paketarchive über eine Internetverbindung. Dies ist problematisch, wenn ich keine Internetverbindung habe. Daher muss ich die Ausführung dieses Codes verhindern, wenn Emacs ohne Internetverbindung gestartet wird. Um dieses Problem zu lösen, frage ich mich, ob es eine Möglichkeit gibt, den Paketaktualisierungscode von Emacs zu ignorieren, wenn ich keine Internetverbindung habe.

Hier sind die ersten Zeilen von mir 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)       

Ich stelle mir vor, dass ich wie folgt Code hinzufügen kann, um meine Emacs-Datei zu laden:

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

Gibt es eine (connected-to-internet)Funktion oder einen ähnlichen Ansatz, um dieses Problem zu beheben?

modulitos
quelle
2
Hier gibt es eine verwandte Antwort: stackoverflow.com/a/21065704/3170376 .
Nennen Sie den
2
Warum möchten Sie die Paketarchive aktualisieren, wenn Sie Emacs starten?
Phils
@Name Das ist mehr als verwandt. Es ist die Antwort (vorausgesetzt, es funktioniert).
Malabarba,
1
Es wird dringend empfohlen, dass Sie nicht bei jedem Start die Paketaktualisierungsinhalte ausführen. Es ist sehr wahrscheinlich, dass Sie es einmal ausführen müssen, wenn Sie Ihre Konfiguration zum ersten Mal auf einem neuen Computer herunterladen und es dann für Monate nicht mehr benötigen. Dies zu tun, wenn Sie eine Verbindung haben, ist die falsche Antwort auf dieses Problem. Das eigentliche Problem ist, dass Sie es überhaupt ausführen, wenn Sie es nicht müssen.
Jordon Biondo

Antworten:

7

Nun, wenn Sie immer noch Inhalte automatisch aktualisieren möchten, können Sie, wann immer möglich, etwas wie den folgenden Code tun:

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

Einige Notizen sind fällig:

  1. Dies ist langsam, und es wird beim normalen Start langsam sein, also mache ich es lieber manuell.
  2. Es gibt keine Möglichkeit, die Internetverbindung im Allgemeinen zu testen. Sie können erst feststellen, dass Sie nach einiger Zeit, die Sie versucht haben, keine Verbindung zu einem bestimmten Dienst herstellen können. Dies ist auch einer der Gründe, warum es so langsam ist.
  3. Der Code ist eher ein Beispiel dafür, wie das Problem angegangen werden kann. Sie hätten es leicht tun können, (ignore-errors (package-refresh-contents))wenn es Ihnen egal wäre, ob es erfolgreich war oder nicht.
wvxvw
quelle
Das ist eindeutig der richtige Weg. Zu jeder Zeit sind einige Teile des Internets zugänglich und andere nicht, und der richtige Weg, damit umzugehen, besteht darin, nach Konnektivität zu suchen.
24.
1
Dies wird auch eine Reihe von großen unsichtbaren Puffern erzeugen. Am besten tun Sie dies (kill-buffer (url-ret ...))
Jordon Biondo
@JordonBiondo ok, Punkt genommen. Ich habe nicht darüber nachgedacht.
wvxvw
6

Eine einfache Lösung, die ich aus meinen Shell-Skripten übernommen habe, ist

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

Sie können dies im *scratch*Puffer testen :

(message (if (internet-up-p) "Up" "Down"))
"Up"
Tyler Earnest
quelle
Diese Lösung gefällt mir am besten, weil sie einfach und schnell ist und die Verbindung zum weiteren Internet testet.
Miguelmorin
4

Eine Sache, die Sie versuchen könnten, ist die Funktion network-interface-list. Es gibt eine Liste der Netzwerkschnittstellen und ihrer IP-Adressen zurück.

Für mich ist das, was es zurückgibt, wenn ich sowohl mit Ethernet als auch mit WLAN verbunden bin:

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

Und wenn ich WLAN ausschalte, en0verschwindet:

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

Experimentieren Sie damit und sehen Sie, was Sie erhalten, wenn Sie keine Internetverbindung haben. Um beispielsweise Pakete nur zu aktualisieren, wenn en0sie aktiv sind, gehen Sie wie folgt vor:

(when (assoc "en0" (network-interface-list))
  (package-refresh-contents))
Legoscia
quelle
Das ist eine interessante Funktion. Ich bekomme, (("eth0" . [10 72 153 234 0]) ("lo" . [127 0 0 1 0]))weil ich mit dem Ethernet verbunden bin.
Kaushal Modi,
3

So erweitern Sie die Antwort von Legoscia:

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

Dies wird eine Liste der aktiven Netzwerkverbindungen zurückzukehren ( lo.*die Loopback - Schnittstelle, in einigen Fällen loin anderen lo#.

Wenn der Test zurückkehrt non-nil, gibt es eine Netzwerkverbindung (WLAN / Ethernet, keine Garantie, dass es tatsächlich ins Internet gelangt. Müsste als Test irgendwo pingen). Wenn der Test zurückkehrt , nilgibt es keine Möglichkeit, das Paket abzurufen aufführen.

Jonathan Leech-Pepin
quelle
2

Ich benutze das Folgende, um loopbackSchnittstellen und auch VirtualBox- und Docker-Schnittstellen auszuschließen . Ich hoffe es ist hilfreich.

(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
quelle
2

Auf einem modernen Linux-System mit DBus und NetworkManager:

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

Ich denke, Sie sehen es falsch. Wenn Sie Ihre Pakete wirklich automatisch aktualisieren möchten, führen Sie dies beim Start nicht synchron aus: Führen Sie dies über einen Leerlaufzeitgeber aus. Z.B

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