Jak załatać pakiet Emacsa?

16

Chcę zmienić pakiet, przetestować go i mam nadzieję, że prześlę później żądanie ściągnięcia. Jak to zrobić w bezpieczny i wydajny sposób? Pytanie może wydawać się zbyt ogólne, zaakceptuję odpowiedź obejmującą następujące kwestie:

  1. Spodziewałbym się zainstalować oddzielną gałąź pakietu i być w stanie przełączać się między nią a stabilną gałęzią według kaprysu, z rekompilacją przeprowadzaną automatycznie, gdy jest to konieczne, ale package.elnie wydaje się, aby oferować prosty sposób na zrobienie tego. Ta odpowiedź na emacs-SE informuje nas, że „Jeśli zainstalowanych jest wiele kopii pakietu, pierwsza zostanie załadowana”, więc myślę, że można ręcznie zepsuć, load-pathale to nie jest solidne. Jaki jest standardowy sposób wyboru konkretnej wersji pakietu spośród zainstalowanych?

  2. Nawet jeśli uda mi się ujawnić Emacsowi kilka gałęzi, w przypadku znacznych poprawek muszę upewnić się, że niezaładowana gałąź jest „rozładowana”, a jej skutki uboczne odizolowane. Czy radzi unload-featuresobie z tym poprawnie, a może ma osobliwości, o których powinien wiedzieć każdy tester pakietów z wieloma wersjami?

  3. Jak zainstalować i przetestować wersję lokalną? Odpowiedź wydaje się zależeć od tego, czy pakiet jest prosty (= jeden plik), czy wielowątkowy. EmacsWiki mówi o pakietach z wieloma plikami : „ MELPA tworzy pakiety dla Ciebie ”. Wątpię, czy muszę (lub powinienem) rozmawiać z MELPA za każdym razem, gdy zmieniam defunformularz w pakiecie z wieloma plikami, ale pozostaje pytanie. Przynajmniej muszę poinformować menedżera pakietów o wersji lokalnej, a jeśli tak, to jak to zrobić?

  4. Jakie nazwy powinienem przypisać do lokalnych wersji pakietów? Załóżmy, że chcę pracować jednocześnie nad wieloma funkcjami lub błędami, co oznacza posiadanie kilku gałęzi. Emacs nie pozwoli na nazewnictwo wersji w sposób opisowy (zgodnie z 20170117.666-somebugorfeature). Chyba mógłbym zmienić nazwę samego pakietu, przyrostek na gałąź, ale znowu, podobnie jak ręczne mieszanie load-pathw Q1, jest to brzydkie włamanie, więc nie spróbuję tego z czymś, co zamierzam wysłać w górę, chyba że jest to powszechnie akceptowana praktyka .

Pytania prawdopodobnie są naiwne, ponieważ nigdy nie napisałem łatki ani nie zastosowałem jej z gitem ani podobnym vcs. Jednak dla wielu użytkowników Emacsa łatanie pakietu Emacsa może być ich pierwszym (a może jedynym) przedsięwzięciem związanym z programowaniem społecznościowym i dlatego, moim zdaniem, odpowiedzi na to pytanie byłyby nadal cenne.

akater
źródło

Odpowiedzi:

7

Aby wdrożyć nieco inny przepływ pracy podczas ładowania różnych wersji pakietów, oto kilka odmian tego, co robię, z których oba używają load-pathdo kontrolowania, której wersji używam (zmiana nazwy pakietu to zły pomysł jeśli istnieją zależności). Mam bieżącą wersję „nice-package” zainstalowaną w ~/.emacs.d/elpaużyciu M-x package-installi klonowanie repozytorium pakietów za ~/src/nice-packagepomocą git clone ....

Z pakietem użytkowania

W init.el mam

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

Gdy :load-pathlinia nie będzie komentowana, użyje ona wersji git pakietu. Komentowanie tej linii i ponowne ładowanie emacsa używa wersji elpa.

Podobne bez pakietu użytkowego

W init.el

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

Teraz wykonaj tę samą sztuczkę komentowania w pierwszym wierszu.

Za pomocą emacs -L

To ten sam pomysł, ale manipulowanie load-pathz poziomu wiersza poleceń. Możesz załadować instancję emacsa za pomocą wersji git pakietu za pomocą

emacs -L ~/src/nice-package

który po prostu umieszcza tę ścieżkę na początku ścieżki ładowania. W ten sposób możesz uruchamiać emacsz innego terminala i pobierać starą i nową wersję pakietu obok siebie.

Różne komentarze

  1. Użyj go M-x eval-bufferpo edycji pliku pakietu, aby załadować nowe utworzone definicje.
  2. Sprawdzanie co kompilator mówi, ze M-x emacs-lisp-byte-compilejest zbyt poręczny
justbur
źródło
Używam tego emacs -Lpodejścia, aby załadować lokalną wersję pakietu, który również zainstalowałem globalnie za pomocą Cask. Jedną rzeczą, która mnie odrzuciła, było to, że uruchamianie <package>-versionzawsze zwraca wersję zainstalowaną globalnie, nawet gdy faktycznie uruchomiłem lokalną zmodyfikowaną wersję. Okazuje się, że było tak, ponieważ <package>-versiondla tego pakietu pobierana jest wersja packages.el.
ntc2
3

Dobre pytanie! Odpowiedź jest taka, że ​​do tej pory nie było dobrej odpowiedzi, ponieważ żaden z istniejących menedżerów pakietów nie został zaprojektowany dla tego przypadku użycia (z wyjątkiem Borg , ale Borg nie próbuje obsługiwać innych typowych operacji zarządzania pakietami, takich jak obsługa zależności) .

Ale teraz jest straight.elmenedżer pakietów nowej generacji dla Emacsa, który rozwiązuje ten problem tak kompleksowo, jak to możliwe. Uwaga: Napisałem straight.el!

Po wstawieniu fragmentu kodu ładującego instalacja pakietu jest tak prosta, jak

(straight-use-package 'magit)

Spowoduje to sklonowanie repozytorium Git dla Magit, skompilowanie pakietu poprzez symlinkowanie jego plików do osobnego katalogu, kompilacja bajtów, generowanie i ocena autoloadów oraz load-pathprawidłowe skonfigurowanie . Oczywiście, jeśli pakiet jest już sklonowany i zbudowany, nic się nie dzieje, a czas inicjacji nie cierpi.

Jak wprowadzasz zmiany w Magit? To banalne! Wystarczy użyć M-x find-functionlub, M-x find-libraryaby przejść do kodu źródłowego i zhakować! Możesz ocenić swoje zmiany, aby przetestować je na żywo, co jest ogólną praktyką w rozwoju Emacsa Lispa, a po ponownym uruchomieniu Emacsa pakiet zostanie automatycznie odbudowany, ponownie skompilowany i tak dalej. Jest całkowicie automatyczny i niezawodny.

Gdy jesteś zadowolony ze swoich zmian, po prostu zatwierdzaj, wypychaj i wysyłaj prośby. Masz całkowitą kontrolę nad swoimi lokalnymi pakietami. Ale twoja konfiguracja może być w 100% odtwarzalna, ponieważ możesz poprosić straight.elo utworzenie pliku blokującego, który zapisuje wersje Git wszystkich twoich pakietów, w tym straight.elsiebie, MELPA i tak dalej.

straight.elmożna zainstalować dowolny pakiet z MELPA, GNU ELPA lub EmacsMirror. Ale ma również bardzo elastyczny przepis DSL, który pozwala zainstalować z dowolnego miejsca, a także dostosować sposób budowania pakietu. Oto przykład, który pokazuje niektóre opcje:

(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.elma absurdalnie wyczerpującą dokumentację. Przeczytaj o tym wszystko na GitHub .

Radon Rosborough
źródło
2

To są dobre pytania!

Emacs działa na modelu obrazu pamięci, w którym ładowanie nowego kodu zmienia obraz pamięci działającej instancji. Definiowanie nowych funkcji i zmiennych można łatwo cofnąć, jeśli zachowasz ich listę, ale moduł może wywoływać wiele skutków ubocznych, które chciałbyś cofnąć. Wygląda na unload-featureto, że całkiem nieźle się to udaje.

Myślę, że to, co będziesz chciał zrobić, to połączenie kodowania na żywo i od czasu do czasu ponownego uruchamiania Emacsa, ładowanie modułu, nad którym pracujesz, z oddziału, a nie z miejsca, w którym jest zainstalowany. Jeśli skończysz z wieloma gałęziami, możesz chcieć skryptu powłoki, który uruchamia emacsa z poprawnym load-pathdla tego, nad którym aktualnie pracujesz. W każdym razie nie zmieniłbym nazwy pakietu; Myślę, że byłoby to jeszcze bardziej mylące, ponieważ emacs mógłby następnie załadować je oba.

Gdy rozwijasz swoje łatki, możesz po prostu przedefiniować funkcje, które zmieniasz bezpośrednio podczas sesji Emacsa na żywo. To pozwala natychmiast przetestować nowe definicje, bez opuszczania Emacsa. W szczególności podczas edytowania pliku elisp można użyć C-M-x( eval-defun) do oceny bieżącej funkcji w bieżącej sesji Emacsa. Możesz wtedy zadzwonić, aby upewnić się, że działa. Jeśli zmieniasz coś, co dzieje się podczas uruchamiania Emacsa, prawdopodobnie będziesz musiał uruchomić i zatrzymać Emacsa, aby to przetestować; możesz to zrobić, uruchamiając i zatrzymując osobny proces Emacsa, aby sesja edytowania nie została przerwana.

db48x
źródło
2

Nie sądzę, aby na to pytanie była jakaś dobra odpowiedź (spodziewam się, że możesz uzyskać częściowe rozwiązanie z Cask, jednak nie znam go wystarczająco dobrze, aby dać ci dobrą odpowiedź, mam nadzieję, że ktoś inny to zrobi), ale oto co robię (rzadko używam pakietu Elisp bez wprowadzania lokalnych zmian, więc to naprawdę mój „normalny” sposób):

  • cd ~/src; git clone ..../elpa.git
  • dla każdej paczki cd ~/src/elisp; git clone ....thepackage.git
  • cd ~/src/elpa/packages; ln -s ~/src/elisp/* .
  • cd ~/src/elpa; make
  • w twoim ~/.emacsdodatku

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

W ten sposób wszystkie pakiety są instalowane „prosto z Gita”, prosty cd ~/src/elpa; makeprzekompiluje te, które tego potrzebują i C-h o thepackage-functionprzejdzie do pliku źródłowego, który jest pod Gitem.

Aby „przełączać się między nim a stabilną gałęzią pod wpływem kaprysu”, musisz git checkout <branch>; cd ~/src/elpa; make: a jeśli chcesz, aby wpłynęło to na uruchamianie sesji Emacsa, zajmie to więcej pracy. Ogólnie polecam nie używać, unload-featurez wyjątkiem wyjątkowych sytuacji (jest to dobra funkcja, ale obecnie nie jest wystarczająco niezawodna).

Nie spełnia również wielu twoich wymagań. Ma też kilka wad, głównie fakt, że klon Git wielu pakietów nie do końca pasuje do układu i zawartości oczekiwanej przez plik maku elpa.git, więc musisz zacząć od ulepszenia tych pakietów (zazwyczaj rzeczy, które mają związek z <pkg>-pkg.el, ponieważ plik makefile elpa.git spodziewa się zbudować ten plik <pkg>.elzamiast go udostępniać, ale co bardziej problematyczne, kompilacja jest wykonywana inaczej, więc czasami trzeba grać z requires).

No i oczywiście oznacza to w zasadzie, że instalujesz te pakiety ręcznie, więc musisz zwracać uwagę na zależności. Ta konfiguracja poprawnie współpracuje z innymi pakietami zainstalowanymi przez package-install, choć nie jest to takie straszne.

Stefan
źródło
2

Inne odpowiedzi na to pytanie, w tym moja inna , mówią o łataniu pakietu Emacsa poprzez wprowadzanie zmian w jego kodzie. Ale ludzie znajdujący to pytanie za pośrednictwem Google mogą myśleć o czymś innym, mówiąc „załatać pakiet Emacsa” - mianowicie, nadpisując jego zachowanie bez konieczności modyfikowania kodu źródłowego.

Mechanizmy do tego celu obejmują, w kolejności rosnącej agresywności:

Pomimo mocy dwóch pierwszych opcji dość często wybrałem trzecią trasę, ponieważ czasami nie ma innej drogi. Ale pytanie brzmi: co, jeśli zmieni się pierwotna definicja funkcji? Nie możesz wiedzieć, że musisz zaktualizować wersję tej definicji, którą skopiowałeś i wkleiłeś do pliku init!

Ponieważ mam obsesję na punkcie łatania rzeczy, napisałem pakiet el-patch, który rozwiązuje ten problem tak kompleksowo, jak to możliwe. Chodzi o to, że w pliku inicjującym definiujesz różnice oparte na wyrażeniu s, które opisują zarówno oryginalną definicję funkcji, jak i zmiany w niej. To sprawia, że ​​łatki są znacznie bardziej czytelne, a także pozwala el-patchpóźniej sprawdzić, czy oryginalna definicja funkcji została zaktualizowana od czasu utworzenia łaty. (Jeśli tak, pokaże zmiany za pośrednictwem Ediff!) Cytując z dokumentacji:

Rozważ następującą funkcję zdefiniowaną w company-statisticspakiecie:

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

Załóżmy, że chcemy zmienić trzeci argument z nilna 'nomessage, aby ukryć komunikat, który jest rejestrowany podczas company-statisticsładowania pliku statystyk. Możemy to zrobić, umieszczając następujący kod w naszym init.el:

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

Po prostu wywołanie el-patch-defunzamiast defundefiniuje łatkę no-op: to znaczy, że nie ma żadnego efektu (cóż, niezupełnie - patrz później ). Jednak dołączając dyrektywy łatek , możesz sprawić, że zmodyfikowana wersja funkcji będzie inna niż oryginalna.

W tym przypadku korzystamy z el-patch-swapdyrektywy. el-patch-swapForma jest zastępowany nilw oryginalnej rozdzielczości (to jest wersja, która jest porównywana z „oficjalnej” definicji company-statistics.el), a także z 'nomessagew zmodyfikowanej definicji (to jest wersja, która jest faktycznie oceniano w init-pliku).

Radon Rosborough
źródło
0

Kiedy wprowadzasz wiele zmian, myślę, że powinieneś użyć straight.el, zobacz odpowiedź Radona Rosborougha .

Jeśli chcesz tylko wprowadzić jednorazową zmianę, załóżmy, że projekt o nazwie fork-mode, wykonaj następujące czynności:

  • Utwórz katalog do przechowywania git mkdir ~/.emacs.d/lisp-gits
  • Zrób widelec z projektu, który chcesz zmienić, powiedz na https://github.com/user/fork-mode
  • Sklonuj widelec cd ~/.emacs.d/lisp-gits && git clone [email protected]:user/fork-mode.git

Napisz następujący kod w swoim .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"))))

Teraz możesz użyć trybu emacs, używając, C-h faby znaleźć funkcje, które chcesz zmienić. Zauważysz, że kiedy pakiet zostanie zainstalowany w lisp-gits, przejdziesz do niego. Użyj magit lub innych poleceń git, aby zatwierdzić / wypchnąć zmiany, a następnie użyj github, aby wysłać żądania ściągnięcia.

Po zaakceptowaniu żądań ściągnięcia możesz po prostu usunąć projekt ~/.emacs.d/lisp-gitsi pozwolić menedżerowi pakietów wykonać swoją pracę.

ppareit
źródło