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


13

Когда я открываю Emacs, он оценивает мой файл инициализации, который включает в себя обновление моих архивов пакетов через интернет-соединение. Это проблематично, когда у меня нет подключения к Интернету, поэтому мне нужно предотвратить выполнение этого кода при запуске 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))если бы вам было все равно, удастся это или нет.

Это явно правильный способ сделать это. В какой-то момент некоторые части Интернета доступны, а некоторые нет, и правильный способ борьбы с ним - поиск соединения.

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"

Мне больше всего нравится это решение, потому что оно простое, быстрое и проверяет подключение к более широкому Интернету.
Мигельморин

4

Одна вещь, которую вы можете попробовать, это функция network-interface-list. Возвращает список сетевых интерфейсов и их IP-адресов.

Для меня это то, что он возвращает, когда я подключен к Ethernet и Wi-Fi:

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

Чтобы расширить ответ Легоссии:

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

Это вернет список активных сетевых подключений ( lo.*это петлевой интерфейс, в некоторых случаях loв других lo#.

Если тест возвращается non-nil, значит, есть сетевое соединение (wifi / 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.