Sinkronisasi paket antar mesin yang berbeda


57

Saya menggunakan emacs di tempat yang berbeda dan saya ingin memiliki setup dan paket yang sama diinstal di mana-mana. Saya kira saya bisa menggunakan repositori kontrol versi untuk file setup. Karena saya menggunakan Prelude , itu akan menjadi ~/.emacs.d/personal/.

Saya tidak tahu bagaimana harus melakukan dengan paket. Apakah ada file di suatu tempat .emacs.d/dengan daftar paket yang diinstal yang dapat saya gunakan untuk membuat emacs di komputer lain untuk juga menginstal yang terdaftar di sana?


2
Bagi saya paket yang diinstal hanyalah bagian dari repositori kontrol versi Emacs saya. Saya byte-compile paket-paket dengan versi Emacs tertua yang saya ingin / perlu gunakan dan juga memasukkan file .elc ke dalam repositori. Ini menawarkan kontrol dan konsistensi maksimum. Trade-off adalah ukuran repositori (relatif) yang besar. Repositori git saya yang berusia 6 tahun memiliki ukuran 120MB. Walaupun saya mungkin bisa lolos dengan 1/10 jika saya tidak menyertakan paket, beberapa megabita "terbuang" itu benar-benar tidak membuat saya khawatir.
paprika

1
Saya harus menambahkan bahwa sementara ELPA / MELPA / ... cukup populer saat ini, masih tidak semua paket tersedia melalui mereka. Jadi, jika Anda menggunakan paket yang membutuhkan instalasi manual, Anda mungkin tidak ingin mereplikasi upaya pada setiap mesin baru yang Anda gunakan (plus untuk setiap peningkatan paket). Sekali lagi, solusi mudah adalah menambahkan paket ke repositori kontrol versi Emacs Anda.
paprika

Tidak bisakah Anda hanya byte kompilasi di situs dan pergi dengan mengabaikan file .elc di git?
Vamsi

@Vamsi: Saya memasukkan file byte-compiled ke dalam repositori karena beberapa paket (non-ELPA) agak rumit untuk dikompilasi karena ketergantungannya. Untuk ini saya tidak suka mengulangi proses jika tidak perlu.
paprika

@ paprika Bisakah Anda memberikan beberapa detail cara mendapatkan pengaturan Anda? Apakah Anda menambahkan semuanya di .emacs.d plus .emacs ke repositori dan hanya itu?
Pemula

Jawaban:


50

Tidak ada file manifes yang dibuat secara otomatis yang dapat Anda sinkronkan untuk mencapai efek yang diinginkan.

Yang mengatakan, sesuatu yang dapat Anda lakukan adalah menambahkan panggilan ke package-installdalam konfigurasi emacs Anda sendiri.

(package-install 'auctex)

Idenya adalah package-installidempoten, jadi jika paket sudah ada, tidak ada yang akan terjadi. Dengan asumsi Anda memiliki panggilan seperti itu untuk setiap paket yang Anda gunakan (atau setidaknya daun dalam grafik dependensi), yang secara efektif akan menyinkronkan paket Anda di seluruh mesin.


Untuk beberapa paket, Anda dapat menggunakan yang berikut ini:

(setq my-package-list '(package1 package2 packageN))
(mapc #'package-install my-package-list)

2
Saya terkejut betapa jauh lebih sederhana pendekatan ini dibandingkan dengan solusi yang disarankan di sini . Apakah ada perbedaan? Cuplikan juga menggunakan package-install.
Stenskjaer

1
Sudah ada perubahan package.elsejak jawaban tertaut itu. Mungkin saja pada saat itu package-installdilakukan operasi pada paket yang ada, bukan hanya yang dihapus.
Jonathan Leech-Pepin

3
Teknik ini sayangnya bermasalah - bahkan jika repositori paket-arsip seragam antara mesin dan ditentukan dalam SCM. Itu tidak menjamin bahwa versi paket identik antara mesin. Masalahnya adalah bahwa versi paket tidak ditentukan; paket-paket individual ini dapat menyimpang dari waktu ke waktu dan dependensinya mungkin menjadi tidak kompatibel. Ini dapat terjadi dengan mudah pada arsip paket aktif seperti melpa.
ctpenrose

@ctpenrose: Apakah Anda punya saran untuk menghindari masalah ini?
siswa

@student Saya telah meminimalkan masalah dengan menggunakan paket melpa-stable dan memperbarui lebih jarang.
ctpenrose

34

Saya menjaga direktori .emacs.d saya di kontrol versi. Kemudian, di init.el saya dan file-file selanjutnya saya menggunakan paket-pakai untuk mendefinisikan pengaturan paket. Tidak hanya menggunakan-paket malas memuat paket Anda, itu akan mengunduhnya sesuai permintaan jika mereka tidak ada dari paket repo apa pun yang Anda buat.

Sebagai contoh, saya menggunakan mode-go, tetapi tidak pada setiap mesin. Di init.el saya, saya memiliki yang berikut ini:

(use-package go-mode
  :ensure t
  :config
  (progn
    (defun my-go-mode-hook ()
      (linum-mode t)
      (setq tab-width 4)
      (add-hook 'before-save-hook 'gofmt-before-save))
    (add-hook 'go-mode-hook 'my-go-mode-hook)))

Ini menambah hook mode, tetapi yang lebih penting, dengan menentukan :ensure titu akan mengunduh paket sesuai permintaan.

Untuk menjaga mesin tetap sinkron, Anda bisa checkout atau menarik dari repo dan memulai Emacs. Setiap paket baru akan diunduh dan diinstal.


Ini adalah solusi yang sekarang saya gunakan juga, bukan Cask, terutama karena (seperti yang dicatat oleh T. Verron) Cask tidak berfungsi (baik) pada Windows, dan merupakan ketergantungan lainnya.
Andy

1
Ini adalah cara saya menggunakan juga, tetapi alih-alih melakukan :ensure go-modeitu adalah mengulangi nama paket, Anda bisa menentukan:ensure t
Pedro Luz

Poin bagus! Ini jawaban lama. Saya akan memperbaruinya.
elarson

Anda juga dapat menggunakan :hookkata kunci untuk menyederhanakan kode Anda.
Guilherme Salomé

17

Di Emacs-25, ada variabelnya package-selected-packages, jadi Anda bisa mengkustomisasi variabel ini dan menggunakannya package-install-selected-packagesuntuk memastikan mereka terinstal.


Perhatikan bahwa saya melihatnya, nama perintah itu agak membingungkan. Bisakah saya mengubahnya menjadi paket-instal-terpilih-paket?
Malabarba

Anggap saja maksud Anda "Sekarang" dan bukannya "Catatan", ya.
Stefan

9

Yang ingin Anda gunakan adalah Cask , yang memungkinkan Anda membuat file Cask yang menentukan paket mana yang akan diinstal cask install. Itu dapat digunakan untuk mengelola dependensi suatu paket, dan "dependensi" dari konfigurasi Emacs Anda dengan mudah. Masukkan file Tong Anda di bawah kontrol versi, dan instal / perbarui paket berdasarkan per mesin.


4
Perlu dicatat bahwa (sampai hari ini) solusi ini tidak berfungsi untuk mesin windows.
T. Verron

1
Saya tidak lagi menggunakan solusi ini, karena alasan Anda (dan Tong itu adalah ketergantungan lain). Sangat bagus untuk membuat paket; mengerikan untuk manajemen konfigurasi.
Andy

6

Pendekatan alternatif akan menjadi sebagai berikut: karena saya tidak hanya ingin menyinkronkan paket Emacs saya, tetapi juga file lainnya (misalnya .emacs, .bashrctetapi juga direktori lain) antara server saya dan laptop saya, saya mulai menggunakan unison, untuk melakukan sinkronisasi file dan direktori. Jadi ketika bekerja pada laptop saya, saya menjalankan sederhana unison laptopsebelum hal lain. ~/.unison/laptop.prfFile saya memiliki bagian berikut untuk file terkait Emacs:

path = .emacs
path = .emacs.d
ignore = Path {.emacs.d/semanticdb}

Karena paket-paket Emacs saya (dan juga cadangan serta bookmark Emacs saya) disimpan dalam ~/.emacs.dhal ini, pastikan saya memiliki semuanya di semua mesin saya.

Pendekatan alternatif akan meletakkan .emacs.ddirektori di direktori yang disinkronkan dengan OwnCloud, DropBox atau layanan sinkronisasi file lainnya dan kemudian membuat symlink dari ~/.emacs.dke direktori bersama itu.


5

Walaupun package.elmerupakan cara standar untuk menginstal paket, Anda mungkin juga ingin mencoba el-getyang sangat berguna untuk menginstal paket yang tidak (atau tidak bisa) di elpa. Jawaban ini berkaitan dengan sinkronisasi paket-paket tersebut.

Cara Anda memastikan bahwa paket yang diberikan diinstal saat menggunakan el-get adalah menambahkan sesuatu seperti berikut ini pada Anda file init

(el-get 'sync '(packages))

di mana paket adalah daftar paket yang ingin Anda instal. Fungsi ini mirip dengan package-installmenginstal paket hanya jika mereka belum terinstal, jika tidak maka hanya menginisialisasi paket.


5

Saya menggunakan sedikit trik "dicuri" dari emacs-starter-kit (saya pikir):

(defun maybe-install-and-require (p)
  (when (not (package-installed-p p))
   (package-install p))
  (require p))

Jadi ketika saya membutuhkan paket, saya hanya menggunakan:

(maybe-install-and-require 'magit)

Pada startup emacs, mengevaluasi konfigurasi saya, package.elakan menyediakan untuk menginstal magit jika itu tidak diinstal.

Anda dapat menemukan konfigurasi saya di sini:

https://github.com/mdallastella/emacs-config/


1
Mengikuti filosofi yang sama, Anda dapat menggunakan 'paradox-butuhkan' dari paradox
csantosb

3

Saya memiliki direktori ~ / emacs yang dikendalikan oleh versi-lincah dan berisi semua yang dibuat oleh pengaturan emacs saya (~ / emacs / site-lisp untuk pustaka yang diunduh secara manual, ~ / emacs / elpa untuk pustaka yang diinstal dengan elpa, ~ / emacs / etc / untuk .emacs yang terpecah, ~ / emacs / dot-emacs.el yang saya symlink sebagai ~ / .emacs). Diperlukan beberapa penyesuaian beberapa paket untuk memiliki semua file penting di dalam pohon ini, tetapi berfungsi dengan baik. Beberapa bit yang spesifik mesin yang telah saya implementasikan oleh conditional pada nama sistem.

Jadi setelah saya menginstal / mengkonfigurasi ulang / mengubah apa pun, saya cukup melakukan pull / push semua perubahan di antara semua mesin yang saya gunakan.

Manfaat tambahan adalah bahwa saya memiliki riwayat lengkap konfigurasi saya dan dapat kembali / membagi dua / mengembalikan jika seandainya terjadi kesalahan.

PS mercurial tampaknya sangat cocok karena memiliki tarikan / dorong dua sisi yang alami, tetapi pengaturan serupa seharusnya tidak sulit untuk dicapai dengan git atau DVD lainnya.


3

Saya memiliki ini setup-packages.eldi setup emacs saya yang merupakan hibrida kode dari blog Prelude dan Tomorokoshi di Package Management .

setup-packages.el melakukan hal berikut:

  • Buat direktori untuk elpapaket jika tidak ada dan tambahkan direktori serta sub-direktori ke load-path.
  • Perbarui package-archivesdaftar dengan Melpa.
  • Periksa apakah Anda memiliki semua paket yang tercantum dalam my-packagesdaftar diinstal. Jika suatu paket tidak diinstal, instal.

Bagaimana cara mengimplementasikannya

  • Simpan di setup-packages.elbawah ini ke ~/.emacs.d/direktori Anda .
  • Atur user-emacs-directory, setup-packages-filedan my-packagesvariabel di init.eldan lakukan (load setup-packages-file).

Ketika Anda memulai emacs untuk pertama kalinya pada mesin yang tidak memiliki paket-paket ini diinstal, semua pacakges yang tercantum di dalam my-packagesakan mendapatkan diinstal secara otomatis.

setup-packages.el

;; setup-packages.el - Package management

(require 'cl)
(require 'package)

;; Set the directory where you want to install the packages
(setq package-user-dir (concat user-emacs-directory "elpa/"))

;; Add melpa package source when using package list
(add-to-list 'package-archives '("melpa" . "http://melpa.org/packages/") t)

;; Load emacs packages and activate them
;; This must come before configurations of installed packages.
;; Don't delete this line.
(package-initialize)
;; `package-initialize' call is required before any of the below
;; can happen

;; Auto install the required packages
;; Method to check if all packages are installed
(defun packages-installed-p ()
  (loop for p in my-packages
        when (not (package-installed-p p)) do (return nil)
        finally (return t)))

;; if not all packages are installed, check one by one and install the missing ones.
(unless (packages-installed-p)
  ;; check for new packages (package versions)
  (message "%s" "Emacs is now refreshing its package database...")
  (package-refresh-contents)
  (message "%s" " done.")
  ;; install the missing packages
  (dolist (p my-packages)
    (when (not (package-installed-p p))
      (package-install p))))

(provide 'setup-packages)

init.el

Anda membutuhkan yang berikut ini di init.el:

(setq user-home-directory  (getenv "HOME"))
(setq user-emacs-directory (concat user-home-directory ".emacs.d/"))
(setq setup-packages-file  (expand-file-name "setup-packages.el" user-emacs-directory))

;; A list of packages to ensure are installed at launch
(setq my-packages
      '(
        ;; package1
        ;; package2
       ))

(load setup-packages-file nil :nomessage) ; Load the packages

2

Untuk mencerminkan konfigurasi saya, saya memutuskan untuk menggunakan pendekatan yang berbeda, menggunakan Syncthing ; setiap perubahan pada file config saya menyebar ke PC yang lain tanpa harus mempedulikannya, jadi ketika saya memutakhirkan paket saya hanya perlu melakukannya di salah satu PC.


2

RSYNC : Menyinkronkan folder / file tertentu menggunakan rsync, baik melalui jaringan rumah atau via sshke server jauh.

rsyncadalah utilitas sinkronisasi satu arah yang dapat menghapus file pada target, jadi pastikan untuk mencadangkan data Anda pada sumber dan lokasi target, dan uji menyeluruh menggunakan --dry-runopsi, sebelum melakukan hal yang nyata.

Untuk membaca tentang cara mengkonfigurasi .authinfofile dengan benar , lihat https://www.gnu.org/software/emacs/manual/auth.html Contoh .authinfokonten file (yang mungkin berisi beberapa entri berbeda) adalah sebagai berikut:

machine mymachine login myloginname password mypassword port myport

Konfigurasikan dan gunakan fungsi rsync-remoteuntuk menyinkronkan sshke server jauh. Atau, gunakan fungsi rsync-localuntuk menyinkronkan pada komputer yang sama atau melalui jaringan rumah tepercaya.

(require 'auth-source)

;;; EXAMPLE:
;;;   (get-auth-info "12.34.567.89" "username")
;;;   (get-auth-info "localhost" "root")
(defun get-auth-info (host user &optional port)
  (let ((info (nth 0 (auth-source-search
                      :host host
                      :user user
                      :port port
                      :require '(:user :secret)
                      :create t))))
    (if info
      (let* ((port (plist-get info :port))
             (secret-maybe (plist-get info :secret))
             (secret
               (if (functionp secret-maybe)
                 (funcall secret-maybe)
                 secret-maybe)))
          (list port secret))
    nil)))

(defun rsync-filter (proc string)
  (cond
    ((string-match
       "^\\([a-zA-Z0-9_\\-\\.]+\\)@\\([a-zA-Z0-9_\\-\\.]+\\)'s password: "
       string)
      (let* ((user (substring string (match-beginning 1) (match-end 1)))
             (host (substring string (match-beginning 2) (match-end 2)))
             (password (car (cdr (get-auth-info host user)))))
        (process-send-string proc (concat password "\n"))))
    ((not (or (string-match "files\\.\\.\\.\r" string)
              (string-match "files to consider\n" string)))
      (with-current-buffer (messages-buffer)
        (let ((inhibit-read-only t))
          (goto-char (point-max))
          (when (not (bolp))
            (insert "\n"))
          (insert string)
          (when (not (bolp))
            (insert "\n")))))))

(defun rsync-remote ()
"Use rsync to a remote server via ssh.  Back-up your data first!!!"
(interactive)
  (let* (
      (host "localhost")
      (username "root")
      (port (or (car (get-auth-info host username))
                (number-to-string (read-number "Port:  "))))
      (source
        (let ((dir (expand-file-name (locate-user-emacs-file "elpa/"))))
          (if (file-directory-p dir)
            dir
            (let ((debug-on-quit nil)
                  (msg (format "`%s` is not a valid directory." dir)))
              (signal 'quit `(,msg))))))
      (target "/private/var/mobile/elpa/")
      (ssh "/usr/bin/ssh")
      (rsync "/usr/bin/rsync")
      (rsync-include-file "/path/to/include-file.txt")
      (rsync-exclude-file "/path/to/exclude-file.txt")
      (rsh (concat "--rsh=ssh -p " port " -l " username))
      (host+target (concat host ":" target)))
    (start-process
        "rsync-process"
        nil
        rsync
        "-avr" ;; must specify the `-r` argument when using `--files-from`
        "--delete"
        ;; The paths inside the exclusion file must be relative, NOT absolute.
        ;;; (concat "--files-from=" rsync-include-file)
        ;;; (concat "--exclude-from=" rsync-exclude-file)
        rsh
        source
        host+target)
    (set-process-filter (get-process "rsync-process") 'rsync-filter)
    (set-process-sentinel
      (get-process "rsync-process")
      (lambda (p e) (when (= 0 (process-exit-status p))
        (message "rsync-remote:  synchronizing ... done."))))))

(defun rsync-local ()
"Use rsync locally -- e.g., over a trusted home network.
 Back-up your data first!!!"
  (interactive)
  (let (
      (rsync-program "/usr/bin/rsync")
      (source
        (let ((dir (expand-file-name
                     (file-name-as-directory
                       (read-directory-name "Source Directory: " nil nil nil nil)))))
          (if (file-directory-p dir)
            dir
            (let ((debug-on-quit nil)
                  (msg (format "`%s` is not a valid directory." dir)))
              (signal 'quit `(,msg))))))
      (target (expand-file-name
                (file-name-as-directory
                  (read-directory-name "Target Directory: " nil nil nil nil)))))
    (unless (y-or-n-p (format "SOURCE:  %s | TARGET:  %s" source target))
      (let ((debug-on-quit nil))
        (signal 'quit `("You have exited the function."))))
    (start-process "rsync-process"
      nil
      rsync-program
      "--delete"
      "-arzhv"
      source
      target)
    (set-process-filter (get-process "rsync-process") #'rsync-process-filter)
    (set-process-sentinel
      (get-process "rsync-process")
      (lambda (p e)
        (when (= 0 (process-exit-status p))
        (message "Done!"))))))

0

https://github.com/redguardtoo/elpa-mirror membuat repositori lokal semua paket yang diinstal.

Penggunaannya sederhana, jalankan saja M-x elpamr-create-mirror-for-installed.

Di komputer lain, masukkan (setq package-archives '(("myelpa" . "~/myelpa/")))ke Anda .emacsdan mulai ulang Emacs.

Sekarang di semua mesin, Anda mendapatkan versi paket yang sama persis.

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.