서로 다른 시스템간에 패키지 동기화


57

다른 장소에서 emacs를 사용하고 있으며 어디에서나 비슷한 설정 및 패키지를 설치하고 싶습니다. 설치 파일에 버전 제어 저장소를 사용할 수 있다고 생각합니다. Prelude를 사용하기 때문에 그럴 것입니다 ~/.emacs.d/personal/.

패키지로 처리하는 방법을 모르겠습니다. .emacs.d/다른 시스템에서 emacs를 작성하여 거기에 나열된 파일을 설치하는 데 사용할 수있는 설치된 패키지 목록 이있는 파일 이 있습니까?


2
나를 위해 설치된 패키지는 내 Emacs 버전 관리 저장소의 일부입니다. 사용하고 싶은 가장 오래된 버전의 Emacs로 패키지를 바이트 컴파일하고 .elc 파일을 리포지토리에 넣습니다. 이것은 최대 제어 및 일관성을 제공합니다. 트레이드 오프는 (상대적으로) 큰 크기의 저장소입니다. 내 6 살짜리 자식 저장소의 크기는 120MB입니다. 패키지를 포함하지 않으면 아마도 그중 10 분의 1을 피할 수 있지만, 그 "소비 한"메가 바이트 몇 개는 저를 걱정하지 않습니다.
파프리카

1
ELPA / MELPA / ...는 요즘 꽤 인기가 있지만 모든 패키지를 아직 사용할 수는 없습니다. 따라서 수동 설치가 필요한 패키지를 사용하는 경우 사용하는 각 새 시스템에 대한 노력을 복제하지 않을 수도 있습니다 (각 패키지 업그레이드에 대한 추가). 다시 말하지만, 쉬운 해결책은 패키지를 Emacs 버전 관리 저장소에 추가하는 것입니다.
파프리카

사이트에서 바이트 컴파일 만하고 git에서 .elc 파일을 무시하고 도망 칠 수는 없습니까?
Vamsi

@Vamsi : 일부 (ELPA가 아닌) 패키지는 종속성으로 인해 컴파일하기에 약간 까다 롭기 때문에 바이트 컴파일 된 파일을 저장소에 넣었습니다. 이를 위해 필요하지 않은 경우 프로세스를 반복하고 싶지 않습니다.
파프리카

@paprika 설정을 얻는 방법에 대한 세부 정보를 제공해 주시겠습니까? .emacs.d와 .emacs의 모든 것을 리포지토리에 추가합니까?
초보자

답변:


50

원하는 효과를 얻기 위해 동기화 할 수있는 자동 생성 매니페스트 파일이 없습니다.

즉, package-installemacs 구성 자체에 호출을 추가하는 것이 가능합니다.

(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는 패키지를 제거하지 않고 기존 패키지에서 작업을 수행 했을 수 있습니다.
Jonathan Leech-Pepin

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 대신 지금도 사용하는 솔루션입니다.
Andy

1
이것이 내가 사용하는 방법이지만 :ensure go-mode패키지 이름을 반복하는 대신 다음과 같이 지정할 수 있습니다.:ensure t
Pedro Luz

좋은 지적! 이것은 오래된 대답입니다. 업데이트하겠습니다.
elarson

:hook키워드를 사용하여 코드를 단순화 할 수도 있습니다 .
길 레르 메 살로메

17

Emacs-25에는 변수가 있으므로이 변수 package-selected-packages를 커스터마이즈하고이를 package-install-selected-packages설치하는 데 사용할 수 있습니다 .


내가 본 명령의 이름은 약간 혼란 스럽습니다. 패키지 설치 선택 패키지로 변경할 수 있습니까?
Malabarba

"Note"대신 "Now"를 의미한다고 가정합니다.
Stefan

9

사용할 패키지 는 Cask 이며, 설치할 패키지를 지정 하는 Cask 파일 을 만들 수 있습니다 cask install. 패키지의 종속성 및 Emacs 구성의 "종속성"을 쉽게 관리하는 데 사용할 수 있습니다. Cask 파일을 버전 관리하에 놓고 시스템별로 패키지를 설치 / 업데이트하십시오.


4
(현재)이 솔루션은 Windows 시스템에서는 작동하지 않습니다.
T. Verron

1
나는 더 이상 당신의 이유 때문에이 솔루션을 사용하지 않습니다 (그리고 Cask는 또 다른 의존성입니다). 패키지 제작에 좋습니다. 구성 관리에 끔찍한.
Andy

6

다른 방법은 다음과 같다 : 난 단지 내 이맥스 패키지를 동기화하지 않기 때문에, 또한 다른 파일 (예를 들어 .emacs, .bashrc뿐만 아니라 다른 디렉토리) 내 서버와 내 노트북 사이, 내가 사용하기 시작 unison파일을 동기화하고, 디렉토리. 따라서 랩톱에서 작업 할 때 다른 작업 unison laptop보다 간단하게 실행 합니다. 내 ~/.unison/laptop.prf파일에는 Emacs 관련 파일에 대한 다음 섹션이 있습니다.

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

내 Emacs 패키지 (및 내 Emacs 백업 및 책갈피)도 여기에 저장되어 ~/.emacs.d있기 때문에 모든 컴퓨터에 모든 것을 갖추 었습니다.

다른 방법은 .emacs.dOwnCloud, 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.el하면 magit이 설치되어 있지 않은 경우 magit 설치를 제공합니다.

내 구성은 여기에서 찾을 수 있습니다.

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


1
같은 철학에 따라, 당신은에서 '역설-필요'사용할 수 역설
csantosb

3

~ / emacs 디렉토리가 있으며 수은 버전으로 제어되며 내 emacs 설정으로 구성되는 모든 항목이 포함되어 있습니다 (수동으로 다운로드 한 라이브러리의 경우 ~ / emacs / site-lisp, 엘파 설치 라이브러리의 경우 ~ / emacs / elpa, ~ / emacs / etc / 분할 된 .emacs, ~ / .emacs / dot-emacs.el은 ~ / .emacs로 심볼릭 링크됩니다). 이 트리 안에 모든 중요한 파일을 갖기 위해서는 일부 패키지를 약간 조정해야했지만 잘 작동합니다. 기계 고유의 몇 비트는 시스템 이름의 조건에 의해 구현되었습니다.

따라서 설치 / 재구성 / 변경 한 후에는 사용하는 모든 컴퓨터 사이의 모든 변경 사항을 가져 오기 / 푸시합니다.

추가 이점은 구성의 전체 기록을 가지고 있으며 문제가 발생하면 다시 돌아가거나 / bisect / revert 할 수 있다는 것입니다.

PS 머큐리얼은 자연스러운 양면 풀 / 푸시를 가지고 있기 때문에 특히 적합 해 보이지만 git 또는 다른 dvc에서는 비슷한 설정을 달성하기 어렵지 않습니다.


3

나는 PreludeTomorokoshi의 Package Management에 대한 블로그의setup-packages.el 하이브리드 인 emacs 설정에 이것을 가지고있다 .

setup-packages.el 다음을 수행합니다.

  • elpa패키지 디렉토리 가 없으면 패키지 디렉토리를 작성 하고 서브 디렉토리를에 추가하십시오 load-path.
  • package-archivesMelpa로 업데이트 목록.
  • my-packages목록에 나열된 모든 패키지가 설치되어 있는지 확인하십시오 . 패키지가 설치되지 않은 경우 설치하십시오.

구현하는 방법

  • setup-packages.el아래를 ~/.emacs.d/디렉토리에 저장하십시오 .
  • 설정 user-emacs-directory, setup-packages-filemy-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 중 하나에서만 수행해야합니다.


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.

다른 기계에서는 Emacs를 넣고 다시 시작 (setq package-archives '(("myelpa" . "~/myelpa/")))하십시오 .emacs.

이제 모든 컴퓨터에서 정확히 동일한 버전의 패키지를 얻게됩니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.