Emacs 패키지를 어떻게 패치합니까?


16

패키지를 변경하고 테스트 한 후 나중에 풀 요청을 제출하고 싶습니다. 안전하고 효율적인 방법으로 어떻게합니까? 질문이 너무 넓게 느껴질 수 있습니다. 다음 문제에 대한 답변을 수락하겠습니다.

  1. 필자는 별도의 패키지 브랜치를 설치하고 필요할 때 자동으로 재 컴파일을 수행하면서 변덕스러운 지점과 안정적인 브랜치 사이를 전환 할 수있을 것으로 기대하지만 package.el그렇게 할 수있는 간단한 방법은 제공하지 않는 것 같습니다. emacs-SE에 대한이 답변 은“패키지의 여러 복사본이 설치된 경우 첫 번째 패키지가로드됩니다”라고 알려주므로 수동으로 엉망이 될 수 load-path있지만 강력하지는 않습니다. 설치된 패키지 중에서 특정 버전의 패키지를 선택하는 표준 방법은 무엇입니까?

  2. 여러 가지 브랜치를 Emacs에 노출시킬 수 있더라도 상당한 조정을 위해 패치되지 않은 브랜치를 "언로드"하고 부작용을 분리해야합니다. unload-feature이것을 올바르게 처리 합니까 아니면 다중 버전 패키지의 모든 테스터가 알아야 할 특성이 있습니까?

  3. 로컬 버전을 설치하고 테스트하려면 어떻게합니까? 답은 패키지가 단순 (= 하나의 파일)인지 아니면 다중 파일인지에 따라 달라집니다. EmacsWiki는 멀티 파일 패키지에 대해 다음과 같이 말합니다.“ MELPA가 패키지를 빌드합니다defun다중 파일 패키지에서 양식을 변경할 때마다 MELPA와 대화해야하는지 (또는)해야하는지 의심 하지만 질문은 남아 있습니다. 최소한 패키지 관리자에게 로컬 버전에 대해 알려 주어야한다면 어떻게해야합니까?

  4. 로컬 버전의 패키지에 어떤 이름을 할당해야합니까? 여러 기능이나 버그에 대해 동시에 작업하려고한다고 가정합니다. 즉, 여러 가지가 있습니다. Emacs는 (의 행을 따라) 설명적인 방식으로 버전 이름을 지정할 수 없습니다 20170117.666-somebugorfeature. 나는 패키지 자체의 이름을 분기당 접미사로 바꿀 수 있지만 load-pathQ1에서 수동으로 엉망으로하는 것처럼 추한 해킹이므로 널리 받아 들여지지 않는 한 업스트림으로 보내려고하는 것으로 시도하지 않을 것입니다. .

내가 git이나 비슷한 vc로 패치를 적용하지 않았기 때문에 질문은 아마도 순진합니다. 그러나 많은 이맥스 사용자들에게는 이맥스 패키지를 패치하는 것이 그들의 첫 번째 (또는 유일한 유일한) 소셜 프로그래밍 노력 일 수 있기 때문에이 질문에 대한 대답은 여전히 ​​가치가 있다고 생각합니다.

답변:


8

다른 버전의 패키지를로드하기위한 약간 다른 작업 흐름을 들으려면 여기에 내가하는 일의 몇 가지 변형이 있습니다. 두 가지 모두 load-path내가 사용중인 버전을 제어하는 ​​데 사용합니다 (패키지 이름 변경은 나쁜 생각입니다) 의존성이있는 경우). 나는에 설치 "좋은 패키지"의 현재 버전이 ~/.emacs.d/elpa사용 M-x package-install하고있는 패키지의 repo 복제 ~/src/nice-package와를 git clone ....

사용 패키지 포함

init.el에서 나는

(use-package nice-package
  :load-path "~/src/nice-package"
  ...)

으로 :load-path라인이 주석 처리,이 패키지의 자식 버전을 사용합니다. 이 줄을 주석 처리하고 emacs를 다시로드하면 elpa 버전이 사용됩니다.

사용 패키지없이 유사

init.el에서

(add-to-list 'load-path "~/src/nice-package")
(require 'nice-package)
...

이제 첫 번째 줄과 동일한 주석 트릭을 수행하십시오.

사용 emacs -L

이것은 같은 생각이지만 load-path명령 줄에서 조작하는 것입니다. 패키지의 git 버전으로 emacs 인스턴스를로드 할 수 있습니다.

emacs -L ~/src/nice-package

로드 경로 앞에이 경로를 추가합니다. 이렇게 emacs하면 다른 터미널에서 시작 하여 이전 버전과 새 버전의 패키지를 나란히 실행할 수 있습니다.

기타 의견

  1. M-x eval-buffer패키지 파일을 편집 한 후 사용 하여 새 정의를로드하십시오.
  2. 컴파일러가 말하는 내용을 확인하는 M-x emacs-lisp-byte-compile것도 편리합니다.

emacs -LCask를 사용하여 전체적으로 설치 한 패키지의 로컬 버전을로드하는 방법을 사용하고 있습니다. 나를 버린 한 가지 사실 <package>-version은 실제로 로컬 수정 버전을 실행하더라도 실행은 항상 전역 설치 버전을 반환 한다는 것입니다 . 때문에이 밝혀이었다 <package>-version이 패키지가의 버전을 가져옵니다 packages.el.
ntc2

3

좋은 질문! 대답은 기존 패키지 관리자가이 사용 사례에 맞게 설계되지 않았기 때문에 지금까지는 좋은 대답이 없었습니다 ( Borg 제외). Borg는 종속성 처리와 같은 다른 일반적인 패키지 관리 작업을 처리하지 않습니다 .

그러나 이제는 straight.el이 문제를 가능한 한 종합적으로 해결하는 차세대 Emacs 패키지 관리자가 있습니다. 면책 조항 : 나는 썼다 straight.el!

부트 스트랩 스 니펫을 삽입 한 후 패키지 설치는 다음과 같이 간단합니다.

(straight-use-package 'magit)

이렇게하면 Magit 용 Git 리포지토리를 복제하고 파일을 별도의 디렉토리에 심볼릭 링크하여 패키지를 작성하고 바이트 컴파일하고 자동로드를 생성 및 평가하며 load-path올바르게 구성 합니다. 물론, 패키지가 이미 복제 및 빌드 된 경우 아무 일도 일어나지 않으며 초기화 시간이 줄지 않습니다.

Magit을 어떻게 변경합니까? 사소한 일입니다! 그냥 사용 M-x find-function하거나 M-x find-library소스 코드로 이동, 멀리 해킹! Emacs Lisp 개발의 일반적인 방법과 마찬가지로 변경 사항을 평가하여 실시간으로 테스트 할 수 있으며 Emacs를 다시 시작하면 패키지가 자동으로 재 빌드, 재 컴파일 등이됩니다. 완전 자동이며 완전합니다.

변경 사항에 만족하면 커밋, 푸시 및 풀 요청을하십시오. 로컬 패키지를 완전히 제어 할 수 있습니다. 그러나 자체 straight.el패키지 straight.el, MELPA 등을 포함한 모든 패키지의 Git 개정판을 저장하는 잠금 파일을 만들 수 있기 때문에 구성을 100 % 재현 할 수 있습니다 .

straight.elMELPA, GNU ELPA 또는 EmacsMirror에서 모든 패키지를 설치할 수 있습니다. 또한 매우 유연한 레시피 DSL을 사용하여 어디에서나 설치할 수 있으며 패키지 구축 방법을 사용자 지정할 수 있습니다. 다음은 몇 가지 옵션을 보여주는 예입니다.

(straight-use-package
 '(magit :type git 
         :files ("lisp/magit*.el" "lisp/git-rebase.el"
                 "Documentation/magit.texi" "Documentation/AUTHORS.md"
                 "COPYING" (:exclude "lisp/magit-popup.el"))
         :host github :repo "raxod502/magit"
         :upstream (:host github :repo "magit/magit")))

straight.el엄청나게 포괄적 인 문서가 있습니다. GitHub에서 그것에 관한 모든 것을 읽으십시오 .


2

이것들은 모두 좋은 질문입니다!

Emacs는 새 코드를로드하면 실행중인 인스턴스의 메모리 이미지가 변경되는 메모리 이미지 모델에서 작동합니다. 새 함수와 변수를 정의하는 것은 쉽게 취소 할 수 있습니다. 목록을 유지하면 취소하려는 모듈에 많은 부작용이있을 수 있습니다. unload-feature그래도 꽤 잘하는 것처럼 보입니다 .

나는 당신이하고 싶은 것은 라이브 코딩과 때때로 Emacs를 다시 시작하는 것의 조합으로, 설치된 모듈이 아닌 지점에서 작업중 인 모듈을로드하는 것입니다. 이러한 분기를 많이 사용하는 load-path경우 현재 작업중 인 것과 동일한 emacs를 시작하는 쉘 스크립트가 필요할 수 있습니다 . 어쨌든 나는 패키지 이름을 바꾸지 않을 것이다. emacs가 둘 다로드 할 수 있기 때문에 더 혼란 스럽다고 생각합니다.

패치를 개발할 때 라이브 Emacs 세션에서 변경중인 기능을 다시 정의하여 시작할 수 있습니다. 이를 통해 Emacs를 떠나지 않고도 새로운 정의를 즉시 테스트 할 수 있습니다. 특히, elisp 파일을 편집 할 때 C-M-x( eval-defun)를 사용 하여 현재 Emacs 세션에서 현재 기능을 평가할 수 있습니다 . 그런 다음 호출하여 작동하는지 확인할 수 있습니다. Emacs 시작시 발생하는 무언가를 변경하는 경우 Emacs를 시작하고 중지해야 테스트 할 수 있습니다. 편집 세션이 중단되지 않도록 별도의 Emacs 프로세스를 시작 및 중지하여이를 수행 할 수 있습니다.


2

나는 그것에 대한 좋은 대답이 아직 없다고 생각합니다. (Cask로 부분적인 해결책을 얻을 수 있다고 생각합니다. 그래서 그것을 사용하여 좋은 대답을 줄만큼 익숙하지는 않습니다. 내가하는 일 (나는 로컬에서 변경하지 않고 Elisp 패키지를 거의 사용하지 않으므로 실제로는 "정상적인"방법입니다.)

  • cd ~/src; git clone ..../elpa.git
  • 각 패키지 cd ~/src/elisp; git clone ....thepackage.git
  • cd ~/src/elpa/packages; ln -s ~/src/elisp/* .
  • cd ~/src/elpa; make
  • 당신의 ~/.emacs추가

    (eval-after-load 'package
     '(add-to-list 'package-directory-list
                   "~/src/elpa/packages"))
    

이런 식으로 모든 패키지는 "Git에서 바로 설치됨"으로 설치되며, 간단한 패키지는 필요한 패키지 cd ~/src/elpa; make를 다시 컴파일하고 C-h o thepackage-functionGit 아래의 소스 파일로 이동합니다.

"변덕스러운 지점과 안정된 지점 사이를 전환하려면" git checkout <branch>; cd ~/src/elpa; make; Emacs 세션 실행에 영향을 주려면 더 많은 작업이 필요합니다. 나는 일반적으로 unload-feature예외적 인 상황을 제외하고는 사용하지 않는 것이 좋습니다 (좋은 기능이지만 현재 충분히 신뢰할 수는 없습니다).

또한 많은 요구 사항을 충족시키지 못합니다. 그리고 많은 단점이 있습니다. 주로 많은 패키지의 Git 클론이 elpa.git의 makefile에서 예상하는 레이아웃과 내용과 일치하지 않기 때문에 패키지를 조정해야합니다 (일반적으로 관련이있는 것들) <pkg>-pkg.elelpa.git의 makefile은이 파일을 제공 <pkg>.el하지 않고이 파일을 빌드 할 것으로 예상 하지만, 더 문제가되는 경우 컴파일이 다르게 수행되므로 때때로 requires 를 사용해야합니다 .

물론 이것은 기본적으로 패키지를 직접 설치한다는 것을 의미하므로 종속성에주의를 기울여야합니다. 이 설정은에 의해 설치된 다른 패키지와 올바르게 상호 작용 package-install하므로 끔찍한 것은 아닙니다.


2

내 다른 답변을 포함 하여이 질문에 대한 다른 답변 은 코드를 변경하여 Emacs 패키지 패치에 대해 이야기합니다. 그러나 구글을 통해이 질문을 찾는 사람들은 "Emacs 패키지 패치"라고 말할 때 다른 소스를 생각할 수 있습니다. 즉, 소스 코드를 수정하지 않고도 동작을 무시합니다.

이를 수행하는 메커니즘에는 다음과 같은 공격성 순서가 포함됩니다.

  • 후크에 함수 추가 또는 다음을 사용하여 동적 변수 바인딩let
  • 강력한 조언 시스템
  • 수정하려는 기능을 대체하는 것이 좋습니다.

처음 두 옵션의 힘에도 불구하고 때로는 다른 방법이 없기 때문에 세 번째 경로를 자주 사용하는 것으로 나타났습니다. 그러나 문제는 원래 함수 정의가 변경되면 어떻게 될까요? init 파일에 복사하여 붙여 넣은 정의의 버전을 업데이트해야한다는 것을 알 방법이 없습니다!

나는 패치하는 것에 집착하기 때문에 패키지를 작성 el-patch하여이 문제를 가능한 한 종합적으로 해결했습니다. 아이디어는 init 파일에 s-expression based diffs를 정의하는 것으로, 원래 함수 정의와 변경 사항을 모두 설명합니다. 이렇게하면 패치를보다 쉽게 ​​읽을 수있게 el-patch되며 나중에 패치를 작성한 후 원래 함수 정의가 업데이트되었는지 여부를 확인할 수 있습니다 . (그렇다면 Ediff를 통한 변경 사항을 보여줄 것입니다!) 문서에서 인용 :

company-statistics패키지에 정의 된 다음 기능을 고려하십시오 .

(defun company-statistics--load ()
  "Restore statistics."
  (load company-statistics-file 'noerror nil 'nosuffix))

통계 파일을로드 할 때 기록되는 메시지를 억제 nil하기 위해 세 번째 인수를에서로 변경한다고 가정 합니다. 우리는 다음 코드를 배치하여 그렇게 할 수 있습니다 .'nomessagecompany-statisticsinit.el

(el-patch-defun company-statistics--load ()
  "Restore statistics."
  (load company-statistics-file 'noerror
        (el-patch-swap nil 'nomessage)
        'nosuffix))

단순히 호출하는 el-patch-defun대신 defun무 작동 패치 를 정의합니다. 즉, 효과가 없습니다 (잘 모르겠지만 나중에 참조 ). 그러나 patch 지정 문 을 포함 하면 수정 된 버전의 함수를 원래 버전과 다르게 만들 수 있습니다.

이 경우 el-patch-swap지침 을 사용합니다 . el-patch-swap양식으로 대체되어 nil원래의 정의 (즉,에서 "공식적인"정의와 비교되어있는 버전 company-statistics.el)과와 'nomessage수정 된 정의 (즉, 실제로 초기화 파일에 평가 버전).


0

당신이 많은 변경을 할 때, 나는 당신이 사용해야한다고 생각합니다 straight.el, Radon Rosborough 의 답변을 참조하십시오 .

일회성 변경을 원한다면이라는 프로젝트를 가정 fork-mode하고 다음 단계를 수행하십시오.

  • 자식을 저장할 디렉토리 만들기 mkdir ~/.emacs.d/lisp-gits
  • 변경하려는 프로젝트를 포크로 말하십시오. https://github.com/user/fork-mode
  • 포크 복제 cd ~/.emacs.d/lisp-gits && git clone git@github.com:user/fork-mode.git

에 다음 코드를 작성하십시오 .emacs

(if (file-exists-p "~/.emacs.d/lisp-gits/fork-mode")
    (use-package fork-mode :load-path "~/.emacs.d/lisp-gits/fork-mode")
  (use-package fork-mode :ensure t))

(use-package fork-mode
  :config
  (setq fork-mode-setting t)
  :hook
  ((fork-mode . (lambda () (message "Inside hook"))))

이제 emacs 모드를 사용 C-h f하여 변경할 기능을 찾을 수 있습니다. 패키지가 lisp-gits에 설치되면 거기로 이동한다는 것을 알 수 있습니다. magit 또는 다른 git 명령을 사용하여 변경 사항을 커밋 / 푸시 한 다음 github을 사용하여 풀 요청을 보냅니다.

풀 요청이 수락되면 프로젝트를 제거 ~/.emacs.d/lisp-gits하고 패키지 관리자가 작업을 수행하도록 할 수 있습니다.


0

쓰라린 마음으로“문명화 된 방식으로는 할 수없는”자신의 대답을 받아 들여야합니다.

package.el충분한 인력으로 해결할 수있는 패키지 관리자 문제가 있으며, 반대로 연구 문제처럼 보이는 코드 재로드 문제가 있습니다. 후자 때문에, 우리는 원래의 질문에 만족스럽게 대답 할 수 없다고 결론 내릴 수 있습니다. 최소한 Emacs 패키지를 개발하는 동안 최소한 Emacs 패키지가 올바르게 컴파일되고로드되도록하려면 Emacs를 다시 시작해야합니다.

해결하려면 package.el문제를, 나는 이맥스 대신 패치 (또는 쓰기) 이맥스 패키지 작성 및 패치 젠투 패키지를했다. 여기에는 고유 한 문제가 있지만 적어도 개별 사용자 수준에서는 다루기 어려운 문제가 있습니다. 특히 젠투의 패키지 관리자“portage”는 컴파일 작업을 위해 자동으로 Emacs를 재시작합니다. package.el사용자 패치, 구성 (특히 동적 모듈을 제공하는 Emacs 패키지와 관련이 있음), 자식 분기에서 설치, 조직 기반 소스에서 설치하지 않는 다른 작업을 수행합니다. 이 기능의 대부분은 2020-03 현재 내장되어 있습니다.

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