Emacsパッケージにパッチを適用するにはどうすればよいですか?


16

パッケージを変更してテストし、その後プルリクエストを送信したいです。安全で効率的な方法でそれを行うにはどうすればよいですか?質問は広すぎると感じるかもしれませんが、私は次の問題をカバーする答えを受け入れます。

  1. パッケージの別のブランチをインストールし、気まぐれに安定したブランチを切り替えることができると期待しています。必要なときに自動的に再コンパイルが実行されますが、それpackage.elを行う簡単な方法は提供されていないようです。emacs-SEに関するこの回答は、「パッケージの複数のコピーがインストールされている場合、最初のコピーがロードされる」ことを教えてくれるので、手動で混乱させることができると思いますload-pathが、これは堅牢ではありません。インストールされているパッケージの中から特定のバージョンのパッケージを選択する標準的な方法は何ですか?

  2. いくつかのブランチをEmacsに公開できたとしても、大幅な調整のために、パッチを当てていないブランチを「アンロード」し、その副作用を分離する必要があります。unload-featureそれはマルチバージョンのパッケージのすべてのテスターが知っておくべきことの特異性を持って適切にまたは多分これを処理しますか?

  3. ローカルバージョンをインストールしてテストするにはどうすればよいですか?答えは、パッケージがシンプル(= 1ファイル)かマルチファイルかによって異なります。EmacsWikiは、マルチファイルパッケージについて次のように述べています。「MELPAはパッケージをビルドします」。defunマルチファイルパッケージのフォームを変更するたびにMELPAと話す必要がある(またはすべき)とは思いませんが、疑問は残ります。少なくとも、ローカルバージョンについてパッケージマネージャーに伝える必要があります。その場合、どのようにすればよいですか?

  4. パッケージのローカルバージョンにどのような名前を割り当てる必要がありますか?複数の機能やバグを同時に処理したい場合、つまり複数のブランチを作成したいとします。Emacsでは、記述的な方法でバージョンに名前を付けることはできません(の行に沿って20170117.666-somebugorfeature)。パッケージごとにサフィックスをブランチごとに名前変更できると思いますが、load-pathQ1 で手動で混乱させるのと同様に、これはいハックなので、広く受け入れられている慣行でない限り、アップストリームに送信するものでそれを試しません。

gitや同様のvcを適用したパッチを作成したことがないため、質問はおそらく単純です。しかし、多くのEmacsユーザーにとって、Emacsパッケージへのパッチ適用は彼らにとって初めての(あるいはおそらく唯一の)ソーシャルプログラミングの試みかもしれません。そのため、この質問に対する答えはまだ価値があると思います。

回答:


7

パッケージの異なるバージョンをロードするためのわずかに異なるワークフローでチャイムインするために、ここで私が行うことのいくつかのバリエーションがあり、どちらも使用しload-pathているバージョンを制御するために使用します依存関係がある場合)。を~/.emacs.d/elpa使用してインストールされた "nice-package"の現在のバージョンM-x package-installと、でパッケージリポジトリのクローンを作成し~/src/nice-packageましたgit clone ...

use-packageを使用

init.elには、

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

:load-path行コメントを外し、これはパッケージのgitのバージョンを使用します。この行をコメント化し、emacsをリロードするには、elpaバージョンを使用します。

use-packageなしで同様

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を再起動すると、パッケージが自動的に再構築、再コンパイルなどされます。それは完全に自動化され、誰にでもできるものです。

変更に満足したら、コミット、プッシュ、プルリクエストを行います。ローカルパッケージを完全に制御できます。ただし、自分自身やMELPA straight.elなどを含むすべてのパッケージのGitリビジョンを保存するstraight.elロックファイルを作成するように要求できるため、構成は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-xeval-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-functionし、Gitの下にあるソースファイルにジャンプします。

「気まぐれでそれと安定ブランチを切り替える」ためには、あなたがする必要がありgit checkout <branch>; cd ~/src/elpa; makeます; また、実行中のEmacsセッションに影響を与えたい場合は、さらに作業が必要になります。通常unload-feature、例外的な状況を除いて使用しないことをお勧めします(これは優れた機能ですが、現時点では十分な信頼性がありません)。

また、多くの要件を満たしていません。さらに、多くのパッケージのGitクローンがelpa.gitのmakefileで期待されるレイアウトと内容に完全に一致しないという事実が主な欠点であるため、これらのパッケージを調整することから始める必要があります(通常は、<pkg>-pkg.el、elpa.gitのmakefileは、このファイルを<pkg>.el提供するのではなく、そこからビルドすることを想定していますが、さらに問題があるのは、コンパイルの実行方法が異なるため、requiresで遊ぶ必要があることです。

ああ、もちろん、これは基本的にこれらのパッケージを手動でインストールすることを意味するため、依存関係に注意する必要があります。このセットアップはpackage-install、tho によってインストールされた他のパッケージと適切に相互作用するため、それほどひどいものではありません。


2

私の他の回答を含むこの質問に対する他の回答は、コードに変更を加えてEmacsパッケージにパッチを当てることについて述べています。しかし、Googleを介してこの質問を見つけた人は、「Emacsパッケージにパッチを当てる」と言うとき、つまり、ソースコードを変更せずにその動作をオーバーライドすることを考えているかもしれません。

これを行うためのメカニズムには、攻撃性の昇順が含まれます。

最初の2つのオプションの力にもかかわらず、他の方法がない場合があるため、私は3番目のルートをかなり頻繁に取っていることに気付きました。しかし、問題は、元の関数定義が変更された場合はどうでしょうか?コピーしてinitファイルに貼り付けた定義のバージョンを更新する必要があることを知る方法はありません。

私はパッチを当てることに夢中なのでel-patch、この問題を可能な限り包括的に解決するパッケージを作成しました。その考えは、元の関数定義とそれに対する変更の両方を記述するs-expressionベースのdiffをinit-fileで定義することです。これにより、パッチがはるかに読みやすくなり、パッチel-patchを作成してから元の関数定義が更新されたかどうかを後で検証することもできます。(もしそうなら、Ediffを介して変更を表示します!)ドキュメントからの引用:

company-statisticsパッケージで定義されている次の関数を検討してください 。

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

私たちはから三番目の引数を変更したいと仮定nilする 'nomessageときにログに記録されるメッセージ抑制するために、 company-statisticsその統計ファイルをロードします。次のコードをに配置することにより、これを実行できますinit.el

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

no-opパッチel-patch-defundefun定義する代わりに単に呼び出すだけです。つまり、効果はありません(まあ、まったくそうではありません。後で参照してください )。ただし、patchディレクティブを含めることにより、変更されたバージョンの関数を元のものとは異なるものにすることができます。

この場合、el-patch-swapディレクティブを使用します。 el-patch-swapフォームが置き換えられnil(、で「公式」の定義と比較されているバージョンであるオリジナルの定義でcompany-statistics.el)、及びで'nomessage(、実際にあなたのinitファイルで評価されているバージョンである)変更の定義インチ


0

多くの変更を行うときstraight.elは、Radon Rosboroughの回答を参照してください。

1回限りの変更を行うだけの場合は、というプロジェクトを想定しfork-modeて、次の手順を実行します。

  • gitを保存するディレクトリを作成します 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、パッケージマネージャーに作業を任せることができます。

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