Код Elisp для перевірки підключення до Інтернету


13

Коли я відкриваю Emacs, він оцінює мій файл init, який включає оновлення моїх архівів пакетів через Інтернет. Це проблематично, коли у мене немає підключення до Інтернету, тому мені потрібно запобігти виконанню цього коду при запуску Emacs без підключення до Інтернету. Щоб вирішити цю проблему, мені цікаво, чи є спосіб Emacs ігнорувати код оновлення пакета, коли у мене немає підключення до Інтернету?

Ось кілька перших моїх рядків 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)       

Я думаю, що я можу додати код, щоб завантажити мій файл Emacs наступним чином:

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

Чи існує (connected-to-internet)функція чи подібний підхід для вирішення цього питання?


2
Тут є відповідна відповідь stackoverflow.com/a/21065704/3170376 .
Ім'я

2
Чому ви хочете оновити архіви пакетів під час запуску Emacs?
філ

@Name Це більше ніж пов'язане. Це відповідь (якщо він працює).
Малабарба

1
Я б настійно радив не запускати пакунок-оновлення вмісту під час кожного запуску. Швидше за все, вам потрібно буде запустити його один раз, коли спершу витягніть конфігурацію на новій машині, а потім вам не потрібно буде знову за місяці. Робити це, коли у вас є з'єднання, є неправильною відповіддю на цю проблему, справжня проблема полягає в тому, що ви працюєте з ним зовсім тоді, коли вам цього не потрібно.
Джордон Біондо

Відповіді:


7

Ну а якщо ви все-таки хотіли автоматично оновлювати вміст, коли це можливо, ви можете зробити щось на зразок коду нижче:

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

Кілька нотаток належить:

  1. Це повільно, і воно буде повільним при нормальному запуску, тому я краще роблю це вручну.
  2. Взагалі немає можливості перевірити підключення до Інтернету. Ви можете виявити, що ви не можете підключитися до певної послуги через деякий час, який ви пробували. Це також одна з причин, чому це так повільно.
  3. Код є більшою ілюстрацією того, як підійти до проблеми. Ви могли б легко зробити це, (ignore-errors (package-refresh-contents))якби вам було все одно, вдалось це чи ні.

Це явно правильний спосіб зробити це. У будь-який час деякі частини Інтернету доступні, а деякі - ні, і належним способом боротьби з ним є перевірка на зв’язок.
jch

1
Це також створить купу великих небачених буферів, найкраще це зробити (kill-buffer (url-ret ...))
Джордон Біондо

@JordonBiondo ок, точка взята. Не думав про це.
wvxvw

6

Просте рішення, яке я прийняв із своїх скриптів оболонки, - це

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

Ви можете перевірити це в *scratch*буфері:

(message (if (internet-up-p) "Up" "Down"))
"Up"

Мені подобається це рішення найбільше, тому що воно просте, швидке та перевіряє зв’язок із ширшим Інтернетом.
miguelmorin

4

Одне, що можна спробувати, це функція network-interface-list. Він повертає список мережевих інтерфейсів та їх IP-адрес.

Для мене це те, що воно повертається, коли я підключений до Ethernet і wifi:

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

І коли я вимикаю wifi, en0зникає:

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

Експериментуйте з цим і подивіться, що ви отримуєте, коли у вас немає підключення до Інтернету. Наприклад, щоб оновити пакети лише тоді, коли en0встановлено, виконайте щось на кшталт:

(when (assoc "en0" (network-interface-list))
  (package-refresh-contents))

Це цікава функція. Я отримую, (("eth0" . [10 72 153 234 0]) ("lo" . [127 0 0 1 0]))тому що я підключений до Ethernet.
Каушал Моді

3

Щоб розширити відповідь Legoscia:

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

Це поверне список активних мережевих з'єднань ( lo.*це інтерфейс зворотного зв'язку, в деяких випадках loв інших lo#.

Якщо тест повертається non-nil, значить, є мережне підключення (Wi-Fi / Ethernet, жодна гарантія, що він фактично доходить до зовнішнього Інтернету. Однак, доведеться десь пінг-програмувати як тест на це), якщо він повертається, nilтоді немає можливості отримати пакет список.


2

Я використовую наступне для виключення loopbackінтерфейсів, а також інтерфейсів VirtualBox та Docker. Я сподіваюся, що це корисно.

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

2

У сучасній системі Linux з DBus та NetworkManager:

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

1

Я думаю, що ти дивишся на це неправильно. Якщо ви дійсно хочете автоматично оновлювати ваші пакети, тоді не робіть це синхронно під час запуску: робіть це з непрацюючого таймера якогось. Напр

(run-with-idle-timer 10 nil
  (lambda ()
    (package-refresh-contents)
    ..etc..))
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.