Paketleri farklı makineler arasında senkronize et


57

Emacs'ı farklı yerlerde kullanıyorum ve her yere benzer bir kurulum ve paketler kurmak istiyorum. Sanırım kurulum dosyaları için bir sürüm kontrol deposu kullanabilirim. Prelude kullandığımdan beri , öyle olurdu ~/.emacs.d/personal/.

Paketlerle nasıl yapacağımı bilmiyorum. Orada .emacs.d/listelenenleri yüklemek için diğer makinelerde emacs yapmak için kullanabileceğim yüklü paketler listesinde bir dosya var mı?


2
Benim için, kurulu paketler Emacs sürüm kontrol havuzumun bir parçası. Paketleri, kullanmak istediğim / ihtiyaç duyduğum en eski Emac sürümü ile derlerim ve .elc dosyalarını depoya koyarım. Bu, maksimum kontrol ve tutarlılık sunar. Takas, deponun (nispeten) büyük boyutudur. 6 yaşındaki git depomun boyutu 120 MB. Paketleri eklemezsem, 1/10 ile kaçabildiğim halde, bu "boşa harcanan" megabaytlar beni gerçekten endişelendirmiyor.
kırmızı biber

1
ELPA / MELPA / ... bugünlerde oldukça popüler olsa da, yine de tüm paketlerin kendilerinden edinilemediğini eklemeliyim. Bu nedenle, el ile kurulum gerektiren bir paket kullanıyorsanız, kullandığınız her yeni makinede (her paket yükseltme için artı) çabalarınızı çoğaltmak istemeyebilirsiniz. Yine kolay bir çözüm paketi Emacs sürüm kontrol deponuza eklemektir.
kırmızı biber

Sadece sitedeki derleme bayt ve git git .elc dosyaları görmezden kaçmak olamaz mı?
Vamsi

@Vamsi: Bayt-derlenmiş dosyaları depoya koyarım çünkü bazı (ELPA olmayan) paketler bağımlılıklarından dolayı derlemek için biraz titiz. Bunlar için gerekli değilse işlemi tekrarlamaktan hoşlanmıyorum.
kırmızı biber

@paprika Kurulumunuzu nasıl alacağınız konusunda biraz bilgi verebilir misiniz? .Emacs.d plus .emacs içindeki her şeyi depoya ekler misiniz?
Acemi

Yanıtlar:


50

İstediğiniz efekti elde etmek için senkronize edebileceğiniz otomatik olarak oluşturulan bir manifest dosyası yok.

Bununla birlikte, yapabileceğiniz bir şey package-installemacs yapılandırmanızın kendisine çağrılar eklemektir .

(package-install 'auctex)

Buradaki fikir, package-installkesin değildir, yani paket zaten mevcutsa, hiçbir şey olmayacak. Paketlerinizi makineler arasında etkin bir şekilde senkronize edecek, kullandığınız her paket için (veya en azından bağımlılık grafiğindeki yapraklar) böyle bir çağrınız olduğunu varsayalım.


Birden fazla paket için aşağıdakileri kullanabilirsiniz:

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

2
Bu yaklaşımın burada önerilen çözüme kıyasla ne kadar basit olduğuna şaşırdım . Fark var mı? Snippet de kullanır package-install.
Stenskjaer

1
package.elBağlantılı cevaptan bu yana değişiklikler oldu . O zamanlar package-installsadece kaldırılmış paketlerde değil mevcut paketlerde de işlem yapılması mümkün .
Jonathan Leech-Pepin

3
Bu teknik maalesef sorunlu - paket arşiv deposu makineler arasında üniform ve SCM'de belirtilmiş olsa bile Paket sürümlerinin makineler arasında aynı olduğu garanti edilmez. Sorun, paket sürümlerinin belirtilmemiş olmasıdır; bu bireysel paketler zamanla farklılık gösterebilir ve bağımlılıkları uyumsuz hale gelebilir. Bu, melpa gibi aktif paket arşivlerinde oldukça kolay bir şekilde gerçekleşebilir.
ctpenrose

@ctpenrose: Bu sorunu önlemek için bir öneriniz var mı?
Öğrenci

@student Melpa-stabil kullanarak ve paketleri daha az güncelleyerek sorunu en aza indirdim.
ctpenrose

34

.Emacs.d dizinini sürüm kontrolünde tutarım. Sonra init.el ve sonraki dosyalarımda paket kurulumunu tanımlamak için use-package kullanıyorum . Kullanım paketi sadece paketlerinizi tembel olarak yüklemekle kalmaz, kurduğunuz herhangi bir paket deposunda bulunmuyorsa talep üzerine indirir.

Mesela go-mode kullanıyorum ama her makinede kullanmıyorum. İnit.el'imde aşağıdakiler var:

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

Bu, bir mod kancası ekler ancak daha da önemlisi, :ensure tpaketi istek üzerine indireceğini belirterek .

Bir makineyi senkronize etmek için depodan kontrol edebilir veya çekebilir ve Emacs'ı başlatabilirsiniz. Yeni paketler indirilecek ve yüklenecektir.


Bu, şimdi de Cask yerine kullandığım çözüm. Öncelikle (T. Verron'un belirttiği gibi) Cask, Windows'ta (iyi) çalışmıyor ve bir başka bağımlılık.
Andy

1
Benim de kullandığım yol budur, fakat bunu yapmak yerine :ensure go-modepaket ismini tekrarlamak yerine , sadece belirtebilirsiniz:ensure t
Pedro Luz

İyi bir nokta! Bu eski bir cevap. Güncelleyeceğim.
elarson

:hookAnahtar kelimenizi kodunuzu basitleştirmek için de kullanabilirsiniz .
Guilherme

17

Emacs-25'te değişken var package-selected-packages, yani bu değişkeni özelleştirebilir ve package-install-selected-packagesyüklendiklerinden emin olmak için kullanabilirsiniz .


Gördüğüm kadarıyla, bu komutun adı biraz kafa karıştırıcı. Paket-install-selected-paketler olarak değiştirebilir miyim?
Malabarba

"Not" yerine "Şimdi" demek istediğinizi varsayarsak, evet.
Stefan

9

Kullanmak istediğiniz Cask , hangi paketlerin yükleneceğini belirten bir Cask dosyası oluşturmanıza olanak sağlar cask install. Bir paketin bağımlılıklarını ve Emacs yapılandırmanızın kolaylıkla "bağımlılıklarını" yönetmek için kullanılabilir. Cask dosyanızı sürüm kontrolü altına alın ve paketleri makineye göre kurun / güncelleyin.


4
Bu çözümün (bugün itibariyle) pencere makineleri için işe yaramadığını belirtmekte fayda var.
T. Verron

1
Artık bu çözümü kullanmıyorum, sizin nedenden dolayı (ve Cask'ın başka bir bağımlılık olduğu). Paketleri yapmak için harika; yapılandırma yönetimi için korkunç.
Andy

6

Alternatif bir yaklaşım şu şekilde olacaktır: yalnızca Emacs paketlerimi senkronize etmek istemediğimden, sunucum ve dizüstüm arasındaki diğer dosyaları da (örneğin .emacs, .bashrcdiğer dizinleri de) unisonsenkronize etmek istemem , dosyaları senkronize etmek için kullanmaya başladım ve dizinleri. Dizüstü bilgisayarımda çalışırken basit bir unison laptopşeyden önce koşuyorum . Benim ~/.unison/laptop.prfdosya Emacs ilgili dosyalar için aşağıdaki bölümü vardır:

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

Emacs paketlerim (ve aynı zamanda Emacs yedeklerim ve yer imlerim de) içinde bulunduğundan ~/.emacs.d, tüm makinelerimde her şeyi aldım.

Alternatif bir yaklaşım, .emacs.ddizini OwnCloud, DropBox veya başka bir dosya senkronizasyon servisiyle senkronize edilmiş bir dizine yerleştirir ve ardından ~/.emacs.dpaylaşılan dizine sembolik bağlantılar oluşturur .


5

package.elPaketleri kurmanın standart yolu olsa da, el-getelpa'da olmayan (ya da olmayan) paketleri kurmak için hangisinin çok faydalı olduğunu denemek isteyebilirsiniz. Bu cevap, bu tür paketlerin senkronizasyonu ile ilgilidir.

El-get kullanırken belirli paketlerin yüklendiğinden emin olmanın yolu, init dosyasına aşağıdaki gibi bir şey eklemektir.

(el-get 'sync '(packages))

Burada paketler, yüklenmesini istediğiniz paketlerin listesidir. Bu fonksiyon, package-installpaketleri henüz kurulmamışlarsa kurmaya benzer , aksi takdirde paketleri basitçe başlatır.


5

Emacs-başlangıç ​​setinden "çalıntı" küçük bir numara kullanıyorum (sanırım):

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

Yani bir pakete ihtiyacım olduğunda, sadece kullanıyorum:

(maybe-install-and-require 'magit)

Emacs başlangıçlarında, benim yapılandırmamı değerlendirmek, package.elyüklü değilse magit'i kurmak için sağlayacaktır.

Yapılandırmamı burada bulabilirsiniz:

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


1
Aynı felsefeyi takip
ederek

3

Mercurial-sürüm kontrollü ve emacs kurulumumun oluşturduğu her şeyi içeren ~ / emacs dizinim var (el ile yüklenmiş kütüphaneler için ~ / emacs / site-lisp, elpa yüklü kütüphaneler için ~ / emacs / elpa, ~ / emacs / etc / bölünmüş .emaclar için, ~ / emacs / dot-emacs.el olan ~ / .emacs). Bu ağacın içindeki tüm önemli dosyalara sahip olmak için bazı paketlerde ince ayarlamalar yapılması gerekiyordu, ancak iyi çalışıyor. Makineye özgü olan bu birkaç bit, sistem adına şartlı olarak uyguladım.

Bu yüzden bir şeyi kurduktan / yeniden yapılandırdıktan / değiştirdikten sonra, kullandığım tüm makineler arasındaki tüm değişiklikleri çek / itmeyi taahhüt ediyorum.

Ekstra yarar, konfigürasyonumun tamamlanmış bir geçmişine sahip olmam ve herhangi bir yanlışlık olması durumunda geri / bisect / geri dönebilmemdir.

PS mercurial, doğal iki taraflı çekme / itme özelliğine sahip olduğu için özellikle uygun görünmektedir, ancak benzer kurulumların git veya başka herhangi bir dvcs ile gerçekleştirilmesi zor olmamalıdır.


3

Bunu setup-packages.el, Prelude ve Tomorokoshi'nin Paket Yönetimi üzerine yazdığı blogun bir melezi olan emacs kurulumumda görüyorum .

setup-packages.el aşağıdakileri yapar:

  • elpaVarsa paketler için bir dizin oluşturun ve onu ve alt dizinlerini load-path.
  • package-archivesMelpa ile güncelleme listesi.
  • Listede listelenen tüm paketlerin my-packageskurulu olup olmadığını kontrol edin . Bir paket kurulu değilse, kurun.

Nasıl uygulanır

  • Aşağıyı dizine setup-packages.elkaydedin ~/.emacs.d/.
  • Set user-emacs-directory, setup-packages-fileve my-packagesdeğişkenler Gözlerinde farklı init.elve yapılacak (load setup-packages-file).

Bu paketleri yüklü olmayan bir makinede ilk kez emacs başlattığınızda, listelenen tüm sayfalar my-packagesotomatik olarak yüklenir.

Kurulum-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

Aşağıdakilere ihtiyacınız olacak 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

Yapılandırmamı yansıtmak için Syncthing kullanarak farklı bir yaklaşıma gitmeye karar verdim ; Konfigürasyon dosyalarımın herhangi birindeki değişiklik, dikkat etmeden bilgisayarımın diğerlerine yayılıyor, bu yüzden paketleri yükseltirken sadece bir tanesinde yapmak zorunda kalıyorum.


2

RSYNC : rsyncBir ev ağı üzerinden veya sshuzak bir sunucu üzerinden seçim klasörlerini / dosyalarını senkronize edin .

rsynchedefteki dosyaları silebilen tek yönlü bir senkronizasyon aracıdır , bu yüzden lütfen verilerinizi hem kaynak hem de hedef konumlarda yedeklediğinizden ve bu --dry-runseçeneği kullanarak işlemi gerçek anlamda yapmadan önce test ettiğinizden emin olun .

.authinfoDosyanın doğru şekilde nasıl yapılandırılacağı hakkında bilgi edinmek için , bkz. Https://www.gnu.org/software/emacs/manual/auth.html Örnek bir .authinfodosya içeriği (birden fazla farklı giriş içerebilir) aşağıdaki gibidir:

machine mymachine login myloginname password mypassword port myport

Uzak bir sunucuya rsync-remotesenkronize etmek için işlevi yapılandırın ve kullanın ssh. Veya rsync-localaynı bilgisayarda veya güvenilir bir ev ağı üzerinden senkronize etmek için işlevi kullanın.

(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 , kurulu tüm paketlerin yerel bir deposunu oluşturur.

Kullanımı basit, sadece koşmak M-x elpamr-create-mirror-for-installed.

Diğer makinelerde, Emacs'ı (setq package-archives '(("myelpa" . "~/myelpa/")))takın .emacsve yeniden başlatın.

Şimdi tüm makinelerde, aynı paket versiyonuna sahip oluyorsunuz.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.