異なるマシン間でパッケージを同期する


57

私はさまざまな場所でemacsを使用しており、同様のセットアップとパッケージをどこにでもインストールしたいと考えています。セットアップファイルにバージョン管理リポジトリを使用できると思います。私はプレリュードを使用しているので、そうなります~/.emacs.d/personal/

パッケージの処理方法がわかりません。.emacs.d/他のマシンでemacを作成してそこにリストされているものをインストールするために使用できるインストール済みパッケージのリストを含むファイルがどこかにありますか?


2
私にとって、インストールされたパッケージは、私のEmacsバージョン管理リポジトリの一部にすぎません。使用したい/必要なEmacsの最も古いバージョンでパッケージをバイトコンパイルし、.elcファイルをリポジトリに配置します。これにより、最大限の制御と一貫性が提供されます。トレードオフは、(比較的)リポジトリのサイズが大きいことです。私の6年前のgitリポジトリのサイズは120MBです。パッケージを含めなければ、おそらくその1/10で問題はありませんが、これらの「無駄な」メガバイトは本当に心配する必要はありません。
パプリカ14

1
ELPA / MELPA / ...は最近非常に人気がありますが、それでもすべてのパッケージが利用できるわけではありません。したがって、手動インストールが必要なパッケージを使用する場合、使用する新しいマシンごとに(パッケージのアップグレードごとに)作業を複製する必要はありません。繰り返しますが、簡単な解決策は、パッケージをEmacsバージョン管理リポジトリに追加することです。
パプリカ14

サイトでバイトコンパイルして、gitの.elcファイルを無視することはできませんか?
Vamsi 14

@Vamsi:バイトコンパイルされたファイルをリポジトリに配置しました。一部の(非ELPA)パッケージは依存関係があるため、コンパイルがややこしいためです。これらの場合、必要でない場合はプロセスを繰り返すのは好きではありません。
パプリカ14

@paprikaセットアップの取得方法について詳しく教えてください。.emacs.dのすべてと.emacsをリポジトリに追加しますか?
初心者

回答:


50

目的の効果を得るために同期できる自動生成されたマニフェストファイルはありません。

とはいえ、できることはpackage-install、emacs構成自体に呼び出しを追加することです。

(package-install 'auctex)

アイデアはpackage-installdem等であるため、パッケージが既に存在する場合、実際には何も起こりません。使用するすべてのパッケージ(または少なくとも依存関係グラフのリーフ)に対してこのような呼び出しがあると仮定すると、マシン間でパッケージを効果的に同期できます。


複数のパッケージの場合、次を使用できます。

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

2
このアプローチがここで提案された解決策と比較してどのくらい簡単かに驚いています。違いはありますか?スニペットもを使用しpackage-installます。
Stenskjaer

1
package.elリンクされた回答以降に変更がありました。その時点で、package-installアンインストールされたパッケージだけでなく、既存のパッケージに対して操作を実行した可能性があります。
ジョナサンリーチペピン14

3
残念ながら、パッケージアーカイブリポジトリがマシン間で均一であり、SCMで指定されている場合でも、この手法には問題があります。パッケージのバージョンがマシン間で同一であることを保証するものではありません。問題は、パッケージのバージョンが指定されていないことです。これらの個々のパッケージは、時間の経過とともに分岐し、依存関係に互換性がなくなる可能性があります。これは、melpaなどのアクティブなパッケージアーカイブで非常に簡単に発生します。
-ctpenrose

@ctpenrose:この問題を回避するための提案はありますか?
学生

@student melpa-stableを使用してパッケージの更新頻度を減らすことで、問題を最小限に抑えました。
ctpenrose

34

.emacs.dディレクトリをバージョン管理に保持しています。次に、init.el以降のファイルでuse-packageを使用して、パッケージのセットアップを定義します。use-packageはパッケージを遅延的にロードするだけでなく、設定したパッケージリポジトリから存在しない場合はオンデマンドでダウンロードします。

たとえば、go-modeを使用していますが、すべてのマシンで使用しているわけではありません。私のinit.elには次のものがあります:

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

これにより、モードフックが追加されますが、さらに重要なことは、指定する:ensure tことにより、オンデマンドでパッケージをダウンロードすることです。

マシンの同期を維持するには、チェックアウトするか、リポジトリからプルしてEmacsを起動します。新しいパッケージがダウンロードされ、インストールされます。


これは、主に(T. Verronが述べたように)CaskがWindowsで(うまく)動作せず、さらに別の依存関係であるため、Caskではなく現在使用しているソリューションです。
アンディ

1
これも私が使用する方法:ensure go-modeですが、パッケージ名を繰り返すのではなく、指定することができます:ensure t
Pedro Luz

いい視点ね!これは古い答えです。更新します。
エラソン

:hookキーワードを使用してコードを簡素化することもできます。
ギルヘルメサロメ

17

Emacs-25には変数package-selected-packagesがあるため、この変数をカスタマイズpackage-install-selected-packagesして、インストールされていることを確認するために使用できます。


私はそれを見ることに注意してください、そのコマンドの名前は少し分かりにくいです。package-install-selected-packagesに変更できますか?
マラバルバ

「メモ」ではなく「今」を意味すると仮定すると、はい。
ステファン

9

使用したいのはCaskです。これにより、インストールするパッケージを指定するCaskファイルを作成できますcask install。パッケージの依存関係、およびEmacs設定の「依存関係」を簡単に管理するために使用できます。Caskファイルをバージョン管理下に置き、マシンごとにパッケージをインストール/更新します。


4
(今日の時点で)このソリューションはWindowsマシンでは機能しないことに注意してください。
T.バーロン14

1
あなたの理由のために、私はこのソリューションを使用しなくなりました(そして、Caskはさらに別の依存関係です)。パッケージ作成に最適。構成管理にとって恐ろしい。
アンディ

6

別のアプローチは、次のようになります。私は私のEmacsのパッケージを同期したくないので、だけでなく、他のファイル(例えば.emacs.bashrcが、他のディレクトリ)私のサーバーと私のラップトップとの間には、私が使用し始めunisonたファイルを同期すると、ディレクトリ。それで、私のラップトップで作業するとき、私はunison laptop他の何かの前に簡単に走ります。私の~/.unison/laptop.prfファイルには、Emacs関連のファイルに関する次のセクションがあります。

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

私のEmacsパッケージ(および私のEmacsバックアップとブックマーク)は~/.emacs.dこれに保存されるため、すべてのマシンにすべてが揃っていることを確認してください。

別のアプローチ.emacs.dとして、OwnCloud、DropBox、またはその他のファイル同期サービスと同期する~/.emacs.dディレクトリにディレクトリを配置し、その共有ディレクトリからシンボリックリンクを作成します。


5

一方でpackage.elパッケージをインストールするための標準的な方法で、あなたもしようとする場合がありますel-getELPA上にない(またはすることはできません)パッケージをインストールするために非常に有用です。この回答は、そのようなパッケージの同期に関するものです。

el-getを使用するときに特定のパッケージを確実にインストールする方法は、initファイルに次のようなものを追加することです。

(el-get 'sync '(packages))

packagesは、インストールするパッケージのリストです。この関数はpackage-install、パッケージがまだインストールされていない場合にのみパッケージをインストールするのと似ています。それ以外の場合は、単にパッケージを初期化します。


5

私はemacs-starter-kitから「盗まれた」ちょっとしたトリックを使用します(私は思う):

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

したがって、パッケージが必要な場合は、単に次を使用します。

(maybe-install-and-require 'magit)

emacsスタートアップでは、私の構成を評価して、package.elmagitがインストールされていない場合にインストールすることを提供します。

ここで私の設定を見つけることができます:

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


1
同じ哲学に続いて、あなたはから「パラドックス-必要」を使用することができパラドックス
csantosb

3

〜/ emacsディレクトリには、mercurial-versionが制御されており、emacsのセットアップに含まれるすべてのものが含まれています(〜/ emacs / site-lispは手動でダウンロードしたライブラリ、〜/ emacs / elpaはelpaがインストールしたライブラリ、〜/ emacs / etc /分割された.emacsの場合は〜/ emacs / dot-emacs.elで、これを〜/ .emacsとしてシンボリックリンクします)。このツリー内にすべての重要なファイルを含めるには、いくつかのパッケージを微調整する必要がありましたが、うまく機能します。マシン固有のいくつかのビットは、システム名の条件によって実装しました。

したがって、何かをインストール/再構成/変更した後、使用するすべてのマシン間ですべての変更をプル/プッシュするだけです。

追加の利点は、設定の完全な履歴があり、何か問題が発生した場合に戻る/二分する/元に戻すことができることです。

PS mercurialは自然な両側のプル/プッシュを備えているため、特に適しているように見えますが、同様のセットアップはgitやその他のdvcで達成するのは難しくありません。


3

私はこれを持っているsetup-packages.elから、コードのハイブリッドである私のEmacsの設定で、前奏曲パッケージ管理上のTomorokoshiさんのブログ

setup-packages.el 次のことを行います。

  • elpaパッケージが存在しない場合はパッケージ用のディレクトリを作成し、そのディレクトリとそのサブディレクトリをに追加しload-pathます。
  • Melpaでpackage-archivesリストを更新します。
  • リストにmy-packagesリストされているすべてのパッケージがインストールされているかどうかを確認します。パッケージがインストールされていない場合は、インストールします。

実装方法

  • setup-packages.el以下を~/.emacs.d/ディレクトリに保存します。
  • 設定しuser-emacs-directorysetup-packages-fileそしてmy-packagesあなたの変数init.elと行います(load setup-packages-file)

これらのパッケージがインストールされていないマシンで初めてemacsを起動すると、リストされているすべてのパッケージmy-packagesが自動的にインストールされます。

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

あなたは次のものが必要です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

設定をミラーリングするために、Syncthingを使用して、別のアプローチを採用することにしました。構成ファイルの変更はすべて、それを気にせずに他のPCに伝播するため、パッケージをアップグレードするときは、PCの1つでそれを行うだけです。


2

RSYNC:を使用rsyncして、ホームネットワーク経由sshで、またはリモートサーバー経由で、選択したフォルダー/ファイルを同期します。

rsyncすることができます一方向の同期ユーティリティです削除対象のファイルは、そうしておいてください、バックアップあなたのデータをソースとターゲットの場所の両方に、そして徹底的に使用してテストし--dry-run、オプションを前に本当のことをやって。

.authinfoファイルを適切に構成する方法については、https://www.gnu.org/software/emacs/manual/auth.htmlを参照して ください.authinfoファイルの内容の例(複数の異なるエントリが含まれる場合があります)は次のとおりです。

machine mymachine login myloginname password mypassword port myport

この機能rsync-remoteを設定して使用sshし、リモートサーバーに同期します。または、この機能rsync-localを使用して、同じコンピューター上または信頼できるホームネットワーク上で同期します。

(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は、インストールされているすべてのパッケージのローカルリポジトリを作成します。

使い方は簡単で、ただ実行するだけM-x elpamr-create-mirror-for-installedです。

他のマシンでは、に挿入(setq package-archives '(("myelpa" . "~/myelpa/")))して.emacsEmacsを再起動します。

これで、すべてのマシンで、まったく同じバージョンのパッケージを入手できます。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.